1+ # Copyright (c) Microsoft Corporation. All rights reserved.
2+ # See LICENSE.txt in the project root for license information.
3+
4+ # requires -Modules AzureStack .Connect
5+
6+ <#
7+ . SYNOPSIS
8+ Contains 2 functions.
9+ Add-VMExtension: Uploads a VM extension to your Azure Stack.
10+ Remove-VMExtension: Removes an existing VM extension from your Azure Stack.
11+ #>
12+
13+
14+ Function Add-VMExtension {
15+
16+ [CmdletBinding (DefaultParameterSetName = ' VMExtensionFromLocal' )]
17+ Param (
18+ [Parameter (Mandatory = $true , ParameterSetName = ' VMExtensionFromLocal' )]
19+ [Parameter (Mandatory = $true , ParameterSetName = ' VMExtesionFromAzure' )]
20+ [ValidatePattern (“ [a-zA-Z0-9-]{3,}” )]
21+ [String ] $publisher ,
22+
23+ [Parameter (Mandatory = $true , ParameterSetName = ' VMExtensionFromLocal' )]
24+ [Parameter (Mandatory = $true , ParameterSetName = ' VMExtesionFromAzure' )]
25+ [ValidatePattern (“ \d+\.\d+\.\d+” )]
26+ [String ] $version ,
27+
28+ [Parameter (ParameterSetName = ' VMExtensionFromLocal' )]
29+ [Parameter (ParameterSetName = ' VMExtesionFromAzure' )]
30+ [String ] $type ,
31+
32+ [Parameter (Mandatory = $true , ParameterSetName = ' VMExtensionFromLocal' )]
33+ [ValidateNotNullorEmpty ()]
34+ [String ] $extensionLocalPath ,
35+
36+ [Parameter (Mandatory = $true , ParameterSetName = ' VMExtesionFromAzure' )]
37+ [ValidateNotNullorEmpty ()]
38+ [String ] $extensionBlobURI ,
39+
40+ [Parameter (Mandatory = $true , ParameterSetName = ' VMExtensionFromLocal' )]
41+ [Parameter (Mandatory = $true , ParameterSetName = ' VMExtesionFromAzure' )]
42+ [ValidateSet (' Windows' , ' Linux' )]
43+ [String ] $osType ,
44+
45+ [Parameter (ParameterSetName = ' VMExtensionFromLocal' )]
46+ [Parameter (ParameterSetName = ' VMExtesionFromAzure' )]
47+ [String ] $vmScaleSetEnabled = " false" ,
48+
49+ [Parameter (ParameterSetName = ' VMExtensionFromLocal' )]
50+ [Parameter (ParameterSetName = ' VMExtesionFromAzure' )]
51+ [String ] $supportMultipleExtensions = " false" ,
52+
53+ [Parameter (Mandatory = $true , ParameterSetName = ' VMExtensionFromLocal' )]
54+ [Parameter (Mandatory = $true , ParameterSetName = ' VMExtesionFromAzure' )]
55+ [ValidateNotNullorEmpty ()]
56+ [String ] $tenantID ,
57+
58+ [Parameter (ParameterSetName = ' VMExtensionFromLocal' )]
59+ [Parameter (ParameterSetName = ' VMExtesionFromAzure' )]
60+ [String ] $location = ' local' ,
61+
62+ [Parameter (Mandatory = $true , ParameterSetName = ' VMExtensionFromLocal' )]
63+ [Parameter (Mandatory = $true , ParameterSetName = ' VMExtesionFromAzure' )]
64+ [System.Management.Automation.PSCredential ] $azureStackCredentials ,
65+
66+ [Parameter (ParameterSetName = ' VMExtensionFromLocal' )]
67+ [Parameter (ParameterSetName = ' VMExtesionFromAzure' )]
68+ [string ] $ArmEndpoint = ' https://adminmanagement.local.azurestack.external'
69+ )
70+
71+ $resourceGroupName = " addvmextresourcegroup"
72+ $storageAccountName = " addvmextstorageaccount"
73+ $containerName = " addvmextensioncontainer"
74+
75+ $subscription , $headers = (Get-AzureStackAdminSubTokenHeader - TenantId $tenantId - AzureStackCredentials $azureStackCredentials - ArmEndpoint $ArmEndpoint )
76+
77+ # potentially the RG was not cleaned up when exception happened in previous run. Test for exist
78+ if (-not (Get-AzureRmResourceGroup - Name $resourceGroupName - Location $location - ErrorAction SilentlyContinue)) {
79+ New-AzureRmResourceGroup - Name $resourceGroupName - Location $location
80+ }
81+
82+ # same for storage
83+ $storageAccount = Get-AzureRmStorageAccount - Name $storageAccountName - ResourceGroupName $resourceGroupName - ErrorAction SilentlyContinue
84+ if (-not ($storageAccount )) {
85+ $storageAccount = New-AzureRmStorageAccount - Name $storageAccountName - Location $location - ResourceGroupName $resourceGroupName - Type Standard_LRS
86+ }
87+
88+ Set-AzureRmCurrentStorageAccount - StorageAccountName $storageAccountName - ResourceGroupName $resourceGroupName
89+
90+ # same for container
91+ $container = Get-AzureStorageContainer - Name $containerName - ErrorAction SilentlyContinue
92+ if (-not ($container )) {
93+ $container = New-AzureStorageContainer - Name $containerName - Permission Blob
94+ }
95+
96+ if ($pscmdlet.ParameterSetName -eq " VMExtensionFromLocal" )
97+ {
98+ $storageAccount.PrimaryEndpoints.Blob
99+ $script :extensionName = Split-Path $extensionLocalPath - Leaf
100+ $script :extensionBlobURIFromLocal = ' {0}{1}/{2}' -f $storageAccount.PrimaryEndpoints.Blob.AbsoluteUri , $containerName , $extensionName
101+ Set-AzureStorageBlobContent - File $extensionLocalPath - Container $containerName - Blob $extensionName
102+ }
103+
104+ $ArmEndpoint = $ArmEndpoint.TrimEnd (" /" )
105+ $uri = $armEndpoint + ' /subscriptions/' + $subscription + ' /providers/Microsoft.Compute.Admin/locations/' + $location + ' /artifactTypes/VMExtension/publishers/' + $publisher
106+ $uri = $uri + ' /types/' + $type + ' /versions/' + $version + ' ?api-version=2015-12-01-preview'
107+
108+ # building request body JSON
109+ if ($pscmdlet.ParameterSetName -eq " VMExtensionFromLocal" ) {
110+ $sourceBlobJSON = ' "SourceBlob" : {"Uri" :"' + $extensionBlobURIFromLocal + ' "}'
111+ }
112+ else {
113+ $sourceBlobJSON = ' "SourceBlob" : {"Uri" :"' + $extensionBlobURI + ' "}'
114+ }
115+
116+ $osTypeJSON = ' "VmOsType" : "' + $osType + ' "'
117+ $ComputeRoleJSON = ' "ComputeRole" : "N/A"'
118+ $VMScaleSetEnabledJSON = ' "VMScaleSetEnabled" : "' + $vmScaleSetEnabled + ' "'
119+ $SupportMultipleExtensionsJSON = ' "SupportMultipleExtensions" : "' + $supportMultipleExtensions + ' "'
120+ $IsSystemExtensionJSON = ' "IsSystemExtension" : "false"'
121+
122+ $propertyBody = $sourceBlobJSON + " ," + $osTypeJSON + ' ,' + $ComputeRoleJSON + " ," + $VMScaleSetEnabledJSON + " ," + $SupportMultipleExtensionsJSON + " ," + $IsSystemExtensionJSON
123+
124+ # building ARMResource
125+
126+ $RequestBody = ' {"Properties":{' + $propertyBody + ' }}'
127+
128+ Invoke-RestMethod - Method PUT - Uri $uri - Body $RequestBody - ContentType ' application/json' - Headers $Headers
129+
130+ $extensionHandler = Invoke-RestMethod - Method GET - Uri $uri - ContentType ' application/json' - Headers $Headers
131+
132+ while ($extensionHandler.Properties.ProvisioningState -ne ' Succeeded' )
133+ {
134+ if ($extensionHandler.Properties.ProvisioningState -eq ' Failed' )
135+ {
136+ Write-Error - Message " VM extension download failed." - ErrorAction Stop
137+ }
138+
139+ if ($extensionHandler.Properties.ProvisioningState -eq ' Canceled' )
140+ {
141+ Write-Error - Message " VM extension download was canceled." - ErrorAction Stop
142+ }
143+
144+ Write-Host " Downloading" ;
145+ Start-Sleep - Seconds 4
146+ $extensionHandler = Invoke-RestMethod - Method GET - Uri $uri - ContentType ' application/json' - Headers $Headers
147+ }
148+
149+ Remove-AzureStorageContainer –Name $containerName - Force
150+ Remove-AzureRmStorageAccount - ResourceGroupName $resourceGroupName - AccountName $storageAccountName
151+ Remove-AzureRmResourceGroup - Name $resourceGroupName - Force
152+ }
153+
154+ Function Remove-VMExtension {
155+ Param (
156+ [ValidatePattern (“ [a-zA-Z0-9-]{3,}” )]
157+ [String ] $publisher ,
158+
159+ [Parameter (Mandatory = $true )]
160+ [ValidatePattern (“ \d+\.\d+\.\d+” )]
161+ [String ] $version ,
162+
163+ [String ] $type = " CustomScriptExtension" ,
164+
165+ [Parameter (Mandatory = $true )]
166+ [ValidateSet (' Windows' , ' Linux' )]
167+ [String ] $osType ,
168+
169+ [Parameter (Mandatory = $true )]
170+ [ValidateNotNullorEmpty ()]
171+ [String ] $tenantID ,
172+
173+ [String ] $location = ' local' ,
174+
175+ [Parameter (Mandatory = $true )]
176+ [System.Management.Automation.PSCredential ] $azureStackCredentials ,
177+
178+ [string ] $ArmEndpoint = ' https://adminmanagement.local.azurestack.external'
179+ )
180+
181+ $subscription , $headers = (Get-AzureStackAdminSubTokenHeader - TenantId $tenantId - AzureStackCredentials $azureStackCredentials - ArmEndpoint $ArmEndpoint )
182+
183+ $ArmEndpoint = $ArmEndpoint.TrimEnd (" /" )
184+ $uri = $armEndpoint + ' /subscriptions/' + $subscription + ' /providers/Microsoft.Compute.Admin/locations/' + $location + ' /artifactTypes/VMExtension/publishers/' + $publisher
185+ $uri = $uri + ' /types/' + $type + ' /versions/' + $version + ' ?api-version=2015-12-01-preview'
186+
187+ try {
188+ Invoke-RestMethod - Method DELETE - Uri $uri - ContentType ' application/json' - Headers $headers
189+ }
190+ catch {
191+ Write-Error - Message (' Deletion of VM extension with publisher "{0}" failed with Error:"{1}.' -f $publisher , $Error ) - ErrorAction Stop
192+ }
193+ }
0 commit comments