Using Windows PowerShell scripts to publish to dev and test environments
When you create a web application in Visual Studio, you can generate a Windows PowerShell script that you can use later to automate the publishing of your website to Azure as a Web App in Azure App Service or a virtual machine. You can edit and extend the Windows PowerShell script in the Visual Studio editor to suit your requirements, or integrate the script with existing build, test, and publishing scripts.
Using these scripts, you can provision customized versions (also known as dev and test environments) of your site for temporary use. For example, you might set up a particular version of your website on an Azure virtual machine or on the staging slot on a website to run a test suite, reproduce a bug, test a bug fix, trial a proposed change, or set up a custom environment for a demo or presentation. After you've created a script that publishes your project, you can re-create identical environments by rerunning the script as needed, or run the script with your own build of your web application to create a custom environment for testing.
Prerequisites
- Visual Studio with the Azure workload installed. See Visual Studio Downloads.
- Azure PowerShell 0.7.4 or later. See How to install and configure Azure PowerShell.
- Windows PowerShell 3.0 or later.
- An Azure account. If you don't have an Azure account, activate your Azure benefits for Visual Studio subscribers or sign up for a free trial.
Additional tools
Additional tools and resources for working with PowerShell in Visual Studio for Azure development are available. See PowerShell Tools for Visual Studio.
Generating the publish scripts
You can generate the publish scripts for a virtual machine that hosts your website when you create a new project by following these instructions. You can also generate publish scripts for web apps in Azure App Service.
Scripts that Visual Studio generates
Visual Studio generates a solution-level folder called PublishScripts that contains two Windows PowerShell files, a publish script for your virtual machine or website, and a module that contains functions that you can use in the scripts. Visual Studio also generates a file in the JSON format that specifies the details of the project you are deploying.
Windows PowerShell publish script
The publish script contains specific publish steps for deploying to a website or virtual machine. Visual Studio provides syntax coloring for Windows PowerShell development. Help for the functions is available, and you can freely edit the functions in the script to suit your changing requirements.
Windows PowerShell module
The Windows PowerShell module that Visual Studio generates contains functions that the publish script uses. These Azure PowerShell functions are not intended to be modified. See How to install and configure Azure PowerShell.
JSON configuration file
The JSON file is created in the Configurations folder and contains configuration data that specifies exactly which resources to deploy to Azure. The name of the file that Visual Studio generates is project-name-WAWS-dev.json if you created a website, or project name-VM-dev.json if you created a virtual machine. Here's an example of a JSON configuration file that's generated when you create a website. Most of the values are self-explanatory. The website name is generated by Azure, so it might not match your project name.
{
"environmentSettings": {
"webSite": {
"name": "WebApplication26632",
"location": "West US"
},
"databases": [{
"connectionStringName": "DefaultConnection",
"databaseName": "WebApplication26632_db",
"serverName": "YourDatabaseServerName",
"user": "sqluser2",
"password": "",
"edition": "",
"size": "",
"collation": "",
"location": "West US"
}]
}
}
When you create a virtual machine, the JSON configuration file looks similar to the following. A cloud service is created as a container for the virtual machine. The virtual machine contains the usual endpoints for web access through HTTP and HTTPS, as well as endpoints for Web Deploy, which lets you publish to the website from your local machine, Remote Desktop, and Windows PowerShell.
{
"environmentSettings": {
"cloudService": {
"name": "myusernamevm1",
"affinityGroup": "",
"location": "West US",
"virtualNetwork": "",
"subnet": "",
"availabilitySet": "",
"virtualMachine": {
"name": "myusernamevm1",
"vhdImage": "a699494373c04fc0bc8f2bb1389d6106__Win2K8R2SP1-Datacenter-201403.01-en.us-127GB.vhd",
"size": "Small",
"user": "vmuser1",
"password": "",
"enableWebDeployExtension": true,
"endpoints": [{
"name": "Http",
"protocol": "TCP",
"publicPort": "80",
"privatePort": "80"
},
{
"name": "Https",
"protocol": "TCP",
"publicPort": "443",
"privatePort": "443"
},
{
"name": "WebDeploy",
"protocol": "TCP",
"publicPort": "8172",
"privatePort": "8172"
},
{
"name": "Remote Desktop",
"protocol": "TCP",
"publicPort": "3389",
"privatePort": "3389"
},
{
"name": "Powershell",
"protocol": "TCP",
"publicPort": "5986",
"privatePort": "5986"
}
]
}
},
"databases": [{
"connectionStringName": "",
"databaseName": "",
"serverName": "",
"user": "",
"password": ""
}],
"webDeployParameters": {
"iisWebApplicationName": "Default Web Site"
}
}
}
You can edit the JSON configuration to change what happens when you run the publish scripts. The cloudService
and virtualMachine
sections are required, but you can delete the databases
section if you don't need it. The properties that are empty in the default configuration file that Visual Studio generates are optional; those properties that have values in the default configuration file are required.
If you have a website that has multiple deployment environments (known as slots) instead of a single production site in Azure, you can include the slot name in the name of the website in the JSON configuration file. For example, if you have a website that's named mysite and a slot for it named test then the URI is mysite-test.cloudapp.net
, but the correct name to use in the configuration file is mysite(test). You can only do this if the website and slots already exist in your subscription. If they don't exist, create the website by running the script without specifying the slot, then create the slot in the Azure portal, and thereafter run the script with the modified website name. For more information about deployment slots for web apps, see Set up staging environments for web apps in Azure App Service.
How to run the publish scripts
If you have never run a Windows PowerShell script before, you must first set the execution policy to enable scripts to run. The policy is a security feature to prevent users from running Windows PowerShell scripts if they're vulnerable to malware or viruses that involve executing scripts.
Run the script
Create the Web Deploy package for your project. A Web Deploy package is a compressed archive (.zip file) that contain files that you want to copy to your website or virtual machine. You can create Web Deploy packages in Visual Studio for any web application.
For more information, see How to: Create a Web Deployment Package in Visual Studio. You can also automate the creation of your Web Deploy package, as described in Customizing and extending the publish scripts.
In Solution Explorer, open the context menu for the script, and then choose Open with PowerShell ISE.
If running Windows PowerShell scripts on this computer for the first time, open a command prompt window with Administrator privileges and type the following command:
Set-ExecutionPolicy RemoteSigned
Sign in to Azure by using the following command.
Add-AzureAccount
When prompted, supply your username and password.
Note that when you automate the script, this method of providing Azure credentials doesn't work. Instead, you should use the
.publishsettings
file to provide credentials. One time only, you use the command Get-AzurePublishSettingsFile to download the file from Azure, and thereafter use Import-AzurePublishSettingsFile to import the file. For detailed instructions, see How to install and configure Azure PowerShell.(Optional) If you want to create Azure resources such as the virtual machine, database, and website without publishing your web application, use the Publish-WebApplication.ps1 command with the -Configuration argument set to the JSON configuration file. This command line uses the JSON configuration file to determine which resources to create. Because it uses the default settings for other command-line arguments, it creates the resources, but doesn't publish your web application. The –Verbose option gives you more information about what's happening.
Publish-WebApplication.ps1 -Verbose –Configuration C:\Path\WebProject-WAWS-dev.json
Use the Publish-WebApplication.ps1 command as shown in one of the following examples to invoke the script and publish your web application. If you need to override the default settings for any of the other arguments, such as the subscription name, publish package name, virtual machine credentials, or database server credentials, you can specify those parameters. Use the –Verbose option to see more information about the progress of the publishing process.
Publish-WebApplication.ps1 –Configuration C:\Path\WebProject-WAWS-dev-json ` –SubscriptionName Contoso ` -WebDeployPackage C:\Documents\Azure\ADWebApp.zip ` -DatabaseServerPassword @{Name="dbServerName";Password="adminPassword"} ` -Verbose
If you're creating a virtual machine, the command looks like the following. This example also shows how to specify the credentials for multiple databases. For the virtual machines that these scripts create, the SSL certificate is not from a trusted root authority. Therefore, you need to use the –AllowUntrusted option.
Publish-WebApplication.ps1 ` -Configuration C:\Path\ADVM-VM-test.json ` -SubscriptionName Contoso ` -WebDeployPackage C:\Path\ADVM.zip ` -AllowUntrusted ` -VMPassword @{name = "vmUserName"; password = "YourPasswordHere"} ` -DatabaseServerPassword @{Name="server1";Password="adminPassword1"}, @{Name="server2";Password="adminPassword2"} ` -Verbose
The script can create databases, but it doesn't create database servers. If you want to create a database server, you can use the New-AzureSqlDatabaseServer function in the Azure module.
Customizing and extending the publish scripts
You can customize the publish script and JSON configuration file. The functions in the Windows PowerShell module AzureWebAppPublishModule.psm1 are not intended to be modified. If you just want to specify a different database or change some of the properties of the virtual machine, edit the JSON configuration file. If you want to extend the functionality of the script to automate building and testing your project, you can implement function stubs in Publish-WebApplication.ps1.
To automate building your project, add code that calls MSBuild to New-WebDeployPackage
as shown in this code example. The path to the MSBuild command is different depending on the version of Visual Studio you have installed. To get the correct path, you can use the function Get-MSBuildCmd, as shown in this example.
To automate building your project
Add the
$ProjectFile
parameter in the global param section.[Parameter(Mandatory = $false)] [ValidateScript({Test-Path $_ -PathType Leaf})] [String] $ProjectFile,
Copy the function
Get-MSBuildCmd
into your script file.function Get-MSBuildCmd { process { $StartInfo = New-Object System.Diagnostics.ProcessStartInfo; $StartInfo.Filename = ${Env:ProgramFiles(x86)} + "\\Microsoft Visual Studio\\Installer\\vswhere.exe" $StartInfo.Arguments = " -latest -requires Microsoft.Component.MSBuild -find MSBuild\\**\\Bin\\MSBuild.exe" $StartInfo.RedirectStandardOutput = $True $StartInfo.UseShellExecute = $False [System.Diagnostics.Process] $VSWhere = [Diagnostics.Process]::Start($StartInfo) $VSWhere.WaitForExit() return $VSWhere.StandardOutput.ReadToEnd(); } }
Replace
New-WebDeployPackage
with the following code and replace the placeholders in the line constructing$msbuildCmd
.function New-WebDeployPackage { #Write a function to build and package your web application
To build your web application, use MSBuild.exe. For help, see MSBuild Command-Line Reference
Write-VerboseWithTime 'Build-WebDeployPackage: Start' $msbuildCmd = '"{0}" "{1}" /T:Rebuild;Package /p:OutputPath="{2}\MSBuildOutputPath" /flp:logfile=msbuild.log,v=d' -f (Get-MSBuildCmd), $ProjectFile, $scriptDirectory Write-VerboseWithTime ('Build-WebDeployPackage: ' + $msbuildCmd)
Start execution of the build command
$job = Start-Process cmd.exe -ArgumentList('/C "' + $msbuildCmd + '"') -WindowStyle Normal -Wait -PassThru
if ($job.ExitCode -ne 0) {
throw('MSBuild exited with an error. ExitCode:' + $job.ExitCode)
}
#Obtain the project name
$projectName = (Get-Item $ProjectFile).BaseName
#Construct the path to web deploy zip package
$DeployPackageDir = '.\MSBuildOutputPath\_PublishedWebsites\{0}_Package\{0}.zip' -f $projectName
#Get the full path for the web deploy zip package. This is required for MSDeploy to work
$WebDeployPackage = Resolve-Path –LiteralPath $DeployPackageDir
Write-VerboseWithTime 'Build-WebDeployPackage: End'
return $WebDeployPackage
}
Call the
New-WebDeployPackage
function before this line:$Config = Read-ConfigFile $Configuration
for web apps or$Config = Read-ConfigFile $Configuration -HasWebDeployPackage:([Bool]$WebDeployPackage)
for virtual machines.if($ProjectFile) { $WebDeployPackage = New-WebDeployPackage }
Invoke the customized script from command line using passing the
$Project
argument, as in the following example:.\Publish-WebApplicationVM.ps1 -Configuration .\Configurations\WebApplication5-VM-dev.json ` -ProjectFile ..\WebApplication5\WebApplication5.csproj ` -VMPassword @{Name="VMUser";Password="Test.123"} ` -AllowUntrusted ` -Verbose
To automate testing of your application, add code to
Test-WebApplication
. Be sure to uncomment the lines in Publish-WebApplication.ps1 where these functions are called. If you don't provide an implementation, you can manually build your project with Visual Studio, and then run the publish script to publish to Azure.
Publishing function summary
To get help for functions you can use at the Windows PowerShell command prompt, use the command Get-Help function-name
. The help includes parameter help and examples. The same help text is also in the script source files AzureWebAppPublishModule.psm1 and Publish-WebApplication.ps1. The script and help are localized in your Visual Studio language.
AzureWebAppPublishModule
Function name | Description |
---|---|
Add-AzureSQLDatabase | Creates a new Azure SQL database. |
Add-AzureSQLDatabases | Creates Azure SQL databases from the values in the JSON configuration file that Visual Studio generates. |
Add-AzureVM | Creates an Azure virtual machine and returns the URL of the deployed VM. The function sets up the prerequisites and then calls the New-AzureVM function (Azure module) to create a new virtual machine. |
Add-AzureVMEndpoints | Adds new input endpoints to a virtual machine and returns the virtual machine with the new endpoint. |
Add-AzureVMStorage | Creates a new Azure Storage account in the current subscription. The name of the account begins with "dev/test" followed by a unique alphanumeric string. The function returns the name of the new storage account. Specify either a location or an affinity group for the new storage account. |
Add-AzureWebsite | Creates a website with the specified name and location. This function calls the New-AzureWebsite function in the Azure module. If the subscription doesn't already include a website with the specified name, this function creates the website and returns a website object. Otherwise, it returns $null . |
Backup-Subscription | Saves the current Azure subscription in the $Script:originalSubscription variable in script scope. This function saves the current Azure subscription (as obtained by Get-AzureSubscription -Current ) and its storage account, and the subscription that is changed by this script (stored in the variable $UserSpecifiedSubscription ) and its storage account, in script scope. By saving the values, you can use a function, such as Restore-Subscription , to restore the original current subscription and storage account to current status if the current status has changed. |
Find-AzureVM | Gets the specified Azure virtual machine. |
Format-DevTestMessageWithTime | Prepends the date and time to a message. This function is designed for messages written to the Error and Verbose streams. |
Get-AzureSQLDatabaseConnectionString | Assembles a connection string to connect to an Azure SQL database. |
Get-AzureVMStorage | Returns the name of the first storage account with the name pattern "dev/test*" (case insensitive) in the specified location or affinity group. If the "dev/test*" storage account doesn't match the location or affinity group, the function ignores it. Specify either a location or an affinity group. |
Get-MSDeployCmd | Returns a command to run the MsDeploy.exe tool. |
New-AzureVMEnvironment | Finds or creates a virtual machine in the subscription that matches the values in the JSON configuration file. |
Publish-WebPackage | Uses MsDeploy.exe and a web publish package .Zip file to deploy resources to a website. This function doesn't generate any output. If the call to MSDeploy.exe fails, the function throws an exception. To get more detailed output, use the -Verbose option. |
Publish-WebPackageToVM | Verifies the parameter values, and then calls the Publish-WebPackage function. |
Read-ConfigFile | Validates the JSON configuration file and returns a hash table of selected values. |
Restore-Subscription | Resets the current subscription to the original subscription. |
Test-AzureModule | Returns $true if the installed Azure module version is 0.7.4 or later. Returns $false if the module isn't installed or is an earlier version. This function has no parameters. |
Test-AzureModuleVersion | Returns $true if the version of the Azure module is 0.7.4 or later. Returns $false if the module isn't installed or is an earlier version. This function has no parameters. |
Test-HttpsUrl | Converts the input URL to a System.Uri object. Returns $True if the URL is absolute and its scheme is HTTPS. Returns $false if the URL is relative, its scheme isn't HTTPS, or the input string can't be converted to a URL. |
Test-Member | Returns $true if a property or method is a member of the object. Otherwise, returns $false . |
Write-ErrorWithTime | Writes an error message prefixed with the current time. This function calls the Format-DevTestMessageWithTime function to prepend the time before writing the message to the Error stream. |
Write-HostWithTime | Writes a message to the host program (Write-Host) prefixed with the current time. The effect of writing to the host program varies. Most programs that host Windows PowerShell write these messages to standard output. |
Write-VerboseWithTime | Writes a verbose message prefixed with the current time. Because it calls Write-Verbose, the message displays only when the script runs with the Verbose parameter or when the VerbosePreference preference is set to Continue. |
Publish-WebApplication
Function name | Description |
---|---|
New-AzureWebApplicationEnvironment | Creates Azure resources, such as a website or virtual machine. |
New-WebDeployPackage | This function isn't implemented. You can add commands in this function to build your project. |
Publish-AzureWebApplication | Publishes a web application to Azure. |
Publish-WebApplication | Creates and deploys Web Apps, virtual machines, SQL databases, and storage accounts for a Visual Studio web project. |
Test-WebApplication | This function isn't implemented. You can add commands in this function to test your application. |
Related content
Learn more about PowerShell scripting by reading Scripting with Windows PowerShell and see other Azure PowerShell scripts at the Script Center.