├── CloudConfigs
├── AzureSubscriptionData.config
├── RoleProperties.txt
├── SQLAzureServerInfo.config
├── SearchConfig.config
├── ServiceConfiguration.Cloud.cscfg
├── ServiceConfiguration.Local.cscfg
├── ServiceDefinition.csdef
├── StartupTasks
│ ├── ConfigureIISAppPool.cmd
│ ├── ConfigureIISAppPool.ps1
│ ├── ManageConfigACL.cmd
│ └── ManageConfigACL.ps1
├── Subscription1.publishsettings
└── diagnostics.wadcfgx
├── README.md
└── Scripts
├── CertificatesManagement.ps1
├── CleanAzureData.ps1
├── Common.ps1
├── Configuration
└── config.json
├── ConfigureRedisCache.ps1
├── CreateAzurePackage.ps1
├── CreateSitefinityAzureResourceGroup.ps1
├── DatabaseAzure.ps1
├── DeploySitefinityToAzureAppService.ps1
├── DeploySitefinityToAzureCloudService.ps1
├── ManageAzureRedisCache.ps1
├── ManageAzureResourceGroup.ps1
├── ManageAzureServices.ps1
├── ManageAzureStorage.ps1
├── Modules.ps1
├── PublishCloudService.ps1
├── Templates
├── Default.json
└── Default.params.json
├── UpdateAzureCloudConfigs.ps1
└── UpdateSitefinityConfigs.ps1
/CloudConfigs/AzureSubscriptionData.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | true
6 | https://management.core.windows.net
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/CloudConfigs/RoleProperties.txt:
--------------------------------------------------------------------------------
1 | TargetFrameWorkVersion=v4.0
--------------------------------------------------------------------------------
/CloudConfigs/SQLAzureServerInfo.config:
--------------------------------------------------------------------------------
1 |
2 |
3 | SQLAzure
4 |
5 |
6 |
7 |
8 |
9 | false
10 |
--------------------------------------------------------------------------------
/CloudConfigs/SearchConfig.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/CloudConfigs/ServiceConfiguration.Cloud.cscfg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/CloudConfigs/ServiceConfiguration.Local.cscfg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/CloudConfigs/ServiceDefinition.csdef:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/CloudConfigs/StartupTasks/ConfigureIISAppPool.cmd:
--------------------------------------------------------------------------------
1 | PowerShell -ExecutionPolicy Unrestricted -File .\ConfigureIISAppPool.ps1
--------------------------------------------------------------------------------
/CloudConfigs/StartupTasks/ConfigureIISAppPool.ps1:
--------------------------------------------------------------------------------
1 | <#
2 |
3 | .SYNOPSIS
4 | This scripts sets the Start Mode of the application pool and the Idle Timeout.
5 |
6 | #>
7 |
8 | param($startMode='AlwaysRunning',
9 | $idleTimeout='0',
10 | $logFileName="ConfigureIISAppPool")
11 |
12 | $Logfile = "$PSScriptRoot\$logFileName.log"
13 |
14 | try{
15 | Import-Module WebAdministration
16 | }catch [Exception]{
17 | Import-Module WebAdministration
18 | }
19 |
20 | function LogWrite
21 | {
22 | Param ([string]$logstring)
23 |
24 | Add-content $Logfile -value $logstring
25 | }
26 |
27 | try{
28 | LogWrite "Start Updating Application Pool Defaults Settings ..."
29 |
30 | LogWrite "Setting Start Mode to `"$startMode`"..."
31 | Set-WebConfigurationProperty /system.applicationHost/applicationPools/applicationPoolDefaults[1] -name startMode -value $startMode
32 |
33 | LogWrite "Setting Idle Timeout to `"$idleTimeout`"..."
34 | Set-WebConfigurationProperty /system.applicationHost/applicationPools/applicationPoolDefaults[1]/processModel[1] -name idleTimeout -value $idleTimeout
35 | }
36 | catch [Exception]{
37 | $("$file.name: " + $_.Exception.Message) | out-file $Logfile -Append
38 | Add-Content $Logfile $error
39 | }
40 | finally{
41 | LogWrite "Finished Updating Application Pool Defaults Settings"
42 | }
43 |
--------------------------------------------------------------------------------
/CloudConfigs/StartupTasks/ManageConfigACL.cmd:
--------------------------------------------------------------------------------
1 | PowerShell -ExecutionPolicy Unrestricted -File .\ManageConfigACL.ps1
--------------------------------------------------------------------------------
/CloudConfigs/StartupTasks/ManageConfigACL.ps1:
--------------------------------------------------------------------------------
1 | <#
2 |
3 | .SYNOPSIS
4 | This scripts gives permissions for the NETWORK SERVICE user to modify Siefinity files.
5 |
6 | #>
7 |
8 | param($defaultDrive = "E:\",
9 | $logFileName = "ManageConfigACL")
10 |
11 | $Logfile = "$PSScriptRoot\$logFileName.log"
12 |
13 | function LogWrite
14 | {
15 | Param ([string]$logstring)
16 |
17 | Add-content $Logfile -value $logstring
18 | }
19 |
20 | try{
21 | LogWrite "Start managing configuration ACL..."
22 |
23 | $drive = $defaultDrive
24 | $rootFolder = $PSScriptRoot
25 | $tokens = $rootFolder.Split(":")
26 |
27 | if($tokens.length -gt 0){
28 | $drive = "{0}:\" -f $tokens[0]
29 | }
30 |
31 | $configurationPath = Join-Path $drive "approot\App_Data\Sitefinity\Configuration\*"
32 |
33 | LogWrite "PSScriptRoot is '$PSScriptRoot'"
34 | LogWrite "drive is '$drive'"
35 | LogWrite "configurationPath is '$configurationPath'"
36 |
37 | LogWrite "Setting configuration ACL for '$configurationPath'"
38 |
39 | icacls $configurationPath '/grant' '"NT AUTHORITY\NetworkService":(w)'
40 | }
41 | catch [Exception]{
42 | $("$file.name: " + $_.Exception.Message) | out-file $Logfile -Append
43 | LogWrite $error
44 | }
45 | finally{
46 | LogWrite "Finished managing configuration ACL"
47 | }
48 |
--------------------------------------------------------------------------------
/CloudConfigs/Subscription1.publishsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/CloudConfigs/diagnostics.wadcfgx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Sitefinity Azure PowerShell Deployment Scripts
2 |
3 | The repository contains scripts for continuous deployment of Sitefinity sites to Azure. You can use the scripts to integrate your Sitefinity to scalable continues integration and automatic deployments. Scripts allow you to integrate uploads from source controls and repository tools like TFS, Git, and GitHub.
4 | You can use scripts to publish Sitefinity directly from your local computer to Azure Web Apps (Azure Websites) and Azure Cloud Service.
5 |
6 | # Features
7 |
8 | - Azure Cloud Service Deployment -Highly available, scalable n-tier cloud apps with more control of the OS
9 | - Azure Websites Deployment -Scalable Web Apps
10 |
11 | Scripts automatically prepare your Sitefinity instance for deployment by modifying needed configurations.
12 |
13 | Scripts support configuration for
14 | - Database instance - create SQL server or connect to existing one. If database doesn't exists new database is created and Sitefinity data is then imported to Azure Database.
15 | - Redis Cache - create a new Redis Cache or use existing one. Note that it is better to use different Redis key prefixes for different instances in case you use one Redis Cache.
16 | - Remote Desktop - option to connect to Cloud Service through remote desktop on the machine. This is not supported for Azure Websites.
17 | - Extended Azure Logs - provides information about your Azure Role and thousands of metrics related to Azure environment
18 | - NLB instances - allows to use Sitefinity in NLB scenario - your Sitefinity license must support NLB
19 | - Azure Search - using Azure Search instead of built-in Lucene provider. Azure Search provides the engine for full-text search text analysis, advanced search features, search data storage, and a query command syntax
20 | - Blob storage providers - use blob storage for your binary data instead of file system or database. Blob storage service allows you to store Sitefinity large amounts of unstructured data, such as text or binary data( images or videos), that can be accessed from anywhere in the world via HTTP or HTTPS. You can use Blob storage to expose data publicly to the world, or to store application data privately
21 | - Use of publish settings file (Management certificate authentication)
22 |
23 | ## Requirements
24 | * Powershell 3.0+
25 | * Microsoft Azure Powershell - https://github.com/Azure/azure-powershell/releases
26 | * Microsoft Azure SDK 2.9.6 - https://www.microsoft.com/en-us/download/details.aspx?id=54289
27 | * Microsoft Azure Authoring Tools
28 | * Microsoft Azure Libraries for NET
29 | * Data Tier Application (DAC) Framework - https://www.microsoft.com/en-us/download/confirmation.aspx?id=53013
30 | * Web Deploy v.3.5 - https://www.microsoft.com/en-us/download/details.aspx?id=39277
31 |
32 | ## Azure Cloud Service Deployment
33 |
34 | #### Update the **AzureSubscriptionData.config** file under **~\CloudConfigs** folder
35 | - Set your **SubscriptionId**
36 | - Set your **SubscriptionName**
37 | - Set your **DeploymentLabel**
38 |
39 | #### Update the **Subscription1.publishsettings** file under **~\CloudConfigs** folder
40 | - Set your Subscription **Id**
41 | - Set your Subscription **Name**
42 | - Set your **ManagementCertificate**
43 |
44 | #### Update the needed properties in the **config.json** file under **~\Scripts\Configuration** folder
45 | - Set your azure **serverName**
46 | - Set your azure **server**
47 | - Set your azure **user**
48 | - Set your azure **password**
49 | - Set your azure **subscription**
50 | - Set the **certificate** properties which is used for **Remote Desktop Access** and for **SSL endpoint**
51 |
52 | ### Using lower version of Azure SDK for .NET
53 | If a lower version of Azure SDK for .NET than the specified in the requirements is used - make sure to update the **schemaVersion** attribute in:
54 | - CloudConfigs/ServiceConfiguration.Cloud.cscfg
55 | - CloudConfigs/ServiceConfiguration.Local.cscfg
56 | - CloudConfigs/ServiceDefinition.csdef
57 |
58 | #### Run the script for Deploying Sitefinity to Azure Cloud Service
59 | ```powershell
60 | .\DeploySitefinityToAzure.ps1 -websiteRootDirectory "C:\temp\SitefinityWebApp" -databaseName "SfDB1" -sqlServer ".\SQLSERVER" -serviceName "myservicename" -storageAccountName "mystorageaccname" -enableRemoteDesktopAccess "true" -enableSsl "false"
61 | ```
62 | #### Run the script for cleaning the Azure storage, service and database
63 | ```powershell
64 | .\CleanAzureData.ps1 -azureDatabaseName "SfDB1" -cloudServiceName "myservicename" -storageAccountName "mystorageaccname"
65 | ```
66 | ## Azure App Services Deployment
67 |
68 | #### Setup for Azure App Services deployment
69 | 1. Set Subscription Information
70 | 1. Run ```Get-AzurePublishSettingsFile``` powershell command or simply navigate to https://manage.windowsazure.com/publishsettings/index?client=powershell to download the publish settings file for your subscription.
71 | 1. Replace the content of **.\CloudConfigs\Subscription1.publishsettings** with the content from the publishsettings you have download in the previous step.
72 | 1. Open .\CloudConfigs\AzureSubscriptionData.config and set the following values:
73 | 1. **CertificateData** - located in the Subscription1.publishsettings file in the ManagementCertificate node
74 | 1. **SubscriptionId** - located in the Subscription1.publishsettings file in the Id node.
75 | 1. **SubscriptionName** - located in the Subscription1.publishsettings file in the Name node.
76 | 1. **DeploymentLabel** - label by your choice.
77 | 1. Set SQL Server information in **.\Scripts\Configurations\config.json** under azure.sql
78 | 1. **location** - this value is to differentiate multiple SQL Server instances in different location. Afterwards the script will know which SQL Server to choose by passing a location parameter. E.g. West Europe
79 | 1. **serverName** - Azure SQL Server name in Azure (e.g. sitefinitysql)
80 | 1. **server** - Full connection string of the Azure SQL Server (e.g. sitefinitysql.database.windows.net)
81 | 1. **user** - Azure SQL user
82 | 1. **password** - Azure SQL password
83 | 1. Open a new powershell session and run the script by specyfing the following parameters:
84 | 1. **websiteRootDirectory** - path to the SitefinityWebApp
85 | 1. **sqlServer** - the local instance of SQL Server (e.g. ".\SQLSERVER")
86 | 1. **databaseName** - the database name of the SitefinityWebApp you will deploy
87 | 1. **websiteName** - the app service name (website name) that will be created in azure
88 | 1. **[Optional]redisCacheConnectionString** - set this if you want to use redis cache. The correct format of the connection string is the following: ```primaryAccessKey@redisCacheName.redis.cache.windows.net?ssl=true```
89 | 1. **[Optional]websiteLocation** - Set where the location of the app service will be. This should match the SQL location property in the config.json you had applied in step. Default value is West Europe.
90 | 1. **[Optional]buildConfiguration** - Set the build configuration in which your project will be built - Debug/Release/ReleasePro... Default value is Release
91 | 1. **[Optional]launchWebsite** - if set, after the deployment finishes, powershell will make a request to the deployed website. Default value is $true
92 |
93 |
94 | **NOTE:** The scripts use default template file located in **.\Scripts\Templates\** You can use your own template file, but be careful with some of the properties, because there are some policies. For example there are policies for the sqlServerName, sqlPassword and search index name.
95 |
96 |
97 | #### Run the script for Deploying Sitefinity to Azure App Services
98 | ```powershell
99 | .\DeploySitefinityToAzureAppService.ps1 -websiteRootDirectory "C:\Tests\Sitefinity_10_0_HF3\Projects\azureAppServiceDemo" -databaseName "azureAppServiceDemoDb" -sqlServer ".\SQLSERVER" -websiteName "azureappsvcsfdemo" -redisCacheConnectionString "l6b65PIJza3zamYsNto8/cvtwtvvs1G4ffPBL3V6ybo=@sfdemoredis.redis.cache.windows.net?ssl=true" -websiteLocation "West Europe" -deployDatabase $true -buildConfiguration "Release" -launchWebsite $true
100 | ```
101 |
--------------------------------------------------------------------------------
/Scripts/CertificatesManagement.ps1:
--------------------------------------------------------------------------------
1 | function AddCertificateToService($serviceName, $certificate, $password)
2 | {
3 | Add-AzureCertificate -serviceName $serviceName -certToDeploy $certificate –password $password
4 | }
5 |
6 | function ImportCertificate($certPath, $thumbPrint)
7 | {
8 | $file = ( Get-ChildItem -Path $certPath )
9 |
10 | if ($file -eq $null) {
11 | throw “Management certificate could not be found under $certPath”
12 | }
13 |
14 | $cert = Get-Item Cert:\CurrentUser\My\$thumbPrint
15 | if ($cert -eq $null) {
16 | Write-Host “Management certificate was not found start importing to 'cert:\CurrentUser\My'”
17 | $file | Import-Certificate -CertStoreLocation cert:\CurrentUser\My
18 | }
19 | return $cert
20 | }
--------------------------------------------------------------------------------
/Scripts/CleanAzureData.ps1:
--------------------------------------------------------------------------------
1 | param($azureDatabaseName,
2 | $cloudServiceName,
3 | $storageAccountName,
4 | $accountLocation = "West Europe")
5 |
6 | . "$PSScriptRoot\Modules.ps1"
7 |
8 |
9 | $sqlConfig = $config.azure.sql | Where-Object { $_.location -eq $accountLocation }
10 |
11 |
12 | if($azureDatabaseName)
13 | {
14 | DeleteAzureDatabase $sqlConfig.serverName $azureDatabaseName $sqlConfig.user $sqlConfig.password
15 | }
16 | else
17 | {
18 | Write-Host "Database name is empty. Database cleanup will be skipped." -ForegroundColor Red
19 | }
20 |
21 | if($cloudServiceName)
22 | {
23 | RemoveCloudService $cloudServiceName
24 | }
25 | else
26 | {
27 | Write-Host "Cloud Service name is empty. Cloud Service cleanup will be skipped." -ForegroundColor Red
28 | }
29 |
30 | if($storageAccountName)
31 | {
32 | RemoveStorageAccount $storageAccountName
33 | }
34 | else
35 | {
36 | Write-Host "Storage Account name is empty. Storage Account cleanup will be skipped." -ForegroundColor Red
37 | }
--------------------------------------------------------------------------------
/Scripts/Common.ps1:
--------------------------------------------------------------------------------
1 | $MsBuildExe = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe"
2 |
3 | function Ensure-File([string]$path) {
4 | if ([System.IO.File]::Exists($path) -eq $false) {
5 | throw (New-Object 'System.IO.FileNotFoundException' -ArgumentList("${path} does not exist."))
6 | }
7 | }
8 |
9 | function LogMessage($message)
10 | {
11 | $currentTime = Get-Date -Format "HH:mm:ss"
12 | Write-Host "[[$currentTime]]::LOG:: $message"
13 | }
14 |
15 | function Get-Settings([string]$settingsPath) {
16 | Ensure-File -path $settingsPath
17 |
18 | $json = Get-Content $settingsPath -Raw
19 | $instance = $json | ConvertFrom-Json
20 |
21 | return $instance
22 | }
23 |
24 | function Get-AzureSdkPath {
25 | param($azureSdkPath)
26 | if(!$azureSdkPath)
27 | {
28 | if(!(Test-Path "$env:ProgramFiles\Microsoft SDKs\Azure\.NET SDK"))
29 | {
30 | $azureSdkPath = (dir "$env:ProgramFiles\Microsoft SDKs\Windows Azure\.NET SDK" -ErrorAction SilentlyContinue | sort Name -desc | select -first 1 ).FullName
31 | }
32 | else
33 | {
34 | #Path is changed for Azure .NET SDk 2.4 and above.
35 | $azureSdkPath = (dir "$env:ProgramFiles\Microsoft SDKs\Azure\.NET SDK" -ErrorAction SilentlyContinue | sort Name -desc | select -first 1 ).FullName
36 | }
37 |
38 | }
39 |
40 | if(!$azureSdkPath -or !(Test-Path $azureSdkPath))
41 | {
42 | throw "Azure SDK not found. Please specify the path to the Azure SDK in the AzureSdkPath parameter or modify the scrtips to get cspack.exe"
43 | }
44 |
45 | Write-Host "SDK path has been set to $azureSdkPath.";
46 | return $azureSdkPath
47 | }
48 |
49 | function Get-SqlPackageExePath
50 | {
51 | $MSSQLx64Directory = "$env:ProgramFiles\Microsoft SQL Server"
52 | $MSSQLx86Directory = "${env:ProgramFiles(x86)}\Microsoft SQL Server"
53 | if(Test-Path $MSSQLx64Directory)
54 | {
55 | $sqlPackageExe = Get-ChildItem $MSSQLx64Directory -Include SqlPackage.exe -Recurse -ErrorAction SilentlyContinue | Select-Object -Last 1
56 | if($sqlPackageExe -ne $null)
57 | {
58 | return $sqlPackageExe
59 | }
60 | }
61 | if(Test-Path $MSSQLx86Directory)
62 | {
63 | $sqlPackageExe = Get-ChildItem $MSSQLx86Directory -Include SqlPackage.exe -Recurse -ErrorAction SilentlyContinue | Select-Object -Last 1
64 | if($sqlPackageExe -ne $null)
65 | {
66 | return $sqlPackageExe
67 | }
68 | }
69 | throw "SqlPackage.exe was not found. Please ensure you have 'SqlPackage.exe' installed on your machine."
70 | }
71 |
72 | function BuildSln($sln, $target, $configuration, $paramsAsString)
73 | {
74 | LogMessage "Start building '$sln'"
75 | & $MsBuildExe $sln /t:$target /p:Configuration=$configuration /p:$paramsAsString
76 | }
--------------------------------------------------------------------------------
/Scripts/Configuration/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "azure": {
3 | "sql": [
4 | {
5 | "location": "",
6 | "serverName": "yourServerName",
7 | "server": "yourServerName.database.windows.net",
8 | "user": "yourUsername",
9 | "password": "yourPassword"
10 | }
11 | ],
12 | "subscription": "",
13 | "accountsLocation": "West Europe",
14 | "roleName": "SitefinityWebApp",
15 | "environment": "Production",
16 | "timeStampFormat": "g",
17 | "resourceGroupName": "",
18 | "azureAccount": "myschoolaccount@mydomain.onmicrosoft.com",
19 | "azureAccountPassword": "",
20 | "alwaysDeleteExistingDeployments": "1",
21 | "enableDeploymentUpgrade": "1",
22 | "sslEndpointName": "SslEndpoint",
23 | "storageAccountKey": ""
24 | },
25 | "files": {
26 | "serviceDefinition": "../CloudConfigs/ServiceDefinition.csdef",
27 | "roleProperties": "../CloudConfigs/RoleProperties.txt",
28 | "cloudConfig": "../CloudConfigs/ServiceConfiguration.Cloud.cscfg",
29 | "subscriptionPublishSettings": "../CloudConfigs/Subscription1.publishsettings",
30 | "azureSubscriptionDataConfig": "../CloudConfigs/AzureSubscriptionData.config",
31 | "azureSqlServerInforFilePath": "../CloudConfigs/SQLAzureServerInfo.config",
32 | "diagnosticsConfig": "../CloudConfigs/diagnostics.wadcfgx",
33 | "searchConfig": "../CloudConfigs/SearchConfig.config"
34 | },
35 | "remoteAccessSettings": [
36 | {
37 | "name": "Microsoft.WindowsAzure.Plugins.RemoteAccess.Enabled",
38 | "value": "true"
39 | },
40 | {
41 | "name": "Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountUsername",
42 | "value": "sitefinity"
43 | },
44 | {
45 | "name": "Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountEncryptedPassword",
46 | "value": "yourAccountEncryptedPassword"
47 | },
48 | {
49 | "name": "Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountExpiration",
50 | "value": "2018-01-22T23:59:59.0000000+02:00"
51 | },
52 | {
53 | "name": "Microsoft.WindowsAzure.Plugins.RemoteForwarder.Enabled",
54 | "value": "true"
55 | }
56 | ],
57 | "certificate":
58 | {
59 | "path":"path to your certificate",
60 | "password":"your remote access password",
61 | "name": "Microsoft.WindowsAzure.Plugins.RemoteAccess.PasswordEncryption",
62 | "thumbprint": "your certificate thumbprint",
63 | "thumbprintAlgorithm": "sha1"
64 | }
65 | }
--------------------------------------------------------------------------------
/Scripts/ConfigureRedisCache.ps1:
--------------------------------------------------------------------------------
1 | #Configures Redis cache in Sitefinity
2 | param(
3 | [Parameter(Mandatory=$True)]
4 | [String]
5 | $systemConfig,
6 | [Parameter(Mandatory=$True)]
7 | [String]
8 | $redisCacheConnectionString
9 | )
10 |
11 | Write-Warning "Configuring redis cache..."
12 |
13 | $doc = New-Object System.Xml.XmlDocument
14 | $doc.Load($systemConfig)
15 |
16 | $loadBalancingConfigNode = $doc.SelectSingleNode("//systemConfig/loadBalancingConfig")
17 | if($loadBalancingConfigNode -eq $null)
18 | {
19 | $loadBalancingConfigNode = $doc.CreateElement("loadBalancingConfig")
20 | $systemConfigNode = $doc.SelectSingleNode("//systemConfig")
21 | $systemConfigNode.AppendChild($loadBalancingConfigNode)
22 | }
23 |
24 | $redisSettingsNode = $doc.SelectSingleNode("//systemConfig/loadBalancingConfig/redisSettings")
25 | if($redisSettingsNode -eq $null)
26 | {
27 | $redisSettingsNode = $doc.CreateElement("redisSettings")
28 | $loadBalancingConfigNode.AppendChild($redisSettingsNode)
29 | }
30 |
31 | $redisSettingsNode.SetAttribute("ConnectionString", $redisCacheConnectionString)
32 |
33 | $doc.Save($systemConfig)
34 |
35 | Write-Warning "Redis cache has been configured."
--------------------------------------------------------------------------------
/Scripts/CreateAzurePackage.ps1:
--------------------------------------------------------------------------------
1 | . "$PSScriptRoot\Common.ps1"
2 |
3 | #Creates Azure package file that will be uploaded to Cloud Service
4 | function CreatePackage($serviceDefinitionPath, $outDir, $projectLocation, $roleName, $rolePropertiesFilePath)
5 | {
6 | $out = [string]::Format("/out:{0}", $outDir)
7 | $role = [string]::Format("/role:{0};{1}", $roleName, $projectLocation)
8 | $sites = [string]::Format("/sites:{0};{1};{2}", $roleName, "Web", $projectLocation)
9 | $roleProperties = [string]::Format("/rolePropertiesFile:{0};{1}", $roleName, $rolePropertiesFilePath)
10 |
11 | LogMessage ("[Start] creating azure cloud package with the following properites: definition path {0}, out directory {1}, role {2}, sites {3}, role properties {4}" -f $serviceDefinitionPath, $out, $role, $sites, $roleProperties)
12 |
13 | $cspackExe = Get-ChildItem -Path (Get-AzureSdkPath) -Include "cspack.exe" -Recurse | select -first 1
14 | & $cspackExe $serviceDefinitionPath $out $role $sites $roleProperties
15 | LogMessage ("[Completed] creating azure cloud package")
16 | }
--------------------------------------------------------------------------------
/Scripts/CreateSitefinityAzureResourceGroup.ps1:
--------------------------------------------------------------------------------
1 | param(
2 | $WebsiteRootDirectory = "",
3 | $DatabaseName = "",
4 | $SqlServer = "",
5 | $ResourceGroupName = "",
6 | $AzureAccount = "",
7 | $AzureAccountPassword = "",
8 | $ResourceGroupLocation = "West Europe",
9 | $TemplateFile = "$PSScriptRoot\Templates\Default.json",
10 | $TemplateParameterFile = "$PSScriptRoot\Templates\Default.params.json",
11 | $BuildConfiguration = "Release"
12 | )
13 |
14 | . "$PSScriptRoot\Modules.ps1"
15 |
16 | $templateParams = Get-Settings $TemplateParameterFile
17 |
18 | $sitefinityProject = Join-Path $websiteRootDirectory "SitefinityWebApp.csproj"
19 | $bacpacDatabaseFile = "$PSScriptRoot\temp\$DatabaseName.bacpac"
20 | $sqlConnectionUser = $templateParams.parameters.sqlServerAdminLogin.value
21 | $sqlConnectionServer = "$($templateParams.parameters.sqlServerName.value).database.windows.net"
22 | $sqlConnectionUsername = "$sqlConnectionUser@$sqlConnectionServer"
23 |
24 | $systemConfigPath = Join-Path $websiteRootDirectory "App_Data\Sitefinity\Configuration\SystemConfig.config"
25 | $outputPath = Join-Path $websiteRootDirectory "pkg"
26 | $buildParameters = "OutputPath=$outputPath;IgnoreDeployManagedRuntimeVersion=true;FilesToIncludeForPublish=AllFilesInProjectFolder"
27 |
28 | # Create new azure resource group
29 | NewAzureResourceGroup -ResourceGroupName $ResourceGroupName `
30 | -ResourceGroupLocation $ResourceGroupLocation `
31 | -AzureAccount $AzureAccount `
32 | -AzureAccountPassword $AzureAccountPassword `
33 | -TemplateFile $TemplateFile `
34 | -TemplateParameterFile $TemplateParameterFile
35 |
36 | # Configure powershell with publishsettings for your subscription
37 | Import-AzurePublishSettingsFile "$PSScriptRoot\$($config.files.subscriptionPublishSettings)"
38 | Set-AzureSubscription -SubscriptionName $config.azure.subscription
39 | Select-AzureSubscription -SubscriptionName $config.azure.subscription
40 |
41 | CreateDatabasePackage $sqlServer $DatabaseName $bacpacDatabaseFile
42 | DeployDatabasePackage $bacpacDatabaseFile $templateParams.parameters.sqlDatabaseName.value $sqlConnectionServer $templateParams.parameters.sqlServerAdminLogin.value $templateParams.parameters.sqlServerAdminLoginPassword.value
43 |
44 | # Update Sitefinity web.config and DataConfig.config with database settings.
45 | UpdateSitefinityWebConfig $websiteRootDirectory
46 | UpdateSitefinityDataConfig $websiteRootDirectory $sqlConnectionServer $sqlConnectionUsername $templateParams.parameters.sqlServerAdminLoginPassword.value $templateParams.parameters.sqlDatabaseName.value
47 |
48 | # Configure Redis Cache
49 | $redisCacheName = $templateParams.parameters.redisCacheName.value
50 | $redisPrimaryKey = GetAzureRedisCacheKey -ResourceGroupName $ResourceGroupName -CacheName $redisCacheName
51 | $redisCacheConnectionString = "$redisPrimaryKey@$redisCacheName.redis.cache.windows.net?ssl=true"
52 | LogMessage "RedisCache connection string: '$redisCacheConnectionString'"
53 | . "$PSScriptRoot\ConfigureRedisCache.ps1" $systemConfigPath $redisCacheConnectionString
54 | . "$PSScriptRoot\ConfigureTestNlbHandlers.ps1" $systemConfigPath
55 |
56 | # Configure Azure Search Service - currently no exposed API
57 | #$azureServiceAdminKey TODO
58 | #$azureSearchServiceName = $templateParams.parameters.azureSearchName.value
59 | #ConfigureAzureSearchService $config.files.searchConfig $azureServiceAdminKey $azureSearchServiceName
60 | #Copy-Item $config.files.searchConfig "$websiteRootDirectory\App_Data\Sitefinity\Configuration" -Force
61 |
62 | # Build deployment package
63 | BuildSln $sitefinityProject "Package" $BuildConfiguration $buildParameters
64 |
65 | $sfPackageLocationPath = Get-ChildItem $outputPath -Recurse -Include "SitefinityWebApp.zip"
66 | LogMessage "Publishing deployment package '$sfPackageLocationPath'..."
67 | Publish-AzureWebsiteProject -Name $templateParams.parameters.siteName.value -Package $sfPackageLocationPath
--------------------------------------------------------------------------------
/Scripts/DatabaseAzure.ps1:
--------------------------------------------------------------------------------
1 | . "$PSScriptRoot\Common.ps1"
2 | $sqlpackageExe = Get-SqlPackageExePath
3 |
4 | # e.g. $bacpacDatabaseFile="C:\temp\DatabaseName.bacpac"
5 | function CreateDatabasePackage($sqlServer, $databaseName, $bacpacDatabaseFile)
6 | {
7 | LogMessage "Creating database package..."
8 | & $sqlpackageExe /a:Export /ssn:$sqlServer /sdn:$databaseName /tf:$bacpacDatabaseFile
9 | LogMessage "Database package has been created."
10 | }
11 |
12 | function DeployDatabasePackage($bacpacDatabaseFile, $databaseName, $azureServer, $user, $password)
13 | {
14 | LogMessage "Importing database package..."
15 | try
16 | {
17 | & $sqlpackageExe /a:Import /sf:$bacpacDatabaseFile /tsn:$azureServer /tdn:$databaseName /tu:$user /tp:$password /p:DatabaseEdition="Basic"
18 | } catch {
19 | if(!($_.Exception.Message -ne $null -and $_.Exception.Message.Contains("compatibility issues with SQL Azure")))
20 | {
21 | throw $_.Exception
22 | }
23 | }
24 | LogMessage "Database package has been imported"
25 | }
26 |
27 | # The serverName must the be just the name of the azure server e.g. "servername" and not the full server address "vdxlfno62c.database.windows.net"
28 | function DeleteAzureDatabase($serverName, $databaseName, $user, $password)
29 | {
30 | $db_password = ConvertTo-SecureString -String $password -AsPlainText -Force
31 | $credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $db_password
32 | $context = New-AzureSqlDatabaseServerContext -ServerName $serverName -Credential $credential
33 | LogMessage "Deleting $databaseName from Azure $serverName server..."
34 | Remove-AzureSqlDatabase -Context $context -DatabaseName $databaseName -Force
35 | LogMessage "$databaseName database deleted from Azure $serverName server."
36 | }
37 |
38 | function EnsureDBDeleted($sqlServer, $dbName)
39 | {
40 | [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
41 | $Server = New-Object Microsoft.SqlServer.Management.Smo.Server($sqlServer)
42 | $DBObject = $Server.Databases[$dbName]
43 | if ($DBObject)
44 | {
45 | LogMessage "Deleting '$dbName' database from '$sqlServer' SQL Server."
46 | $Server.KillAllProcesses($dbName)
47 | $Server.KillDatabase($dbName)
48 | }
49 | }
50 |
51 | function ImportDatabaseFromAzure($azureServer, $databaseName, $user, $password, $sqlServer)
52 | {
53 | LogMessage "Exporting '$databaseName' database from '$azureServer' azure server..."
54 | $bacpacDatabaseFile = "$PSScriptRoot\$databaseName.bacpac"
55 | & $sqlpackageExe /a:Export /ssn:$azureServer /sdn:$databaseName /su:$user /sp:$password /tf:$bacpacDatabaseFile
56 |
57 | EnsureDBDeleted $sqlServer $databaseName
58 |
59 | LogMessage "Importing '$databaseName' database from '$azureServer' azure server..."
60 | & $sqlpackageExe /a:Import /sf:$bacpacDatabaseFile /tdn:$databaseName /tsn:$sqlServer
61 |
62 | Remove-Item $bacpacDatabaseFile
63 | }
64 |
65 | function BackupDatabase($sqlServer, $databaseName, $bakupFolder)
66 | {
67 | New-Item -ItemType Directory -Path $bakupFolder -Force
68 | $dbBakFullPath = $bakupFolder+"\" + $databaseName +".bak"
69 | SQLCMD.EXE -S $sqlServer -E -q "exit(BACKUP DATABASE [$databaseName] TO DISK='$dbBakFullPath')"
70 | }
--------------------------------------------------------------------------------
/Scripts/DeploySitefinityToAzureAppService.ps1:
--------------------------------------------------------------------------------
1 | <#
2 |
3 | .SYNOPSIS
4 | Script to deploy web app to Azure App Services.
5 |
6 | .DESCRIPTION
7 | This Powershell Script applies the required modifications and deploys the database and the sitefinity web app
8 | to Azure App Services. The deployment will set the minimal Pricing Tiers for the Database(Basic) and for the App Service(Free).
9 |
10 | .EXAMPLE
11 | .\DeploySitefinityToAzureAppService.ps1 -$websiteRootDirectory "pathToSitefinityWebApp" -databaseName "localDbName" -sqlServer "localSqlServerInstance" -websiteName "yourWebsiteName" -$redisCacheConnectionString "primaryKey@redisCacheName.redis.cache.windows.net?ssl=true"
12 |
13 | #>
14 | param([Parameter(Mandatory=$True)]$websiteRootDirectory,
15 | [Parameter(Mandatory=$True)]$databaseName,
16 | [Parameter(Mandatory=$True)]$sqlServer,
17 | [Parameter(Mandatory=$True)]$websiteName,
18 | $redisCacheConnectionString,
19 | $websiteLocation = "West Europe",
20 | $deployDatabase = $true,
21 | $buildConfiguration = "Release",
22 | $launchWebsite = $true)
23 |
24 | . "$PSScriptRoot\Modules.ps1"
25 |
26 | $sitefinityProject = Join-Path $websiteRootDirectory "SitefinityWebApp.csproj"
27 | $tempDir = "$PSScriptRoot\temp"
28 |
29 | if(!(Test-Path $tempDir))
30 | {
31 | New-Item $tempDir -ItemType Directory -Force
32 | }
33 |
34 | $bacpacDatabaseFile = "$tempDir\$databaseName.bacpac"
35 |
36 | $sqlConfig = $config.azure.sql | Where-Object { $_.location -eq $websiteLocation }
37 |
38 | Write-Host "Sql server is set to : $($sqlConfig.server)"
39 | $sqlConnectionUser = $sqlConfig.user
40 | $sqlConnectionServer = $sqlConfig.server
41 | $sqlConnectionUsername = "$sqlConnectionUser@$sqlConnectionServer"
42 |
43 | $systemConfigPath = Join-Path $websiteRootDirectory "App_Data\Sitefinity\Configuration\SystemConfig.config"
44 | $outputPath = Join-Path $websiteRootDirectory "pkg"
45 | $buildParameters = "OutputPath=$outputPath;IgnoreDeployManagedRuntimeVersion=true;FilesToIncludeForPublish=AllFilesInProjectFolder"
46 |
47 | # Configure powershell with publishsettings for your subscription
48 | Import-AzurePublishSettingsFile "$PSScriptRoot\$($config.files.subscriptionPublishSettings)"
49 | Set-AzureSubscription -SubscriptionName $config.azure.subscription
50 | Select-AzureSubscription -SubscriptionName $config.azure.subscription
51 | $subscription = Get-AzureSubscription $config.azure.subscription
52 | LogMessage "Azure Cloud Service deploy script started."
53 | LogMessage "Preparing deployment of $deploymentLabel for $($subscription.subscriptionname) with Subscription ID $($subscription.subscriptionid)."
54 |
55 | LogMessage 'Add-AzureWebsite: Start'
56 | $website = Get-AzureWebsite -Name $websiteName -ErrorAction SilentlyContinue
57 |
58 | if ($website)
59 | {
60 | LogMessage ('Add-AzureWebsite: An existing web site ' +
61 | $website.Name + ' was found')
62 | }
63 | else
64 | {
65 | if (Test-AzureName -Website -Name $websiteName)
66 | {
67 | LogMessage ('Website {0} already exists' -f $websiteName)
68 | }
69 | else
70 | {
71 | $website = New-AzureWebsite -Name $websiteName -Location $websiteLocation -Verbose
72 | }
73 | }
74 |
75 | $website | Out-String | Write-Host
76 | LogMessage 'Add-AzureWebsite: End'
77 |
78 | # Deploying Sitefinity database
79 | # First the database is packed from local isntance and then imported to the destination Azure server
80 | if($deployDatabase)
81 | {
82 | CreateDatabasePackage $sqlServer $databaseName $bacpacDatabaseFile
83 | DeployDatabasePackage $bacpacDatabaseFile $databaseName $sqlConfig.server $sqlConnectionUsername $sqlConfig.password
84 | }
85 | else
86 | {
87 | Write-Host "Deploy Database parameter set to: $deployDatabase. Skipping database deployment..."
88 | }
89 |
90 | # Update Sitefinity web.config and DataConfig.config with database settings.
91 | UpdateSitefinityWebConfig $websiteRootDirectory
92 | UpdateSitefinityDataConfig $websiteRootDirectory $sqlConfig.server $sqlConnectionUsername $sqlConfig.password $databaseName
93 |
94 | if([string]::IsNullOrEmpty($redisCacheConnectionString))
95 | {
96 | LogMessage "Redis connection string not specified. Skipping redis configuration"
97 | }
98 | else
99 | {
100 | # Configure Redis Cache
101 | . "$PSScriptRoot\ConfigureRedisCache.ps1" $systemConfigPath $redisCacheConnectionString
102 | }
103 |
104 | # Build deployment package
105 | BuildSln $sitefinityProject "Package" $buildConfiguration $buildParameters
106 |
107 | $sfPackageLocationPath = Get-ChildItem $outputPath -Recurse -Include "SitefinityWebApp.zip"
108 | LogMessage "Publishing deployment package '$sfPackageLocationPath'..."
109 | Publish-AzureWebsiteProject -Name $websiteName -Package $sfPackageLocationPath
110 |
111 | LogMessage "Azure websites deployment has completed."
112 | if ($launchWebsite -eq "true")
113 | {
114 | LogMessage "Opening '$websiteName' site..."
115 | Show-AzureWebsite -Name $websiteName
116 | }
117 |
--------------------------------------------------------------------------------
/Scripts/DeploySitefinityToAzureCloudService.ps1:
--------------------------------------------------------------------------------
1 | <#
2 |
3 | .SYNOPSIS
4 | Script to deploy web app to Azure Cloud Services.
5 |
6 | .DESCRIPTION
7 | This Powershell Script applies the required modifications and deploys the database and the sitefinity web app
8 | to Azure Cloud Services.
9 |
10 | .EXAMPLE
11 | .\DeploySitefinityToAzureCloudService.ps1 -$websiteRootDirectory "C:\SitefinityWebApp_10_0_6400_0\testdeployment" -databaseName "testdeploymentdb" -sqlServer ".\SQLSERVER" -serviceName "testdeployment" -storageAccountName "testdeployment"
12 |
13 | #>
14 | param([Parameter(Mandatory=$True)]$websiteRootDirectory,
15 | [Parameter(Mandatory=$True)]$databaseName,
16 | [Parameter(Mandatory=$True)]$sqlServer,
17 | [Parameter(Mandatory=$True)]$serviceName,
18 | [Parameter(Mandatory=$True)]$storageAccountName,
19 | $vmSize = "Medium",
20 | $enableRemoteDesktopAccess = "true",
21 | $enableDiagnostics = "true",
22 | $enableSsl = "false",
23 | $enableRedisCache = "false",
24 | $deployDatabase = "true",
25 | $instanceCount = '1',
26 | $accountLocation = "West Europe"
27 | )
28 |
29 | . "$PSScriptRoot\Modules.ps1"
30 |
31 | $serviceName = $serviceName.ToLower()
32 | $storageAccountName = $storageAccountName.ToLower()
33 | New-Item "$PSScriptRoot\temp" -ItemType "Directory" -Force
34 | $bacpacDatabaseFile = "$PSScriptRoot\temp\$databaseName.bacpac"
35 | $azurePackage = "$PSScriptRoot\temp\cloud_package.cspkg"
36 | $azureStartupTaskScripts = "$PSScriptRoot\..\CloudConfigs\StartupTasks"
37 | $startupTasksTargetDirectory = Join-Path $websiteRootDirectory "\bin\"
38 | $deploymentLabel = "ContinuousDeploy to $servicename"
39 | $slot = $config.azure.environment
40 | $serviceUrl = "$serviceName.cloudapp.net"
41 | $azureTempFilesDir = Join-Path $env:APPDATA "Windows Azure Powershell"
42 |
43 | $sqlConfig = $config.azure.sql | Where-Object { $_.location -eq $accountLocation }
44 |
45 | Write-Host "Sql server is set to : $($sqlConfig.server)"
46 | $sqlConnectionUser = $sqlConfig.user
47 | $sqlConnectionServer = $sqlConfig.server
48 | $sqlConnectionUsername = "$sqlConnectionUser@$sqlConnectionServer"
49 |
50 | try
51 | {
52 | $serviceDefinitionPath = Resolve-Path "$PSScriptRoot\$($config.files.serviceDefinition)"
53 | $cloudConfigPath = Resolve-Path "$PSScriptRoot\$($config.files.cloudConfig)"
54 | $subscriptionPublishSettingsPath = Resolve-Path "$PSScriptRoot\$($config.files.subscriptionPublishSettings)"
55 | $rolePropertiesPath = Resolve-Path "$PSScriptRoot\$($config.files.roleProperties)"
56 | $diagnosticsConfigPath = Resolve-Path "$PSScriptRoot\$($config.files.diagnosticsConfig)"
57 |
58 | Write-Host "Cleaning up Azure Subscriptions"
59 | Get-AzureSubscription | % { Remove-AzureSubscription $_.SubscriptionName -Force }
60 |
61 | Write-Host "Cleaning up temp Azure Powershell Files from $azureTempFilesDir"
62 | Get-ChildItem $azureTempFilesDir | % { Remove-Item $_.FullName }
63 |
64 | #configure powershell with publishsettings for your subscription
65 | Import-AzurePublishSettingsFile $subscriptionPublishSettingsPath
66 |
67 | $acc = CreateStorageAccount $storageAccountName $accountLocation
68 | Set-AzureSubscription -CurrentStorageAccountName $storageAccountName -SubscriptionName $config.azure.subscription
69 | Select-AzureSubscription -SubscriptionName $config.azure.subscription
70 | $subscription = Get-AzureSubscription $config.azure.subscription
71 |
72 | LogMessage "Azure Cloud Service deploy script started."
73 | LogMessage "Preparing deployment of $deploymentLabel for $($subscription.subscriptionname) with Subscription ID $($subscription.subscriptionid)."
74 |
75 | if($deployDatabase -eq "true")
76 | {
77 | CreateDatabasePackage $sqlServer $databaseName $bacpacDatabaseFile
78 | DeployDatabasePackage $bacpacDatabaseFile $databaseName $sqlConfig.server $sqlConnectionUsername $sqlConfig.password
79 | UpdateSQLAzureServerInfoData $databaseName $databaseName
80 | }
81 | else
82 | {
83 | Write-Host "Deploy Database parameter set to: $deployDatabase. Skipping database deployment..."
84 | }
85 |
86 | #Copies all startup task scripts to the website binaries directory.
87 | robocopy $azureStartupTaskScripts $startupTasksTargetDirectory
88 |
89 | UpdateInstancesCount $instanceCount
90 |
91 | if([int]$instanceCount -gt 1)
92 | {
93 | UpdateSitefinityWebConfig $websiteRootDirectory
94 | }
95 | if($enableDiagnostics -eq "true")
96 | {
97 | EnableAzureTraceListener $websiteRootDirectory
98 | }
99 |
100 | UpdateSitefinityDataConfig $websiteRootDirectory $sqlConfig.server $sqlConnectionUsername $sqlConfig.password $databaseName
101 |
102 | if($enableRedisCache -eq "true")
103 | {
104 | #The AzureResourceManager module requires Add-AzureAccount. A Publish Settings file is not sufficient.
105 | $secpassword = ConvertTo-SecureString $config.azure.azureAccountPassword -AsPlainText -Force
106 | $credentials = New-Object System.Management.Automation.PSCredential ($config.azure.azureAccount, $secpassword)
107 | Add-AzureAccount -Credential $credentials
108 | $redisCacheName = "$($serviceName)redis"
109 | $redisPrimaryKey = NewAzureRedisCache -CacheName $redisCacheName -ResourceGroupName $config.azure.resourceGroupName -Location $config.azure.accountsLocation
110 | $redisCacheConnectionString = "$redisPrimaryKey@$redisCacheName.redis.cache.windows.net?ssl=true"
111 | $systemConfigPath = "$websiteRootDirectory\App_Data\Sitefinity\Configuration\SystemConfig.config"
112 | LogMessage "RedisCache connection string: '$redisCacheConnectionString'"
113 | . "$PSScriptRoot\..\..\CommonScripts\PowerShell\Common\SitefinitySetup\ConfigureRedisCache.ps1" $systemConfigPath $redisCacheConnectionString
114 | }
115 |
116 | $serv = CreateCloudService $serviceName $accountLocation
117 |
118 | UpdateAzureSubscriptionData $acc.AccountName $serv.ServiceName $acc.AccountName $accountLocation
119 | UpdateServiceConfigurationCloudData $acc.AccountName $acc.AccessKey
120 | if($enableSsl -eq "true" -or $enableRemoteDesktopAccess -eq "true")
121 | {
122 | $certificatePath = Resolve-Path "$PSScriptRoot\$($config.certificate.path)"
123 | AddCertificateToService $serviceName $certificatePath $config.certificate.password
124 | AddCertificatesNode
125 | } else {
126 | DeleteCertificatesNode
127 | }
128 | ConfigureSsl -EnableSsl $enableSsl
129 | ConfigureRemoteDesktop -EnableRemoteDesktopAccess $enableRemoteDesktopAccess
130 | UpdateVMSize -ServiceDefinitionPath "$serviceDefinitionPath" -VMSize $vmSize
131 |
132 | CreatePackage $serviceDefinitionPath $azurePackage $websiteRootDirectory $config.azure.roleName $rolePropertiesPath
133 | Publish $serv.ServiceName $acc.AccountName $azurePackage $cloudConfigPath $config.azure.environment $deploymentLabel $config.azure.timeStampFormat $config.azure.alwaysDeleteExistingDeployments $config.azure.enableDeploymentUpgrade $config.azure.subscription $subscriptionPublishSettingsPath
134 |
135 | if($enableDiagnostics -eq "true")
136 | {
137 | LogMessage "Setting AzureServiceDiagnosticsExtension..."
138 | $storageAccountKey = (Get-AzureStorageKey -StorageAccountName $storageAccountName).Primary
139 | $storageContext = New-AzureStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageAccountKey
140 | Set-AzureServiceDiagnosticsExtension -ServiceName $serviceName -DiagnosticsConfigurationPath $diagnosticsConfigPath -StorageContext $storageContext -Role $config.azure.roleName
141 | }
142 | }
143 | finally
144 | {
145 | LogMessage "Azure deployment has completed."
146 | }
147 |
--------------------------------------------------------------------------------
/Scripts/ManageAzureRedisCache.ps1:
--------------------------------------------------------------------------------
1 | # Creates new redis cache in an already existing resource group
2 | # The AzureResourceManager module requires Add-AzureAccount
3 | function NewAzureRedisCache
4 | {
5 | Param(
6 | [Parameter(Mandatory=$true)]
7 | [String]
8 | $CacheName
9 | ,
10 | [Parameter(Mandatory=$true)]
11 | [String]
12 | $ResourceGroupName
13 | ,
14 | [Parameter(Mandatory=$true)]
15 | [String]
16 | $Location
17 | ,
18 | [ValidateSet("Basic","Standard")]
19 | [String]
20 | $Sku="Basic"
21 | )
22 |
23 | Switch-AzureMode AzureResourceManager
24 | Write-Host "Creating '$cacheName' azure redis cache..."
25 | $redisCache = New-AzureRedisCache -Location $location -Name $cacheName -ResourceGroupName $resourceGroupName -Size 250MB -Sku $Sku
26 |
27 | # Wait until the Cache is provisioned.
28 | for ($i = 0; $i -le 60; $i++)
29 | {
30 | Start-Sleep -s 30
31 | $cacheGet = Get-AzureRedisCache -ResourceGroupName $resourceGroupName -Name $cacheName
32 | Write-Host "'$cacheName' redis cache current state is '$($cacheGet[0].ProvisioningState)'..."
33 | if ([string]::Compare("succeeded", $cacheGet[0].ProvisioningState, $True) -eq 0)
34 | {
35 | break
36 | }
37 | If($i -eq 60)
38 | {
39 | exit
40 | }
41 | }
42 |
43 | $cacheKeys = Get-AzureRedisCacheKey -ResourceGroupName $resourceGroupName -Name $cacheName
44 | Switch-AzureMode AzureServiceManagement
45 | return $($cacheKeys.PrimaryKey)
46 | }
47 |
48 | function GetAzureRedisCacheKey
49 | {
50 | Param(
51 | [Parameter(Mandatory=$true)]
52 | [String]
53 | $CacheName
54 | ,
55 | [Parameter(Mandatory=$true)]
56 | [String]
57 | $ResourceGroupName
58 | )
59 | Switch-AzureMode AzureResourceManager
60 |
61 | $cacheKeys = Get-AzureRedisCacheKey -ResourceGroupName $ResourceGroupName -Name $CacheName
62 |
63 | Switch-AzureMode AzureServiceManagement
64 | return $($cacheKeys.PrimaryKey)
65 | }
--------------------------------------------------------------------------------
/Scripts/ManageAzureResourceGroup.ps1:
--------------------------------------------------------------------------------
1 | # Creates new azure resource group with website template
2 | # The AzureResourceManager module requires Add-AzureAccount
3 | function NewAzureResourceGroup
4 | {
5 | Param(
6 | [Parameter(Mandatory=$true)]
7 | $ResourceGroupName,
8 | [Parameter(Mandatory=$true)]
9 | $AzureAccount,
10 | [Parameter(Mandatory=$true)]
11 | $AzureAccountPassword,
12 | $ResourceGroupLocation = "West Europe",
13 | $TemplateFile = "$PSScriptRoot\Templates\Default.json",
14 | $TemplateParameterFile = "$PSScriptRoot\Templates\Default.params.json"
15 | )
16 |
17 | Switch-AzureMode AzureResourceManager
18 |
19 | #NOTE:
20 | #The AzureResourceManager module requires Add-AzureAccount. A Publish Settings file is not sufficient.
21 | $secpassword = ConvertTo-SecureString $AzureAccountPassword -AsPlainText -Force
22 | $credentials = New-Object System.Management.Automation.PSCredential ($AzureAccount, $secpassword)
23 | Add-AzureAccount -Credential $credentials
24 |
25 | #Creating new AzureResourceGroup
26 | Write-Host "Creating '$ResourceGroupName' Azure Resource group..."
27 |
28 |
29 | New-AzureResourceGroup -Name $ResourceGroupName `
30 | -Location $ResourceGroupLocation `
31 | -TemplateFile $TemplateFile `
32 | -TemplateParameterFile $TemplateParameterFile `
33 | -Force -Verbose
34 |
35 | Write-Host "'$ResourceGroupName' Azure Resource group has been successfully created."
36 |
37 | Switch-AzureMode AzureServiceManagement
38 | }
--------------------------------------------------------------------------------
/Scripts/ManageAzureServices.ps1:
--------------------------------------------------------------------------------
1 | #Creates Cloud Service
2 | function CreateCloudService($Name, $Location)
3 | {
4 | $service = Get-AzureService | where { $_.ServiceName -eq $Name }
5 | if(!$service)
6 | {
7 | LogMessage ("[Start] creating cloud service {0} in location {1}" -f $Name, $Location)
8 | New-AzureService -ServiceName $Name -Location $Location
9 | LogMessage ("[Finish] creating cloud service {0} in location {1}" -f $Name, $Location)
10 | }
11 | else
12 | {
13 | LogMessage ("Cloud service '{0}' exists. New cloud service hasn't been created" -f $Name)
14 | }
15 |
16 | Return @{ServiceName = $Name}
17 | }
18 |
19 | #Removes Cloud Service
20 | function RemoveCloudService($Name)
21 | {
22 | LogMessage ("[Start] removing cloud service {0}" -f $Name)
23 | $service = Get-AzureService | where { $_.ServiceName -eq $Name }
24 | if($service)
25 | {
26 | LogMessage ("[InProgress] cloud service found {0}" -f $Name)
27 | $stat = Remove-AzureService $service.ServiceName -Force
28 | if($stat.OperationStatus -eq "Succeeded")
29 | {
30 | LogMessage ("[Finish] removing cloud service {0}" -f $Name)
31 | }
32 | else
33 | {
34 | LogMessage ("Removing cloud service '{0}' failed" -f $Name)
35 | }
36 | }
37 | else
38 | {
39 | LogMessage ("Cloud service '{0}' not found" -f $Name)
40 | }
41 | }
--------------------------------------------------------------------------------
/Scripts/ManageAzureStorage.ps1:
--------------------------------------------------------------------------------
1 | #Creates Storage Account
2 | function CreateStorageAccount($Name, $Location)
3 | {
4 | $sAccount = Get-AzureStorageAccount | where { $_.StorageAccountName -eq $Name }
5 | if(!$sAccount)
6 | {
7 | # Create a new storage account
8 | LogMessage ("[Start] creating storage account {0} in location {1}" -f $Name, $Location)
9 | New-AzureStorageAccount -StorageAccountName $Name -Location $Location -Verbose
10 | LogMessage ("[Finish] creating storage account {0} in location {1}" -f $Name, $Location)
11 | }
12 | else
13 | {
14 | LogMessage ("Storage account '{0}' exists. New azure storage account hasn't been created" -f $Name)
15 | }
16 | # Get the access key of the storage account
17 | $key = Get-AzureStorageKey -StorageAccountName $Name
18 | # Generate the connection string of the storage account
19 | $connectionString = "BlobEndpoint=http://{0}.blob.core.windows.net/;QueueEndpoint=http://{0}.queue.core.windows.net/;TableEndpoint=http://{0}.table.core.windows.net/;AccountName={0};AccountKey={1}" -f $Name, $key.Primary
20 |
21 | #this returns the storage key. example $storageData.AccessKey
22 | Return @{AccountName = $Name; AccessKey = $key.Primary; ConnectionString = $connectionString}
23 | }
24 |
25 | #Removes Storage account
26 | function RemoveStorageAccount($Name)
27 | {
28 | LogMessage ("[Start] removing storage account {0}" -f $Name)
29 | $sAccount = Get-AzureStorageAccount | where { $_.StorageAccountName -eq $Name }
30 | if($sAccount)
31 | {
32 | LogMessage ("[InProgress] storage account found {0}" -f $Name)
33 | $stat = Remove-AzureStorageAccount -StorageAccountName $Name
34 | if($stat.OperationStatus -eq "Succeeded")
35 | {
36 | LogMessage ("[Finish] removing storage account {0}" -f $Name)
37 | }
38 | else
39 | {
40 | LogMessage ("Removing storage account '{0}' failed" -f $Name)
41 | }
42 | }
43 | else
44 | {
45 | LogMessage ("Storage account '{0}' not found" -f $Name)
46 | }
47 | }
--------------------------------------------------------------------------------
/Scripts/Modules.ps1:
--------------------------------------------------------------------------------
1 | #$ErrorActionPreference = "Stop"
2 |
3 | . "$PSScriptRoot\Common.ps1"
4 | . "$PSScriptRoot\CreateAzurePackage.ps1"
5 | . "$PSScriptRoot\DatabaseAzure.ps1"
6 | . "$PSScriptRoot\ManageAzureServices.ps1"
7 | . "$PSScriptRoot\ManageAzureStorage.ps1"
8 | . "$PSScriptRoot\ManageAzureResourceGroup.ps1"
9 | . "$PSScriptRoot\ManageAzureRedisCache.ps1"
10 | . "$PSScriptRoot\PublishCloudService.ps1"
11 | . "$PSScriptRoot\UpdateAzureCloudConfigs.ps1"
12 | . "$PSScriptRoot\UpdateSitefinityConfigs.ps1"
13 | . "$PSScriptRoot\CertificatesManagement.ps1"
14 |
15 | #configure powershell with Azure 1.7 modules
16 | Import-Module "C:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Azure.psd1"
17 | $config = Get-Settings "$PSScriptRoot\Configuration\config.json"
--------------------------------------------------------------------------------
/Scripts/PublishCloudService.ps1:
--------------------------------------------------------------------------------
1 | function Publish($serviceName, $storageAccountName, $packageLocation, $cloudConfigLocation, $environment, $deploymentLabel, $timeStampFormat, $alwaysDeleteExistingDeployments, $enableDeploymentUpgrade, $selectedsubscription)
2 | {
3 | LogMessage ("[Publish] is called with the folling parameters 'Serivce name: {0}', 'Storage account name: {1}', 'Package location: {2}','Cloud config location: {3}', 'Environment: {4}' " -f $serviceName, $storageAccountName, $packageLocation, $cloudConfigLocation, $environment)
4 |
5 | $deployment = Get-AzureDeployment -ServiceName $serviceName -Slot $slot -ErrorVariable a -ErrorAction silentlycontinue
6 | if ($a[0] -ne $null)
7 | {
8 | LogMessage "No deployment is detected. Creating a new deployment. "
9 | }
10 | #check for existing deployment and then either upgrade, delete + deploy, or cancel according to $alwaysDeleteExistingDeployments and $enableDeploymentUpgrade boolean variables
11 | if ($deployment.Name -ne $null)
12 | {
13 | switch ($alwaysDeleteExistingDeployments)
14 | {
15 | 1
16 | {
17 | switch ($enableDeploymentUpgrade)
18 | {
19 | 1 #Update deployment inplace (usually faster, cheaper, won't destroy VIP)
20 | {
21 | LogMessage "Deployment exists in $servicename. Upgrading deployment..."
22 | UpgradeDeployment
23 | }
24 | 0 #Delete then create new deployment
25 | {
26 | LogMessage "Deployment exists in $servicename. Deleting deployment..."
27 | DeleteDeployment
28 | CreateNewDeployment
29 |
30 | }
31 | } # switch ($enableDeploymentUpgrade)
32 | }
33 | 0
34 | {
35 | LogMessage "ERROR: Deployment exists in $servicename. Script execution cancelled."
36 | exit
37 | }
38 | } #switch ($alwaysDeleteExistingDeployments)
39 | } else {
40 | CreateNewDeployment
41 | }
42 |
43 | $deployment = Get-AzureDeployment -slot $slot -serviceName $servicename
44 | $deploymentUrl = $deployment.Url
45 |
46 | LogMessage "Created Cloud Service with URL $deploymentUrl."
47 | LogMessage "Azure Cloud Service deploy script finished."
48 | }
49 |
50 | function CreateNewDeployment()
51 | {
52 | write-progress -id 3 -activity "Creating New Deployment" -Status "In progress"
53 | LogMessage "Creating New Deployment: In progress"
54 |
55 | $opstat = New-AzureDeployment -Slot $slot -Package $packageLocation -Configuration $cloudConfigLocation -label $deploymentLabel -ServiceName $serviceName
56 |
57 | $completeDeployment = Get-AzureDeployment -ServiceName $serviceName -Slot $slot
58 | $completeDeploymentID = $completeDeployment.deploymentid
59 |
60 | write-progress -id 3 -activity "Creating New Deployment" -completed -Status "Complete"
61 | LogMessage "Creating New Deployment: Complete, Deployment ID: $completeDeploymentID"
62 |
63 | StartInstances
64 | }
65 |
66 | function UpgradeDeployment()
67 | {
68 | write-progress -id 3 -activity "Upgrading Deployment" -Status "In progress"
69 | LogMessage "Upgrading Deployment: In progress"
70 |
71 | LogMessage "Slot: '$slot', Label: '$deploymentLabel', ServiceName: '$serviceName'"
72 | # perform Update-Deployment
73 | $setdeployment = Set-AzureDeployment -Upgrade -Slot $slot -Package $packageLocation -Configuration $cloudConfigLocation -label $deploymentLabel -ServiceName $serviceName -Force
74 |
75 | $completeDeployment = Get-AzureDeployment -ServiceName $serviceName -Slot $slot
76 | $completeDeploymentID = $completeDeployment.deploymentid
77 |
78 | write-progress -id 3 -activity "Upgrading Deployment" -completed -Status "Complete"
79 | LogMessage "Upgrading Deployment: Complete, Deployment ID: $completeDeploymentID"
80 | }
81 |
82 | function DeleteDeployment()
83 | {
84 |
85 | write-progress -id 2 -activity "Deleting Deployment" -Status "In progress"
86 | LogMessage "Deleting Deployment: In progress"
87 |
88 | #WARNING - always deletes with force
89 | $removeDeployment = Remove-AzureDeployment -Slot $slot -ServiceName $serviceName -Force
90 |
91 | write-progress -id 2 -activity "Deleting Deployment: Complete" -completed -Status $removeDeployment
92 | LogMessage "Deleting Deployment: Complete"
93 | }
94 |
95 | function StartInstances()
96 | {
97 | write-progress -id 4 -activity "Starting Instances" -status "In progress"
98 | LogMessage "Starting Instances: In progress"
99 |
100 | $deployment = Get-AzureDeployment -ServiceName $serviceName -Slot $slot
101 | $runstatus = $deployment.Status
102 |
103 | if ($runstatus -ne 'Running')
104 | {
105 | $run = Set-AzureDeployment -Slot $slot -ServiceName $serviceName -Status Running
106 | }
107 | $deployment = Get-AzureDeployment -ServiceName $serviceName -Slot $slot
108 | $oldStatusStr = @("") * $deployment.RoleInstanceList.Count
109 |
110 | while (-not(AllInstancesRunning($deployment.RoleInstanceList)))
111 | {
112 | $i = 1
113 | foreach ($roleInstance in $deployment.RoleInstanceList)
114 | {
115 | $instanceName = $roleInstance.InstanceName
116 | $instanceStatus = $roleInstance.InstanceStatus
117 |
118 | if ($oldStatusStr[$i - 1] -ne $roleInstance.InstanceStatus)
119 | {
120 | $oldStatusStr[$i - 1] = $roleInstance.InstanceStatus
121 | LogMessage "Starting Instance '$instanceName': $instanceStatus"
122 | }
123 |
124 | write-progress -id (4 + $i) -activity "Starting Instance '$instanceName'" -status "$instanceStatus"
125 | $i = $i + 1
126 | }
127 |
128 | sleep -Seconds 1
129 |
130 | $deployment = Get-AzureDeployment -ServiceName $serviceName -Slot $slot
131 | }
132 |
133 | $i = 1
134 | foreach ($roleInstance in $deployment.RoleInstanceList)
135 | {
136 | $instanceName = $roleInstance.InstanceName
137 | $instanceStatus = $roleInstance.InstanceStatus
138 |
139 | if ($oldStatusStr[$i - 1] -ne $roleInstance.InstanceStatus)
140 | {
141 | $oldStatusStr[$i - 1] = $roleInstance.InstanceStatus
142 | LogMessage "Starting Instance '$instanceName': $instanceStatus"
143 | }
144 |
145 | $i = $i + 1
146 | }
147 |
148 | $deployment = Get-AzureDeployment -ServiceName $serviceName -Slot $slot
149 | $opstat = $deployment.Status
150 |
151 | write-progress -id 4 -activity "Starting Instances" -completed -status $opstat
152 | LogMessage "Starting Instances: $opstat"
153 | }
154 |
155 | function AllInstancesRunning($roleInstanceList)
156 | {
157 | foreach ($roleInstance in $roleInstanceList)
158 | {
159 | if ($roleInstance.InstanceStatus -ne "ReadyRole")
160 | {
161 | return $false
162 | }
163 | }
164 |
165 | return $true
166 | }
--------------------------------------------------------------------------------
/Scripts/Templates/Default.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "siteName": {
6 | "type": "string"
7 | },
8 | "hostingPlanName": {
9 | "type": "string"
10 | },
11 | "siteLocation": {
12 | "type": "string"
13 | },
14 | "sku": {
15 | "type": "string",
16 | "allowedValues": [
17 | "Free",
18 | "Shared",
19 | "Basic",
20 | "Standard",
21 | "Premium"
22 | ],
23 | "defaultValue": "Free"
24 | },
25 | "instancesCount": {
26 | "type": "int",
27 | "defaultValue": 1
28 | },
29 | "workerSize": {
30 | "type": "string",
31 | "allowedValues": [
32 | "0",
33 | "1",
34 | "2"
35 | ],
36 | "defaultValue": "0"
37 | },
38 | "redisCacheName": {
39 | "type": "string"
40 | },
41 | "redisCacheLocation": {
42 | "type": "string"
43 | },
44 | "redisCacheSKUName": {
45 | "type": "string",
46 | "allowedValues": [
47 | "Basic",
48 | "Standard"
49 | ],
50 | "defaultValue": "Standard"
51 | },
52 | "redisCacheSKUFamily": {
53 | "type": "string",
54 | "allowedValues": [
55 | "C"
56 | ],
57 | "defaultValue": "C"
58 | },
59 | "redisCacheSKUCapacity": {
60 | "type": "int",
61 | "allowedValues": [
62 | 0,
63 | 1,
64 | 2,
65 | 3,
66 | 4,
67 | 5,
68 | 6
69 | ],
70 | "defaultValue": 0
71 | },
72 | "redisCacheVersion": {
73 | "type": "string",
74 | "allowedValues": [
75 | "2.8"
76 | ],
77 | "defaultValue": "2.8"
78 | },
79 | "sqlServerName": {
80 | "type": "string"
81 | },
82 | "sqlServerLocation": {
83 | "type": "string"
84 | },
85 | "sqlServerAdminLogin": {
86 | "type": "string"
87 | },
88 | "sqlServerAdminLoginPassword": {
89 | "type": "securestring"
90 | },
91 | "sqlDatabaseName": {
92 | "type": "string"
93 | },
94 | "sqlDatabaseCollation": {
95 | "type": "string",
96 | "defaultValue": "SQL_Latin1_General_CP1_CI_AS"
97 | },
98 | "sqlDatabaseEdition": {
99 | "type": "string",
100 | "defaultValue": "Web",
101 | "allowedValues": [
102 | "Basic",
103 | "Business",
104 | "Premium",
105 | "Standard",
106 | "Web"
107 | ]
108 | },
109 | "azureSearchName": {
110 | "type": "string"
111 | },
112 | "azureSearchLocation": {
113 | "type": "string"
114 | },
115 | "azureSearchSku": {
116 | "type": "string",
117 | "allowedValues": [
118 | "free",
119 | "standard",
120 | "standard2"
121 | ],
122 | "defaultValue": "standard"
123 | },
124 | "azureSearchReplicaCount": {
125 | "type": "int",
126 | "allowedValues": [
127 | 1,
128 | 2,
129 | 3,
130 | 4,
131 | 5,
132 | 6
133 | ],
134 | "defaultValue": 1
135 | },
136 | "azureSearchPartitionCount": {
137 | "type": "int",
138 | "allowedValues": [
139 | 1,
140 | 2,
141 | 3,
142 | 4,
143 | 6,
144 | 12
145 | ],
146 | "defaultValue": 1
147 | }
148 | },
149 | "resources": [
150 | {
151 | "apiVersion": "2014-06-01",
152 | "name": "[parameters('hostingPlanName')]",
153 | "type": "Microsoft.Web/serverfarms",
154 | "location": "[parameters('siteLocation')]",
155 | "tags": {
156 | "displayName": "HostingPlan"
157 | },
158 | "properties": {
159 | "name": "[parameters('hostingPlanName')]",
160 | "sku": "[parameters('sku')]",
161 | "workerSize": "[parameters('workerSize')]",
162 | "numberOfWorkers": "[parameters('instancesCount')]"
163 | }
164 | },
165 | {
166 | "apiVersion": "2014-06-01",
167 | "name": "[parameters('siteName')]",
168 | "type": "Microsoft.Web/sites",
169 | "location": "[parameters('siteLocation')]",
170 | "tags": {
171 | "[concat('hidden-related:', resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]": "Resource",
172 | "displayName": "Website"
173 |
174 | },
175 | "dependsOn": [
176 | "[concat('Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]"
177 | ],
178 | "properties": {
179 | "name": "[parameters('siteName')]",
180 | "serverFarm": "[parameters('hostingPlanName')]"
181 | }
182 | },
183 | {
184 | "apiVersion": "2014-04-01",
185 | "name": "[concat(parameters('hostingPlanName'), '-', resourceGroup().name)]",
186 | "type": "Microsoft.Insights/autoscalesettings",
187 | "location": "[parameters('siteLocation')]",
188 | "tags": {
189 | "[concat('hidden-link:', resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]": "Resource",
190 | "displayName": "AutoScaleSettings"
191 | },
192 | "dependsOn": [
193 | "[concat('Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]"
194 | ],
195 | "properties": {
196 | "profiles": [
197 | {
198 | "name": "Default",
199 | "capacity": {
200 | "minimum": 1,
201 | "maximum": 2,
202 | "default": 1
203 | },
204 | "rules": [
205 | {
206 | "metricTrigger": {
207 | "metricName": "CpuPercentage",
208 | "metricResourceUri": "[concat(resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]",
209 | "timeGrain": "PT1M",
210 | "statistic": "Average",
211 | "timeWindow": "PT10M",
212 | "timeAggregation": "Average",
213 | "operator": "GreaterThan",
214 | "threshold": 80.0
215 | },
216 | "scaleAction": {
217 | "direction": "Increase",
218 | "type": "ChangeCount",
219 | "value": 1,
220 | "cooldown": "PT10M"
221 | }
222 | },
223 | {
224 | "metricTrigger": {
225 | "metricName": "CpuPercentage",
226 | "metricResourceUri": "[concat(resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]",
227 | "timeGrain": "PT1M",
228 | "statistic": "Average",
229 | "timeWindow": "PT1H",
230 | "timeAggregation": "Average",
231 | "operator": "LessThan",
232 | "threshold": 60.0
233 | },
234 | "scaleAction": {
235 | "direction": "Decrease",
236 | "type": "ChangeCount",
237 | "value": 1,
238 | "cooldown": "PT1H"
239 | }
240 | }
241 | ]
242 | }
243 | ],
244 | "enabled": false,
245 | "name": "[concat(parameters('hostingPlanName'), '-', resourceGroup().name)]",
246 | "targetResourceUri": "[concat(resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]"
247 | }
248 | },
249 | {
250 | "apiVersion": "2014-04-01",
251 | "name": "[concat('ServerErrors ', parameters('siteName'))]",
252 | "type": "Microsoft.Insights/alertrules",
253 | "location": "[parameters('siteLocation')]",
254 | "dependsOn": [
255 | "[concat('Microsoft.Web/sites/', parameters('siteName'))]"
256 | ],
257 | "tags": {
258 | "[concat('hidden-link:', resourceGroup().id, '/providers/Microsoft.Web/sites/', parameters('siteName'))]": "Resource",
259 | "displayName": "ServerErrorsAlertRule"
260 | },
261 | "properties": {
262 | "name": "[concat('ServerErrors ', parameters('siteName'))]",
263 | "description": "[concat(parameters('siteName'), ' has some server errors, status code 5xx.')]",
264 | "isEnabled": false,
265 | "condition": {
266 | "odata.type": "Microsoft.Azure.Management.Insights.Models.ThresholdRuleCondition",
267 | "dataSource": {
268 | "odata.type": "Microsoft.Azure.Management.Insights.Models.RuleMetricDataSource",
269 | "resourceUri": "[concat(resourceGroup().id, '/providers/Microsoft.Web/sites/', parameters('siteName'))]",
270 | "metricName": "Http5xx"
271 | },
272 | "operator": "GreaterThan",
273 | "threshold": 0.0,
274 | "windowSize": "PT5M"
275 | },
276 | "action": {
277 | "odata.type": "Microsoft.Azure.Management.Insights.Models.RuleEmailAction",
278 | "sendToServiceOwners": true,
279 | "customEmails": []
280 | }
281 | }
282 | },
283 | {
284 | "apiVersion": "2014-04-01",
285 | "name": "[concat('ForbiddenRequests ', parameters('siteName'))]",
286 | "type": "Microsoft.Insights/alertrules",
287 | "location": "[parameters('siteLocation')]",
288 | "dependsOn": [
289 | "[concat('Microsoft.Web/sites/', parameters('siteName'))]"
290 | ],
291 | "tags": {
292 | "[concat('hidden-link:', resourceGroup().id, '/providers/Microsoft.Web/sites/', parameters('siteName'))]": "Resource",
293 | "displayName": "ForbiddenRequestsAlertRule"
294 | },
295 | "properties": {
296 | "name": "[concat('ForbiddenRequests ', parameters('siteName'))]",
297 | "description": "[concat(parameters('siteName'), ' has some requests that are forbidden, status code 403.')]",
298 | "isEnabled": false,
299 | "condition": {
300 | "odata.type": "Microsoft.Azure.Management.Insights.Models.ThresholdRuleCondition",
301 | "dataSource": {
302 | "odata.type": "Microsoft.Azure.Management.Insights.Models.RuleMetricDataSource",
303 | "resourceUri": "[concat(resourceGroup().id, '/providers/Microsoft.Web/sites/', parameters('siteName'))]",
304 | "metricName": "Http403"
305 | },
306 | "operator": "GreaterThan",
307 | "threshold": 0,
308 | "windowSize": "PT5M"
309 | },
310 | "action": {
311 | "odata.type": "Microsoft.Azure.Management.Insights.Models.RuleEmailAction",
312 | "sendToServiceOwners": true,
313 | "customEmails": []
314 | }
315 | }
316 | },
317 | {
318 | "apiVersion": "2014-04-01",
319 | "name": "[concat('CPUHigh ', parameters('hostingPlanName'))]",
320 | "type": "Microsoft.Insights/alertrules",
321 | "location": "[parameters('siteLocation')]",
322 | "dependsOn": [
323 | "[concat('Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]"
324 | ],
325 | "tags": {
326 | "[concat('hidden-link:', resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]": "Resource",
327 | "displayName": "CPUHighAlertRule"
328 | },
329 | "properties": {
330 | "name": "[concat('CPUHigh ', parameters('hostingPlanName'))]",
331 | "description": "[concat('The average CPU is high across all the instances of ', parameters('hostingPlanName'))]",
332 | "isEnabled": false,
333 | "condition": {
334 | "odata.type": "Microsoft.Azure.Management.Insights.Models.ThresholdRuleCondition",
335 | "dataSource": {
336 | "odata.type": "Microsoft.Azure.Management.Insights.Models.RuleMetricDataSource",
337 | "resourceUri": "[concat(resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]",
338 | "metricName": "CpuPercentage"
339 | },
340 | "operator": "GreaterThan",
341 | "threshold": 90,
342 | "windowSize": "PT15M"
343 | },
344 | "action": {
345 | "odata.type": "Microsoft.Azure.Management.Insights.Models.RuleEmailAction",
346 | "sendToServiceOwners": true,
347 | "customEmails": []
348 | }
349 | }
350 | },
351 | {
352 | "apiVersion": "2014-04-01",
353 | "name": "[concat('LongHttpQueue ', parameters('hostingPlanName'))]",
354 | "type": "Microsoft.Insights/alertrules",
355 | "location": "[parameters('siteLocation')]",
356 | "dependsOn": [
357 | "[concat('Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]"
358 | ],
359 | "tags": {
360 | "[concat('hidden-link:', resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]": "Resource",
361 | "displayName": "LongHttpQueueAlertRule"
362 | },
363 | "properties": {
364 | "name": "[concat('LongHttpQueue ', parameters('hostingPlanName'))]",
365 | "description": "[concat('The HTTP queue for the instances of ', parameters('hostingPlanName'), ' has a large number of pending requests.')]",
366 | "isEnabled": false,
367 | "condition": {
368 | "odata.type": "Microsoft.Azure.Management.Insights.Models.ThresholdRuleCondition",
369 | "dataSource": {
370 | "odata.type": "Microsoft.Azure.Management.Insights.Models.RuleMetricDataSource",
371 | "resourceUri": "[concat(resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]",
372 | "metricName": "HttpQueueLength"
373 | },
374 | "operator": "GreaterThan",
375 | "threshold": 100.0,
376 | "windowSize": "PT5M"
377 | },
378 | "action": {
379 | "odata.type": "Microsoft.Azure.Management.Insights.Models.RuleEmailAction",
380 | "sendToServiceOwners": true,
381 | "customEmails": []
382 | }
383 | }
384 | },
385 | {
386 | "apiVersion": "2014-04-01",
387 | "name": "[parameters('siteName')]",
388 | "type": "Microsoft.Insights/components",
389 | "location": "[parameters('siteLocation')]",
390 | "dependsOn": [
391 | "[concat('Microsoft.Web/sites/', parameters('siteName'))]"
392 | ],
393 | "tags": {
394 | "[concat('hidden-link:', resourceGroup().id, '/providers/Microsoft.Web/sites/', parameters('siteName'))]": "Resource",
395 | "displayName": "AppInsightsComponent"
396 | },
397 | "properties": {
398 | "applicationId": "[parameters('siteName')]"
399 | }
400 | },
401 | {
402 | "name": "[parameters('redisCacheName')]",
403 | "type": "Microsoft.Cache/Redis",
404 | "location": "[parameters('redisCacheLocation')]",
405 | "apiVersion": "2014-04-01-preview",
406 | "dependsOn": [ ],
407 | "tags": {
408 | "displayName": "RedisCache"
409 | },
410 | "properties": {
411 | "sku": {
412 | "name": "[parameters('redisCacheSKUName')]",
413 | "family": "[parameters('redisCacheSKUFamily')]",
414 | "capacity": "[parameters('redisCacheSKUCapacity')]"
415 | },
416 | "redisVersion": "[parameters('redisCacheVersion')]"
417 | }
418 | },
419 | {
420 | "name": "[parameters('sqlServerName')]",
421 | "type": "Microsoft.Sql/servers",
422 | "location": "[parameters('sqlServerLocation')]",
423 | "apiVersion": "2014-04-01-preview",
424 | "dependsOn": [ ],
425 | "tags": {
426 | "displayName": "sqlServer"
427 | },
428 | "properties": {
429 | "administratorLogin": "[parameters('sqlServerAdminLogin')]",
430 | "administratorLoginPassword": "[parameters('sqlServerAdminLoginPassword')]"
431 | },
432 | "resources": [
433 | {
434 | "name": "AllowAllWindowsAzureIps",
435 | "type": "firewallrules",
436 | "location": "[parameters('sqlServerLocation')]",
437 | "apiVersion": "2014-04-01-preview",
438 | "dependsOn": [
439 | "[concat('Microsoft.Sql/servers/', parameters('sqlServerName'))]"
440 | ],
441 | "properties": {
442 | "startIpAddress": "0.0.0.0",
443 | "endIpAddress": "255.255.255.255"
444 | }
445 | },
446 | {
447 | "name": "[parameters('sqlDatabaseName')]",
448 | "type": "databases",
449 | "location": "[parameters('sqlServerLocation')]",
450 | "apiVersion": "2014-04-01-preview",
451 | "dependsOn": [
452 | "[parameters('sqlServerName')]"
453 | ],
454 | "tags": {
455 | "displayName": "sqlDatabase"
456 | },
457 | "properties": {
458 | "collation": "[parameters('sqlDatabaseCollation')]",
459 | "edition": "[parameters('sqlDatabaseEdition')]",
460 | "maxSizeBytes": "1073741824"
461 | }
462 | }
463 | ]
464 | },
465 | {
466 | "apiVersion": "2015-02-28",
467 | "name": "[parameters('azureSearchName')]",
468 | "type": "Microsoft.Search/searchServices",
469 | "location": "[parameters('azureSearchLocation')]",
470 | "properties": {
471 | "sku": {
472 | "name": "[parameters('azureSearchSku')]"
473 | },
474 | "replicaCount": "[parameters('azureSearchReplicaCount')]",
475 | "partitionCount": "[parameters('azureSearchPartitionCount')]"
476 | }
477 | }
478 | ]
479 | }
--------------------------------------------------------------------------------
/Scripts/Templates/Default.params.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "siteName": {
6 | "value": ""
7 | },
8 | "hostingPlanName": {
9 | "value": ""
10 | },
11 | "siteLocation": {
12 | "value": "West Europe"
13 | },
14 | "sku": {
15 | "value": "Basic"
16 | },
17 | "workerSize": {
18 | "value": "0"
19 | },
20 | "instancesCount": {
21 | "value": 2
22 | },
23 | "sqlServerName": {
24 | "value": ""
25 | },
26 | "sqlDatabaseName": {
27 | "value": ""
28 | },
29 | "sqlServerLocation": {
30 | "value": "West Europe"
31 | },
32 | "sqlServerAdminLogin": {
33 | "value": ""
34 | },
35 | "sqlServerAdminLoginPassword": {
36 | "value": ""
37 | },
38 | "redisCacheName": {
39 | "value": ""
40 | },
41 | "redisCacheLocation": {
42 | "value": "West Europe"
43 | },
44 | "redisCacheSKUName": {
45 | "value": "Standard"
46 | },
47 | "redisCacheSKUCapacity": {
48 | "value": 0
49 | },
50 | "azureSearchName": {
51 | "value": ""
52 | },
53 | "azureSearchLocation": {
54 | "value": "West Europe"
55 | },
56 | "azureSearchSku": {
57 | "value": "standard"
58 | },
59 | "azureSearchReplicaCount": {
60 | "value": 1
61 | },
62 | "azureSearchPartitionCount": {
63 | "value": 1
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/Scripts/UpdateAzureCloudConfigs.ps1:
--------------------------------------------------------------------------------
1 | function UpdateAzureSubscriptionData($currentStorageAccount, $cloudServiceName, $storageServiceName, $location)
2 | {
3 | $azureSubscriptionDataConfig = Resolve-Path "$PSScriptRoot\$($config.files.azureSubscriptionDataConfig)"
4 | Write-Host "Azure subscription data config is: $azureSubscriptionDataConfig"
5 |
6 | Set-ItemProperty $azureSubscriptionDataConfig -name IsReadOnly -value $false
7 | [Xml]$sdXml = Get-Content $azureSubscriptionDataConfig
8 |
9 | #update Current storage account
10 | $sdXml.AzureSubscriptionData.CurrentStorageAccount = $currentStorageAccount
11 |
12 | #update could service data
13 | Foreach ($cloudService in $sdXml.AzureSubscriptionData.CloudService)
14 | {
15 | $cloudService.Name = $cloudServiceName
16 | $cloudService.Location = $location
17 | }
18 |
19 | #update storage service data
20 | Foreach ($storageService in $sdXml.AzureSubscriptionData.StorageService)
21 | {
22 | $storageService.Name = $storageServiceName
23 | }
24 |
25 | $sdXml.Save($azureSubscriptionDataConfig)
26 | }
27 |
28 | function UpdateServiceConfigurationCloudData($AccountName, $AccountKey)
29 | {
30 | $cloudConfig = Resolve-Path "$PSScriptRoot\$($config.files.cloudConfig)"
31 | Write-Host "Cloud config path is: $cloudConfig"
32 |
33 | Set-ItemProperty $cloudConfig -name IsReadOnly -value $false
34 | [Xml]$cscfgXml = Get-Content $cloudConfig
35 | $connectionStringValue = [string]::Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}", $AccountName, $AccountKey)
36 |
37 | $settingNode = $cscfgXml.ServiceConfiguration.Role.ConfigurationSettings.Setting | where {$_.name -like 'Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString'}
38 | $settingNode.Value = $connectionStringValue
39 |
40 | $cscfgXml.Save($cloudConfig)
41 | }
42 |
43 | function UpdateInstancesCount($count)
44 | {
45 | $cloudConfig = Resolve-Path "$PSScriptRoot\$($config.files.cloudConfig)"
46 | Write-Host "Cloud config path is: $cloudConfig"
47 |
48 | Set-ItemProperty $cloudConfig -name IsReadOnly -value $false
49 | [Xml]$cscfgXml = Get-Content $cloudConfig
50 | $instancesNode = $cscfgXml.ServiceConfiguration.Role.Instances;
51 | $instancesNode.count = $count
52 | $cscfgXml.Save($cloudConfig)
53 | }
54 |
55 | # Example: UpdateVMSize -ServiceDefinitionPath "C:\Temp\Tools\AzureDeployment\CloudConfigs\ServiceDefinition.csdef" -VMSize "big"
56 | function UpdateVMSize
57 | {
58 | Param(
59 | [string]$ServiceDefinitionPath,
60 | [string]$VMSize
61 | )
62 |
63 | Set-ItemProperty $ServiceDefinitionPath -name IsReadOnly -value $false
64 | if ($ServiceDefinitionPath -eq $null)
65 | {
66 | Throw "Path to xml file is not provided."
67 | }
68 |
69 | if ($VMSize -eq $null)
70 | {
71 | Throw "VMSize is not provided as a parameter."
72 | }
73 |
74 | [Xml]$XMLfile = Get-Content $ServiceDefinitionPath
75 | $XMLFile.ServiceDefinition.WebRole.vmsize = $VMSize
76 | $XMLFile.save($ServiceDefinitionPath)
77 | }
78 |
79 | # Example: UpdateVMModules -ServiceDefinitionPath "C:\Temp\Tools\AzureDeployment\CloudConfigs\ServiceDefinition.csdef" -Modules @("RemoteAccess", "RemoteForwarder")
80 | function UpdateVMModules
81 | {
82 | Param(
83 | [string]$ServiceDefinitionPath,
84 | [array]$Modules
85 | )
86 |
87 | if ($ServiceDefinitionPath -eq $null)
88 | {
89 | Throw "Path to xml file is not provided."
90 | }
91 |
92 | if ($Modules -eq $null)
93 | {
94 | Throw "No modules were provided."
95 | }
96 |
97 | Set-ItemProperty $ServiceDefinitionPath -name IsReadOnly -value $false
98 | [Xml]$XMLfile = Get-Content $ServiceDefinitionPath
99 | $xdns = $XMLfile.DocumentElement.NamespaceURI
100 | Foreach ($module in $Modules)
101 | {
102 | if(($XMLFile.ServiceDefinition.WebRole.Imports.Import | where {$_.moduleName -like $module}) -eq $null){
103 | $newImport = $XMLfile.CreateElement("Import", $xdns)
104 | $XMLFile.ServiceDefinition.WebRole.Imports.AppendChild($newImport)
105 | $newImport.SetAttribute("moduleName", $module)
106 | }
107 | }
108 |
109 | $XMLFile.save($ServiceDefinitionPath)
110 | }
111 |
112 | function DeleteVMModules
113 | {
114 | Param(
115 | [Parameter(Mandatory=$true)]
116 | [string]$ServiceDefinitionPath,
117 | [Parameter(Mandatory=$true)]
118 | [array]$Modules
119 | )
120 |
121 | Set-ItemProperty $ServiceDefinitionPath -name IsReadOnly -value $false
122 | [Xml]$XMLfile = Get-Content $ServiceDefinitionPath
123 | $nsmgr = New-Object Xml.XmlNamespaceManager $XMLfile.NameTable
124 | $nsmgr.AddNamespace("ns", $XMLfile.DocumentElement.NamespaceURI)
125 | foreach ($module in $Modules)
126 | {
127 | $moduleNode = $XMLfile.SelectSingleNode("//ns:ServiceDefinition/ns:WebRole/ns:Imports/ns:Import[@moduleName='$module']", $nsmgr)
128 | if($moduleNode -ne $null) {
129 | $moduleNode.ParentNode.RemoveChild($moduleNode)
130 | }
131 | }
132 |
133 | $XMLFile.save($ServiceDefinitionPath)
134 | }
135 |
136 | function UpdateSQLAzureServerInfoData($rootDatabase, $targetDatabase)
137 | {
138 | $azureSqlServerInforFilePath = Resolve-Path "$PSScriptRoot\$($config.files.azureSqlServerInforFilePath)"
139 | Write-Host "Sql Server Info file Path is: $azureSqlServerInforFilePath"
140 |
141 | Set-ItemProperty $azureSqlServerInforFilePath -name IsReadOnly -value $false
142 | [Xml]$sdInfoXml = Get-Content $azureSqlServerInforFilePath
143 |
144 | $sdInfoXml.ServerInfo.ServerInstance = $sqlConfig.server
145 | $sdInfoXml.ServerInfo.Login = $sqlConfig.user
146 | $sdInfoXml.ServerInfo.Password = $sqlConfig.password
147 | $sdInfoXml.ServerInfo.RootDatabase = $rootDatabase
148 | $sdInfoXml.ServerInfo.TargetDatabase = $targetDatabase
149 |
150 | $sdInfoXml.Save($azureSqlServerInforFilePath)
151 | }
152 |
153 | function GenerateRemoteDesktopRequiredSettingsNodes($serviceConfigurationPath)
154 | {
155 | Set-ItemProperty $serviceConfigurationPath -name IsReadOnly -value $false
156 | [Xml]$cscfgXml = Get-Content $serviceConfigurationPath
157 |
158 | foreach($setting in $config.remoteAccessSettings)
159 | {
160 | $settingNode = $cscfgXml.ServiceConfiguration.Role.ConfigurationSettings.Setting | where {$_.name -like $setting.name}
161 | if($settingNode -ne $null){
162 | $settingNode.Value = $setting.value;
163 | }else{
164 | $configSettings = $cscfgXml.ServiceConfiguration.Role.ConfigurationSettings;
165 | $xdNS = $cscfgXml.DocumentElement.NamespaceURI
166 | $elem = $cscfgXml.CreateElement('Setting', $xdNS)
167 | $elem.SetAttribute('name',$setting.name)
168 | $elem.SetAttribute('value',$setting.value)
169 | $configSettings.AppendChild($elem);
170 | }
171 | }
172 |
173 | $cscfgXml.Save($serviceConfigurationPath)
174 | }
175 |
176 | function RemoveRemoteDesktopRequiredSettingsNodes($serviceConfigurationPath)
177 | {
178 | Set-ItemProperty $serviceConfigurationPath -name IsReadOnly -value $false
179 | [Xml]$cscfgXml = Get-Content $serviceConfigurationPath
180 | $nsmgr = New-Object Xml.XmlNamespaceManager $cscfgXml.NameTable
181 | $nsmgr.AddNamespace("ns", $cscfgXml.DocumentElement.NamespaceURI)
182 |
183 | foreach($setting in $config.remoteAccessSettings)
184 | {
185 | $settingNode = $cscfgXml.SelectSingleNode("//ns:ServiceConfiguration/ns:Role/ns:ConfigurationSettings/ns:Setting[@name='$($setting.name)']", $nsmgr)
186 | if($settingNode -ne $null) {
187 | $settingNode.ParentNode.RemoveChild($settingNode)
188 | }
189 | }
190 |
191 | $cscfgXml.Save($serviceConfigurationPath)
192 | }
193 |
194 | function AddCertificatesNode
195 | {
196 | $cloudConfig = Resolve-Path "$PSScriptRoot\$($config.files.cloudConfig)"
197 | Write-Host "Cloud config path is: $cloudConfig"
198 |
199 | Set-ItemProperty $cloudConfig -name IsReadOnly -value $false
200 | [Xml]$cscfgXml = Get-Content $cloudConfig
201 |
202 | $roleElement = $cscfgXml.ServiceConfiguration.Role
203 | $xdNS = $cscfgXml.DocumentElement.NamespaceURI
204 | $certificateElement = $cscfgXml.ServiceConfiguration.Role.Certificates
205 | if($certificateElement -eq $null){
206 | $certificateElement = $cscfgXml.CreateElement('Certificates', $xdNS)
207 | $roleElement.AppendChild($certificateElement);
208 | }
209 | $elem = $cscfgXml.ServiceConfiguration.Role.Certificates.Certificate | where {$_.name -like $config.certificate.name}
210 | if($elem -eq $null){
211 | $elem = $cscfgXml.CreateElement('Certificate', $xdNS)
212 | $certificateElement.AppendChild($elem);
213 | }
214 | $elem.SetAttribute('name', $config.certificate.name)
215 | $elem.SetAttribute('thumbprint', $config.certificate.thumbprint)
216 | $elem.SetAttribute('thumbprintAlgorithm', $config.certificate.thumbprintAlgorithm)
217 |
218 | $cscfgXml.Save($cloudConfig)
219 | }
220 |
221 | function DeleteCertificatesNode
222 | {
223 | $cloudConfig = Resolve-Path "$PSScriptRoot\$($config.files.cloudConfig)"
224 | Write-Host "Cloud config path is: $cloudConfig"
225 |
226 | Set-ItemProperty $cloudConfig -name IsReadOnly -value $false
227 | [Xml]$cscfgXml = Get-Content $cloudConfig
228 | $nsmgr = New-Object Xml.XmlNamespaceManager $cscfgXml.NameTable
229 | $nsmgr.AddNamespace("ns", $cscfgXml.DocumentElement.NamespaceURI)
230 | $certificatesNode = $cscfgXml.SelectSingleNode("//ns:ServiceConfiguration/ns:Role/ns:Certificates", $nsmgr)
231 | if($certificatesNode -ne $null) {
232 | $certificatesNode.ParentNode.RemoveChild($certificatesNode)
233 | }
234 | $cscfgXml.Save($cloudConfig)
235 | }
236 |
237 | function ConfigureRemoteDesktop
238 | {
239 | Param(
240 | [Parameter(Mandatory=$true)]
241 | [string]$EnableRemoteDesktopAccess
242 | )
243 |
244 | $cloudConfig = Resolve-Path "$PSScriptRoot\$($config.files.cloudConfig)"
245 | $serviceDefinition = Resolve-Path "$PSScriptRoot\$($config.files.serviceDefinition)"
246 | Write-Host "Cloud config path is: $cloudConfig"
247 | Write-Host "Service Definition Path is: $serviceDefinition"
248 |
249 | Set-ItemProperty $cloudConfig -name IsReadOnly -value $false
250 | [Xml]$cscfgXml = Get-Content $cloudConfig
251 | if($EnableRemoteDesktopAccess -eq "true")
252 | {
253 | UpdateVMModules -ServiceDefinitionPath $serviceDefinition -Modules @("RemoteAccess", "RemoteForwarder")
254 | GenerateRemoteDesktopRequiredSettingsNodes $cloudConfig
255 | } else {
256 | DeleteVMModules -ServiceDefinitionPath $serviceDefinition -Modules @("RemoteAccess", "RemoteForwarder")
257 | RemoveRemoteDesktopRequiredSettingsNodes $cloudConfig
258 | }
259 | }
260 |
261 | function ConfigureSsl
262 | {
263 | Param(
264 | [Parameter(Mandatory=$true)]
265 | [string]$EnableSsl
266 | )
267 | $serviceDefinition = Resolve-Path "$PSScriptRoot\$($config.files.serviceDefinition)"
268 | Write-Host "Service Definition Path is: $serviceDefinition"
269 |
270 | Set-ItemProperty $serviceDefinition -name IsReadOnly -value $false
271 | [Xml]$XMLfile = Get-Content $serviceDefinition
272 | $xdns = $XMLfile.DocumentElement.NamespaceURI
273 |
274 | if($EnableSsl -eq "true") {
275 | if(($XMLFile.ServiceDefinition.WebRole.Sites.Site.Bindings.Binding | where {$_.name -like $config.azure.sslEndpointName}) -eq $null){
276 | $sslBinding = $XMLfile.CreateElement("Binding", $xdns)
277 | $XMLFile.ServiceDefinition.WebRole.Sites.Site.Bindings.AppendChild($sslBinding)
278 | $sslBinding.SetAttribute("name", $config.azure.sslEndpointName)
279 | $sslBinding.SetAttribute("endpointName", $config.azure.sslEndpointName)
280 | }
281 | if(($XMLFile.ServiceDefinition.WebRole.Endpoints.InputEndpoint | where {$_.name -like $config.azure.sslEndpointName}) -eq $null){
282 | $sslEndpoint = $XMLfile.CreateElement("InputEndpoint", $xdns)
283 | $XMLFile.ServiceDefinition.WebRole.Endpoints.AppendChild($sslEndpoint)
284 | $sslEndpoint.SetAttribute("name", $config.azure.sslEndpointName)
285 | $sslEndpoint.SetAttribute("protocol", "https")
286 | $sslEndpoint.SetAttribute("port", "443")
287 | $sslEndpoint.SetAttribute("certificate", $config.certificate.name)
288 | }
289 | } else {
290 | $nsmgr = New-Object Xml.XmlNamespaceManager $XMLfile.NameTable
291 | $nsmgr.AddNamespace("ns", $xdns)
292 | $bindingNode = $XMLFile.SelectSingleNode("//ns:ServiceDefinition/ns:WebRole/ns:Sites/ns:Site/ns:Bindings/ns:Binding[@name='$SslEndpointName']", $nsmgr)
293 | if($bindingNode -ne $null) {
294 | $bindingNode.ParentNode.RemoveChild($bindingNode)
295 | }
296 | $endpointNode = $XMLFile.SelectSingleNode("//ns:ServiceDefinition/ns:WebRole/ns:Endpoints/ns:InputEndpoint[@name='$SslEndpointName']", $nsmgr)
297 | if($endpointNode -ne $null) {
298 | $endpointNode.ParentNode.RemoveChild($endpointNode)
299 | }
300 | }
301 |
302 | $XMLFile.save($serviceDefinition)
303 | }
--------------------------------------------------------------------------------
/Scripts/UpdateSitefinityConfigs.ps1:
--------------------------------------------------------------------------------
1 | function UpdateSitefinityWebConfig($websiteRootDirectory)
2 | {
3 | $webConfig = Join-Path $websiteRootDirectory "\web.config"
4 | Set-ItemProperty $webConfig -name IsReadOnly -value $false
5 | $doc = New-Object System.Xml.XmlDocument
6 | $doc.Load($webConfig)
7 |
8 | if($doc.SelectSingleNode("//configuration/configSections/sectionGroup[@name='telerik']") -eq $null)
9 | {
10 | $configSectionsNode = $doc.SelectSingleNode("//configuration/configSections")
11 | $sectionGroupNode = $doc.CreateElement("sectionGroup")
12 | $sectionGroupNode.SetAttribute("name","telerik")
13 | $configSectionsNode.AppendChild($sectionGroupNode)
14 | $sectionNode = $doc.CreateElement("section")
15 | $sectionNode.SetAttribute("name","sitefinity")
16 | $sectionNode.SetAttribute("type","Telerik.Sitefinity.Configuration.SectionHandler, Telerik.Sitefinity")
17 | $sectionNode.SetAttribute("requirePermission","false")
18 | $sectionGroupNode.AppendChild($sectionNode)
19 | }
20 |
21 | if($doc.SelectSingleNode("//configuration/telerik") -eq $null)
22 | {
23 | $configurationNode = $doc.SelectSingleNode("//configuration")
24 | $telerikNode = $doc.CreateElement("telerik")
25 | $sitefinityNode = $doc.CreateElement("sitefinity")
26 | $testingNode = $doc.CreateElement("testing")
27 | $testingNode.SetAttribute("enabled", "true")
28 | $testingNode.SetAttribute("loadBalancingSyncLoggingEnabled", "false") #disable nlb sync logging becase it is peformance overhead.
29 | $environmentNode = $doc.CreateElement("environment")
30 | $environmentNode.SetAttribute("platform", "WindowsAzure")
31 | $sitefinityConfigNode = $doc.CreateElement("sitefinityConfig")
32 | $sitefinityConfigNode.SetAttribute("storageMode", "Database")
33 | $sitefinityNode.AppendChild($testingNode)
34 | $sitefinityNode.AppendChild($environmentNode)
35 | $sitefinityNode.AppendChild($sitefinityConfigNode)
36 | $telerikNode.AppendChild($sitefinityNode)
37 | $configurationNode.AppendChild($telerikNode)
38 | }
39 |
40 | $doc.Save($webConfig)
41 | }
42 |
43 | function UpdateSitefinityDataConfig($websiteRootDirectory, $azureServer, $user, $password, $database)
44 | {
45 | $dataConfig = Join-Path $websiteRootDirectory "\App_Data\Sitefinity\Configuration\DataConfig.config"
46 | Set-ItemProperty $dataConfig -name IsReadOnly -value $false
47 | $doc = New-Object System.Xml.XmlDocument
48 | $doc.Load($dataConfig)
49 | $connectionString = "Server=$azureServer;User ID=$user;Password=$password;Database=$database; Trusted_Connection=False;Encrypt=True"
50 | $connectionStringAttr = $doc.SelectSingleNode("//dataConfig/connectionStrings/add/@connectionString")
51 | $connectionStringAttr.Value = $connectionString
52 |
53 | $dbTypeAttr = $doc.SelectSingleNode("//dataConfig/connectionStrings/add/@dbType")
54 | if($dbTypeAttr)
55 | {
56 | $dbTypeAttr.Value = "SqlAzure"
57 | }
58 | else
59 | {
60 | $connectionStringNode = $doc.SelectSingleNode("//dataConfig/connectionStrings/add")
61 | $dbTypeAttribute = $doc.CreateAttribute("dbType")
62 | $dbTypeAttribute.Value = "SqlAzure"
63 | $connectionStringNode.Attributes.Append($dbTypeAttribute)
64 | }
65 |
66 | $doc.Save($dataConfig)
67 | }
68 |
69 | function EnableAzureTraceListener($websiteRootDirectory)
70 | {
71 | $webConfig = Join-Path $websiteRootDirectory "\web.config"
72 | Set-ItemProperty $webConfig -name IsReadOnly -value $false
73 | $doc = New-Object System.Xml.XmlDocument
74 | $doc.Load($webConfig)
75 |
76 |
77 | if($doc.SelectSingleNode("//configuration/system.diagnostics/trace/listeners/add[@name='AzureDiagnostics']") -eq $null)
78 | {
79 | $traceListenersNode = $doc.SelectSingleNode("//configuration/system.diagnostics/trace/listeners")
80 | if($traceListenersNode -eq $null)
81 | {
82 | $traceNode = $doc.SelectSingleNode("//configuration/system.diagnostics/trace")
83 | if($traceNode -eq $null)
84 | {
85 | $diagnosticsNode = $doc.SelectSingleNode("//configuration/system.diagnostics")
86 | if($diagnosticsNode -eq $null)
87 | {
88 | $diagnosticsNode = $doc.CreateElement("system.diagnostics")
89 | $doc.SelectSingleNode("//configuration").AppendChild($diagnosticsNode)
90 | }
91 | $traceNode = $doc.CreateElement("trace")
92 | $diagnosticsNode.AppendChild($traceNode)
93 | }
94 | $traceListenersNode = $doc.CreateElement("listeners")
95 | $traceNode.AppendChild($traceListenersNode)
96 | }
97 | $azureDiagnosticsNode = $doc.CreateElement("add")
98 | $azureDiagnosticsNode.SetAttribute("type", "Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=2.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")
99 | $azureDiagnosticsNode.SetAttribute("name", "AzureDiagnostics")
100 | $filterNode = $doc.CreateElement("filter")
101 | $filterNode.SetAttribute("type", "")
102 | $azureDiagnosticsNode.AppendChild($filterNode)
103 | $traceListenersNode.AppendChild($azureDiagnosticsNode)
104 | $doc.Save($webConfig)
105 | }
106 | }
107 |
108 | function ConfigureAzureSearchService($searchConfig, $azureServiceAdminKey, $azureSearchServiceName)
109 | {
110 | Set-ItemProperty $searchConfig -name IsReadOnly -value $false
111 | $doc = New-Object System.Xml.XmlDocument
112 | $doc.Load($searchConfig)
113 | $azureSearchServiceNode = $doc.SelectSingleNode("//searchConfig/searchServices/add")
114 | $azureSearchServiceNode.Attributes['azureServiceAdminKey'].Value = $azureServiceAdminKey
115 | $azureSearchServiceNode.Attributes['azureSearchServiceName'].Value = $azureSearchServiceName
116 | $doc.Save($searchConfig)
117 | }
--------------------------------------------------------------------------------