1- # Requires -Version 3.0
2-
3- Param (
4- [string ] [Parameter (Mandatory = $true )] $ResourceGroupLocation ,
5- [string ] $ResourceGroupName = ' AZ-400-Crash-Course' ,
6- [switch ] $UploadArtifacts ,
7- [string ] $StorageAccountName ,
8- [string ] $StorageContainerName = $ResourceGroupName.ToLowerInvariant () + ' -stageartifacts' ,
9- [string ] $TemplateFile = ' azuredeploy.json' ,
10- [string ] $TemplateParametersFile = ' azuredeploy.parameters.json' ,
11- [string ] $ArtifactStagingDirectory = ' .' ,
12- [string ] $DSCSourceFolder = ' DSC' ,
13- [switch ] $ValidateOnly
14- )
15-
16- try {
17- [Microsoft.Azure.Common.Authentication.AzureSession ]::ClientFactory.AddUserAgent(" VSAzureTools-$UI $ ( $host.name ) " .replace(' ' , ' _' ), ' 3.0.0' )
18- } catch { }
19-
20- $ErrorActionPreference = ' Stop'
21- Set-StrictMode - Version 3
22-
23- function Format-ValidationOutput {
24- param ($ValidationOutput , [int ] $Depth = 0 )
25- Set-StrictMode - Off
26- return @ ($ValidationOutput | Where-Object { $_ -ne $null } | ForEach-Object { @ (' ' * $Depth + ' : ' + $_.Message ) + @ (Format-ValidationOutput @ ($_.Details ) ($Depth + 1 )) })
27- }
28-
29- $OptionalParameters = New-Object - TypeName Hashtable
30- $TemplateFile = [System.IO.Path ]::GetFullPath([System.IO.Path ]::Combine($PSScriptRoot , $TemplateFile ))
31- $TemplateParametersFile = [System.IO.Path ]::GetFullPath([System.IO.Path ]::Combine($PSScriptRoot , $TemplateParametersFile ))
32-
33- if ($UploadArtifacts ) {
34- # Convert relative paths to absolute paths if needed
35- $ArtifactStagingDirectory = [System.IO.Path ]::GetFullPath([System.IO.Path ]::Combine($PSScriptRoot , $ArtifactStagingDirectory ))
36- $DSCSourceFolder = [System.IO.Path ]::GetFullPath([System.IO.Path ]::Combine($PSScriptRoot , $DSCSourceFolder ))
37-
38- # Parse the parameter file and update the values of artifacts location and artifacts location SAS token if they are present
39- $JsonParameters = Get-Content $TemplateParametersFile - Raw | ConvertFrom-Json
40- if (($JsonParameters | Get-Member - Type NoteProperty ' parameters' ) -ne $null ) {
41- $JsonParameters = $JsonParameters.parameters
42- }
43- $ArtifactsLocationName = ' _artifactsLocation'
44- $ArtifactsLocationSasTokenName = ' _artifactsLocationSasToken'
45- $OptionalParameters [$ArtifactsLocationName ] = $JsonParameters | Select - Expand $ArtifactsLocationName - ErrorAction Ignore | Select - Expand ' value' - ErrorAction Ignore
46- $OptionalParameters [$ArtifactsLocationSasTokenName ] = $JsonParameters | Select - Expand $ArtifactsLocationSasTokenName - ErrorAction Ignore | Select - Expand ' value' - ErrorAction Ignore
47-
48- # Create DSC configuration archive
49- if (Test-Path $DSCSourceFolder ) {
50- $DSCSourceFilePaths = @ (Get-ChildItem $DSCSourceFolder - File - Filter ' *.ps1' | ForEach-Object - Process {$_.FullName })
51- foreach ($DSCSourceFilePath in $DSCSourceFilePaths ) {
52- $DSCArchiveFilePath = $DSCSourceFilePath.Substring (0 , $DSCSourceFilePath.Length - 4 ) + ' .zip'
53- Publish-AzureRmVMDscConfiguration $DSCSourceFilePath - OutputArchivePath $DSCArchiveFilePath - Force - Verbose
54- }
55- }
56-
57- # Create a storage account name if none was provided
58- if ($StorageAccountName -eq ' ' ) {
59- $StorageAccountName = ' stage' + ((Get-AzureRmContext ).Subscription.SubscriptionId).Replace(' -' , ' ' ).substring(0 , 19 )
60- }
61-
62- $StorageAccount = (Get-AzureRmStorageAccount | Where-Object {$_.StorageAccountName -eq $StorageAccountName })
63-
64- # Create the storage account if it doesn't already exist
65- if ($StorageAccount -eq $null ) {
66- $StorageResourceGroupName = ' ARM_Deploy_Staging'
67- New-AzureRmResourceGroup - Location " $ResourceGroupLocation " - Name $StorageResourceGroupName - Force
68- $StorageAccount = New-AzureRmStorageAccount - StorageAccountName $StorageAccountName - Type ' Standard_LRS' - ResourceGroupName $StorageResourceGroupName - Location " $ResourceGroupLocation "
69- }
70-
71- # Generate the value for artifacts location if it is not provided in the parameter file
72- if ($OptionalParameters [$ArtifactsLocationName ] -eq $null ) {
73- $OptionalParameters [$ArtifactsLocationName ] = $StorageAccount.Context.BlobEndPoint + $StorageContainerName + ' /'
74- }
75-
76- # Copy files from the local storage staging location to the storage account container
77- New-AzureStorageContainer - Name $StorageContainerName - Context $StorageAccount.Context - ErrorAction SilentlyContinue * > & 1
78-
79- $ArtifactFilePaths = Get-ChildItem $ArtifactStagingDirectory - Recurse - File | ForEach-Object - Process {$_.FullName }
80- foreach ($SourcePath in $ArtifactFilePaths ) {
81- Set-AzureStorageBlobContent - File $SourcePath - Blob $SourcePath.Substring ($ArtifactStagingDirectory.length + 1 ) `
82- - Container $StorageContainerName - Context $StorageAccount.Context - Force
83- }
84-
85- # Generate a 4 hour SAS token for the artifacts location if one was not provided in the parameters file
86- if ($OptionalParameters [$ArtifactsLocationSasTokenName ] -eq $null ) {
87- $OptionalParameters [$ArtifactsLocationSasTokenName ] = ConvertTo-SecureString - AsPlainText - Force `
88- (New-AzureStorageContainerSASToken - Container $StorageContainerName - Context $StorageAccount.Context - Permission r - ExpiryTime (Get-Date ).AddHours(4 ))
89- }
90- }
91-
92- # Create the resource group only when it doesn't already exist
93- if ((Get-AzureRmResourceGroup - Name $ResourceGroupName - Location $ResourceGroupLocation - Verbose - ErrorAction SilentlyContinue) -eq $null ) {
94- New-AzureRmResourceGroup - Name $ResourceGroupName - Location $ResourceGroupLocation - Verbose - Force - ErrorAction Stop
95- }
96-
97- if ($ValidateOnly ) {
98- $ErrorMessages = Format-ValidationOutput (Test-AzureRmResourceGroupDeployment - ResourceGroupName $ResourceGroupName `
99- - TemplateFile $TemplateFile `
100- - TemplateParameterFile $TemplateParametersFile `
101- @OptionalParameters )
102- if ($ErrorMessages ) {
103- Write-Output ' ' , ' Validation returned the following errors:' , @ ($ErrorMessages ), ' ' , ' Template is invalid.'
104- }
105- else {
106- Write-Output ' ' , ' Template is valid.'
107- }
108- }
109- else {
110- New-AzureRmResourceGroupDeployment - Name ((Get-ChildItem $TemplateFile ).BaseName + ' -' + ((Get-Date ).ToUniversalTime()).ToString(' MMdd-HHmm' )) `
111- - ResourceGroupName $ResourceGroupName `
112- - TemplateFile $TemplateFile `
113- - TemplateParameterFile $TemplateParametersFile `
114- @OptionalParameters `
115- - Force - Verbose `
116- - ErrorVariable ErrorMessages
117- if ($ErrorMessages ) {
118- Write-Output ' ' , ' Template deployment returned the following errors:' , @ (@ ($ErrorMessages ) | ForEach-Object { $_.Exception.Message.TrimEnd (" `r`n " ) })
119- }
1+ # Requires -Version 3.0
2+
3+ Param (
4+ [string ] [Parameter (Mandatory = $true )] $ResourceGroupLocation ,
5+ [string ] $ResourceGroupName = ' AZ-400-Crash-Course' ,
6+ [switch ] $UploadArtifacts ,
7+ [string ] $StorageAccountName ,
8+ [string ] $StorageContainerName = $ResourceGroupName.ToLowerInvariant () + ' -stageartifacts' ,
9+ [string ] $TemplateFile = ' azuredeploy.json' ,
10+ [string ] $TemplateParametersFile = ' azuredeploy.parameters.json' ,
11+ [string ] $ArtifactStagingDirectory = ' .' ,
12+ [string ] $DSCSourceFolder = ' DSC' ,
13+ [switch ] $ValidateOnly
14+ )
15+
16+ try {
17+ [Microsoft.Azure.Common.Authentication.AzureSession ]::ClientFactory.AddUserAgent(" VSAzureTools-$UI $ ( $host.name ) " .replace(' ' , ' _' ), ' 3.0.0' )
18+ } catch { }
19+
20+ $ErrorActionPreference = ' Stop'
21+ Set-StrictMode - Version 3
22+
23+ function Format-ValidationOutput {
24+ param ($ValidationOutput , [int ] $Depth = 0 )
25+ Set-StrictMode - Off
26+ return @ ($ValidationOutput | Where-Object { $_ -ne $null } | ForEach-Object { @ (' ' * $Depth + ' : ' + $_.Message ) + @ (Format-ValidationOutput @ ($_.Details ) ($Depth + 1 )) })
27+ }
28+
29+ $OptionalParameters = New-Object - TypeName Hashtable
30+ $TemplateFile = [System.IO.Path ]::GetFullPath([System.IO.Path ]::Combine($PSScriptRoot , $TemplateFile ))
31+ $TemplateParametersFile = [System.IO.Path ]::GetFullPath([System.IO.Path ]::Combine($PSScriptRoot , $TemplateParametersFile ))
32+
33+ if ($UploadArtifacts ) {
34+ # Convert relative paths to absolute paths if needed
35+ $ArtifactStagingDirectory = [System.IO.Path ]::GetFullPath([System.IO.Path ]::Combine($PSScriptRoot , $ArtifactStagingDirectory ))
36+ $DSCSourceFolder = [System.IO.Path ]::GetFullPath([System.IO.Path ]::Combine($PSScriptRoot , $DSCSourceFolder ))
37+
38+ # Parse the parameter file and update the values of artifacts location and artifacts location SAS token if they are present
39+ $JsonParameters = Get-Content $TemplateParametersFile - Raw | ConvertFrom-Json
40+ if (($JsonParameters | Get-Member - Type NoteProperty ' parameters' ) -ne $null ) {
41+ $JsonParameters = $JsonParameters.parameters
42+ }
43+ $ArtifactsLocationName = ' _artifactsLocation'
44+ $ArtifactsLocationSasTokenName = ' _artifactsLocationSasToken'
45+ $OptionalParameters [$ArtifactsLocationName ] = $JsonParameters | Select - Expand $ArtifactsLocationName - ErrorAction Ignore | Select - Expand ' value' - ErrorAction Ignore
46+ $OptionalParameters [$ArtifactsLocationSasTokenName ] = $JsonParameters | Select - Expand $ArtifactsLocationSasTokenName - ErrorAction Ignore | Select - Expand ' value' - ErrorAction Ignore
47+
48+ # Create DSC configuration archive
49+ if (Test-Path $DSCSourceFolder ) {
50+ $DSCSourceFilePaths = @ (Get-ChildItem $DSCSourceFolder - File - Filter ' *.ps1' | ForEach-Object - Process {$_.FullName })
51+ foreach ($DSCSourceFilePath in $DSCSourceFilePaths ) {
52+ $DSCArchiveFilePath = $DSCSourceFilePath.Substring (0 , $DSCSourceFilePath.Length - 4 ) + ' .zip'
53+ Publish-AzureRmVMDscConfiguration $DSCSourceFilePath - OutputArchivePath $DSCArchiveFilePath - Force - Verbose
54+ }
55+ }
56+
57+ # Create a storage account name if none was provided
58+ if ($StorageAccountName -eq ' ' ) {
59+ $StorageAccountName = ' stage' + ((Get-AzureRmContext ).Subscription.SubscriptionId).Replace(' -' , ' ' ).substring(0 , 19 )
60+ }
61+
62+ $StorageAccount = (Get-AzureRmStorageAccount | Where-Object {$_.StorageAccountName -eq $StorageAccountName })
63+
64+ # Create the storage account if it doesn't already exist
65+ if ($StorageAccount -eq $null ) {
66+ $StorageResourceGroupName = ' ARM_Deploy_Staging'
67+ New-AzureRmResourceGroup - Location " $ResourceGroupLocation " - Name $StorageResourceGroupName - Force
68+ $StorageAccount = New-AzureRmStorageAccount - StorageAccountName $StorageAccountName - Type ' Standard_LRS' - ResourceGroupName $StorageResourceGroupName - Location " $ResourceGroupLocation "
69+ }
70+
71+ # Generate the value for artifacts location if it is not provided in the parameter file
72+ if ($OptionalParameters [$ArtifactsLocationName ] -eq $null ) {
73+ $OptionalParameters [$ArtifactsLocationName ] = $StorageAccount.Context.BlobEndPoint + $StorageContainerName + ' /'
74+ }
75+
76+ # Copy files from the local storage staging location to the storage account container
77+ New-AzureStorageContainer - Name $StorageContainerName - Context $StorageAccount.Context - ErrorAction SilentlyContinue * > & 1
78+
79+ $ArtifactFilePaths = Get-ChildItem $ArtifactStagingDirectory - Recurse - File | ForEach-Object - Process {$_.FullName }
80+ foreach ($SourcePath in $ArtifactFilePaths ) {
81+ Set-AzureStorageBlobContent - File $SourcePath - Blob $SourcePath.Substring ($ArtifactStagingDirectory.length + 1 ) `
82+ - Container $StorageContainerName - Context $StorageAccount.Context - Force
83+ }
84+
85+ # Generate a 4 hour SAS token for the artifacts location if one was not provided in the parameters file
86+ if ($OptionalParameters [$ArtifactsLocationSasTokenName ] -eq $null ) {
87+ $OptionalParameters [$ArtifactsLocationSasTokenName ] = ConvertTo-SecureString - AsPlainText - Force `
88+ (New-AzureStorageContainerSASToken - Container $StorageContainerName - Context $StorageAccount.Context - Permission r - ExpiryTime (Get-Date ).AddHours(4 ))
89+ }
90+ }
91+
92+ # Create the resource group only when it doesn't already exist
93+ if ((Get-AzureRmResourceGroup - Name $ResourceGroupName - Location $ResourceGroupLocation - Verbose - ErrorAction SilentlyContinue) -eq $null ) {
94+ New-AzureRmResourceGroup - Name $ResourceGroupName - Location $ResourceGroupLocation - Verbose - Force - ErrorAction Stop
95+ }
96+
97+ if ($ValidateOnly ) {
98+ $ErrorMessages = Format-ValidationOutput (Test-AzureRmResourceGroupDeployment - ResourceGroupName $ResourceGroupName `
99+ - TemplateFile $TemplateFile `
100+ - TemplateParameterFile $TemplateParametersFile `
101+ @OptionalParameters )
102+ if ($ErrorMessages ) {
103+ Write-Output ' ' , ' Validation returned the following errors:' , @ ($ErrorMessages ), ' ' , ' Template is invalid.'
104+ }
105+ else {
106+ Write-Output ' ' , ' Template is valid.'
107+ }
108+ }
109+ else {
110+ New-AzureRmResourceGroupDeployment - Name ((Get-ChildItem $TemplateFile ).BaseName + ' -' + ((Get-Date ).ToUniversalTime()).ToString(' MMdd-HHmm' )) `
111+ - ResourceGroupName $ResourceGroupName `
112+ - TemplateFile $TemplateFile `
113+ - TemplateParameterFile $TemplateParametersFile `
114+ @OptionalParameters `
115+ - Force - Verbose `
116+ - ErrorVariable ErrorMessages
117+ if ($ErrorMessages ) {
118+ Write-Output ' ' , ' Template deployment returned the following errors:' , @ (@ ($ErrorMessages ) | ForEach-Object { $_.Exception.Message.TrimEnd (" `r`n " ) })
119+ }
120120}
0 commit comments