Skip to content

Instantly share code, notes, and snippets.

@udawtr
Last active January 1, 2016 10:29
Show Gist options
  • Save udawtr/8132029 to your computer and use it in GitHub Desktop.
Save udawtr/8132029 to your computer and use it in GitHub Desktop.
このPowerShellスクリプトモジュールは、WindowsAzureクラウドサービスへデプロイするための機能を提供します。ステージングが空であれば、新規デプロイを行い。そうでなければ、更新デプロイを行います。デプロイ処理中に *.cscfgファイル内の接続文字列を書き変えてプロダクションとステージングで同じ接続文字列を使うことを回避します。例えば、MyConnectionStringという名前で接続文字列を*.cscfgに定義しているとして、そこに使用するストレージアカウントがstorage1またはstorage2であるなら、自動的にプロダクションと衝突しないほうのストレージアカウントを選んで更新します。This PS Script Module provide the funct…
function Publish-AzureCloud
{
param(
[Parameter(Mandatory=$true)]
[string]
$ServiceName,
[Parameter(Mandatory=$true)]
[string]
$SubscriptionId,
[Parameter(ValueFromPipeline=$true,Mandatory=$true)]
[System.Security.Cryptography.X509Certificates.X509Certificate]
$Certificate,
[Parameter(Mandatory=$true)]
[string]
$Package,
[Parameter(Mandatory=$true)]
[string]
$Configuration,
[Parameter(Mandatory=$true)]
[string]
$Label,
[Parameter(Mandatory=$true)]
[string]
$UploadStorageName,
[string[]]
$SwapStorageAccountNames,
[string[]]
$SwapStorageConnectionStrings,
[string]
$SwapStorageConfigName
)
process
{
$servicename = $ServiceName
$sub = $SubscriptionId
$cert = $Certificate
$package = $Package
$cfg = $Configuration
$label = $Label
$storagename = $UploadStorageName
$swapaccounts = $SwapStorageAccountNames
$swapconnections = $SwapStorageConnectionStrings
$swapconf = $SwapStorageConfigName
Export-WebConfig $package
$webConfigPath = Join-Path ((pwd).Path) "Web.config"
Check-SessionState $webConfigPath
$ErrorActionPreference = "Stop"
Import-AzureSDK
Set-AzureSubscription -SubscriptionName mysub -SubscriptionId $sub -Certificate $cert -CurrentStorageAccount $storagename
Select-AzureSubscription mysub
#Get current configuration
echo "Checking the existence of the deployment $servicename (Staging) ..."
Get-AzureDeployment $servicename -Slot staging -OutVariable out -ErrorAction SilentlyContinue | Out-Null
$st = $out[0].Status
if( $st -eq $NULL )
{
echo "The deployment $servicename (Staging) is NOT existed."
echo "Checking the existence of the deployment $servicename (Production) ..."
Get-AzureDeployment $servicename -Slot production -OutVariable out2 -ErrorAction SilentlyContinue | Out-Null
$st2 = $out2[0].Status
if( $st2 -eq $NULL )
{
echo "The deployment $servicename (Production) is NOT existed."
$conf = $NULL
}
else
{
echo "The deployment $servicename (Production) is already EXISTED."
$conf = [xml]$out2[0].Configuration
}
}
else
{
echo "The deployment $servicename (Staging) is already EXISTED."
$conf = [xml]$out.Configuration
}
if( $conf -eq $NULL )
{
echo 'Donot modify storage account because we have no deployments.'
$newcfg = (Resolve-Path $cfg)
}
else
{
#Determine new connection
$accountname = Get-StorageAccountName -conf $conf -swapconf $swapconf
if( $accountname -eq $NULL )
{
echo "Failed to detect current storage account name of $SwapStorageConfigName"
exit
}
echo "Current storage account is $accountname"
$connection1 = $swapconnections[0]
$connection2 = $swapconnections[1]
$accountname1 = $swapaccounts[0]
$accountname2 = $swapaccounts[1]
if( $st -eq $NULL )
{
#in case of staging is NOT existed
if( ($conf -eq $NULL) -or ($accountname -eq $accountname2) )
{
$connection = $connection1
echo "New storage account (Staging) is $accountname1"
}
elseif($accountname -eq $accountname1 )
{
$connection = $connection2
echo "New storage account (Staging) is $accountname2"
}
else
{
echo 'Cannot detect storage accountname. failed.'
exit
}
}
else
{
#in case of staging is EXISTED
if( $accountname -eq $accountname1 )
{
$connection = $connection1
echo "New storage account (Staging) is $accountname1"
}
elseif($accountname -eq $accountname2 )
{
$connection = $connection2
echo "New storage account (Staging) is $accountname2"
}
else
{
echo 'Cannot detect storage accountname. failed.'
exit
}
}
#Modify new configuration
$newconf = [xml](Get-Content (Resolve-Path $cfg))
$ret = Set-ConnectionString -newconf $newconf -swapconf $swapconf -connection $connection
if( $ret -eq $false )
{
echo "Failed to detect $swapconf at $cfg"
exit
}
$newcfg = (Resolve-Path $cfg)
echo "Save midifed configuration file to $newcfg"
#echo $newconf.outerxml
$newconf.Save($newcfg)
}
#Check existings staging deployment
$st = $out[0].Status
if( $st -eq $NULL )
{
#NewDeploy(Deploying->Suspended)
echo "New-Deployment $servicename (Staging) Starting..."
New-AzureDeployment -Label "$label" -ServiceName $servicename -Slot staging -Package (Resolve-Path $package) -Configuration $newcfg
echo "New-Deployment $servicename (Staging) Completed."
}
else
{
#UpdateDeploy
echo "Update-Deployment $servicename (Staging) Starting..."
Set-AzureDeployment -Upgrade -label "$label" -Servicename $servicename -Slot staging -package (Resolve-Path $package) -configuration $newcfg -force
echo "Update-Deployment $servicename (Staging) Completed."
}
#Get Staging URL
Get-StagingURL $servicename
}
}
function Check-SessionState($path)
{
#Check-up Web.config
$webcfg = [xml](Get-Content $path)
$smode = $webcfg.configuration."system.web".sessionState.mode
$smode = $smode.ToLower().Trim()
if( $smode -eq "inproc" ){
echo "[Error]The session mode is InProc. This mode cause some error at multi server environment."
exit
} elseif($smode -eq ""){
echo "[Error]Fail to detect the session mode."
exit
} else {
echo "The session mode is $smode."
}
}
function Export-WebConfig($package)
{
$cspkg_path = (Resolve-Path $package).Path
$cspkg_path_zip = $cspkg_path + ".zip"
$sh = New-Object -ComObject Shell.Application
#Copy *.cspkg => *.cspkg.zip
Copy-Item -Path $cspkg_path -Destination $cspkg_path_zip
#Get *.ccsx
$cssx = $sh.NameSpace($cspkg_path_zip).Items() | Where-Object { $_.Path.EndsWith(".cssx") }
$cssx | ForEach-Object {
#ref http://technet.microsoft.com/en-us/library/ee176633.aspx
$sh.NameSpace((pwd).Path).CopyHere($_, 0x14)
#Rename *.cssx => *.cssx.zip
$cssx_path = (Resolve-Path $_.Name).Path
$cssx_path_zip = $cssx_path + ".zip"
Rename-Item -Path $cssx_path -NewName $cssx_path_zip
#Get Web.config
$webConfig = $sh.NameSpace($cssx_path_zip + "\approot").Items() | Where-Object { $_.Path.EndsWith("Web.config") }
if( $webConfig -ne $NULL )
{
#ref http://technet.microsoft.com/en-us/library/ee176633.aspx
$sh.NameSpace((pwd).Path).CopyHere($webConfig, 0x14)
}
#Remove *.cssx.zip
Remove-Item -Path $cssx_path_zip
}
#Remove *.cspkg.zip
Remove-Item -Path $cspkg_path_zip
}
function Import-AzureSDK
{
$path1 = 'C:\Program Files\Microsoft SDKs\Windows Azure\PowerShell\Azure'
$path2 = 'C:\Program Files (x86)\Microsoft SDKs\Windows Azure\PowerShell\Azure'
If( Test-Path $path1 )
{
Get-ChildItem "$path1\*.psd1" | ForEach-Object {Import-Module $_}
return
}
If( Test-Path $path2 )
{
Get-ChildItem "$path2\*.psd1" | ForEach-Object {Import-Module $_}
return
}
echo "Failed to find the path of Windows Azure PowerShell. To install, visit http://www.windowsazure.com/ja-jp/downloads/"
exit
}
function Get-StorageAccountName($conf, $swapconf)
{
foreach($role in $conf.ServiceConfiguration.Role)
{
foreach($setting in $role.ConfigurationSettings.Setting)
{
if( $setting.name -eq $swapconf)
{
$accountname = $setting.value.Split(';')[1].Split('=')[1].Trim().ToLower()
return $accountname
}
}
}
return $NULL
}
function Set-ConnectionString($newconf, $swapconf, $connection)
{
$flag = $false
foreach($role in $newconf.ServiceConfiguration.Role)
{
foreach($setting in $role.ConfigurationSettings.Setting)
{
if( $setting.name -eq $swapconf)
{
$setting.value = $connection
$flag = $true
}
}
}
return $flag
}
function Get-StagingURL($servicename)
{
echo "Get URL of the Deployment $servicename (Staging) "
Get-AzureDeployment -slot staging -servicename $servicename -outvariable out
$url = $out[0].Url
echo "New staging URL is $url"
$env:STAGINGURL=$url
$ErrorActionPreference = "SilentlyContinue"
$cli = New-Object System.Net.WebClient
$script:success = $FALSE
#Check for new url is available
:label do{
trap{
echo "Cannot reached ... "
$script:success = $FALSE
continue
}
sleep 30
$script:success = $TRUE
$cli.DownloadString($url) | Out-Null
}while( $script:success -eq $FALSE)
if( $script:success -eq $TRUE ){ echo "OK. New URL is already rechable." } else { echo "NG" }
}
Import-Module (Resolve-Path "AzureCloudPublisher.psm1")
$servicename = "my azure cloud service name"
$sub = "my azure subscription id"
$cert = Get-Item cert:\CurrentUser\My\<Thumb print of management certification>
$package = "path of *.cspkg"
$cfg= "path of *.cscfg"
$label = "label of this deploy"
$storagename = "storage-to-upload-package"
$swapaccounts = 'storage1', 'storage2'
$swapconnections =
'DefaultEndpointsProtocol=https;AccountName=storage1;AccountKey=*******',
'DefaultEndpointsProtocol=https;AccountName=storage2;AccountKey=******'
$swapconf = "MyConnectionString"
Publish-AzureCloud -ServiceName $servicename -SubscriptionId $sub -Certificate $cert -Package $package -Configuration $cfg -Label $label -UploadStorageName $storagename -SwapStorageAccountNames $swapaccounts -SwapStorageConnectionStrings $swapconnections -SwapStorageConfigName $swapconf
@udawtr
Copy link
Author

udawtr commented Feb 7, 2014

Probably the error processo of Get-AzureDeployment was changed.
If Staging or Production slot has no deployment, previously Get-AzureDeployment return just emty.
But now I get Error and this script will stop.
So I add the option -ErrorAction SilentlyContinue.

Second change is about connection string modification.
If you have more than two roles in one cloud service, previous version of this script don't update all of connection strings. Just changed first one.I fixed this problem in this version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment