Skip to content

Commit 1bb3f29

Browse files
committed
Add VmExtension ps API calls
1 parent 84c6509 commit 1bb3f29

2 files changed

Lines changed: 197 additions & 1 deletion

File tree

ComputeAdmin/AzureStack.ComputeAdmin.psm1

Lines changed: 183 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55

66
<#
77
.SYNOPSIS
8-
Contains 3 functions.
8+
Contains 5 functions.
99
Add-VMImage: Uploads a VM Image to your Azure Stack and creates a Marketplace item for it.
1010
Remove-VMImage: Removes an existing VM Image from your Azure Stack. Does not delete any
1111
maketplace items created by Add-VMImage.
1212
New-Server2016VMImage: Creates and Uploads a new Server 2016 Core and / or Full Image and
1313
creates a Marketplace item for it.
14+
Add-VMExtension: Uploads a VM extension to your Azure Stack.
15+
Remove-VMExtension: Removes an existing VM extension from your Azure Stack.
1416
#>
1517

1618
Function Add-VMImage{
@@ -660,5 +662,185 @@ Function CreateGalleyItem{
660662
Remove-Item "$workdir\MarketplaceItem.zip"
661663
$azpkg = '{0}\{1}' -f $workdir, $galleryItemName
662664
return Get-Item -LiteralPath $azpkg
665+
}
666+
667+
Function Add-VMExtension{
668+
669+
[CmdletBinding(DefaultParameterSetName='VMExtensionFromLocal')]
670+
Param(
671+
[Parameter(Mandatory=$true, ParameterSetName='VMExtensionFromLocal')]
672+
[Parameter(Mandatory=$true, ParameterSetName='VMExtesionFromAzure')]
673+
[ValidatePattern([a-zA-Z0-9-]{3,})]
674+
[String] $publisher,
675+
676+
[Parameter(Mandatory=$true, ParameterSetName='VMExtensionFromLocal')]
677+
[Parameter(Mandatory=$true, ParameterSetName='VMExtesionFromAzure')]
678+
[ValidatePattern(\d+\.\d+\.\d+)]
679+
[String] $version,
680+
681+
[Parameter(ParameterSetName='VMExtensionFromLocal')]
682+
[Parameter(ParameterSetName='VMExtesionFromAzure')]
683+
[String] $type,
684+
685+
[Parameter(Mandatory=$true, ParameterSetName='VMExtensionFromLocal')]
686+
[ValidateNotNullorEmpty()]
687+
[String] $extensionLocalPath,
688+
689+
[Parameter(Mandatory=$true, ParameterSetName='VMExtesionFromAzure')]
690+
[ValidateNotNullorEmpty()]
691+
[String] $extensionBlobURI,
692+
693+
[Parameter(Mandatory=$true, ParameterSetName='VMExtensionFromLocal')]
694+
[Parameter(Mandatory=$true, ParameterSetName='VMExtesionFromAzure')]
695+
[ValidateSet('Windows' ,'Linux')]
696+
[String] $osType,
697+
698+
[Parameter(ParameterSetName='VMExtensionFromLocal')]
699+
[Parameter(ParameterSetName='VMExtesionFromAzure')]
700+
[String] $vmScaleSetEnabled = "false",
701+
702+
[Parameter(ParameterSetName='VMExtensionFromLocal')]
703+
[Parameter(ParameterSetName='VMExtesionFromAzure')]
704+
[String] $supportMultipleExtensions = "false",
705+
706+
[Parameter(Mandatory=$true, ParameterSetName='VMExtensionFromLocal')]
707+
[Parameter(Mandatory=$true, ParameterSetName='VMExtesionFromAzure')]
708+
[ValidateNotNullorEmpty()]
709+
[String] $tenantID,
710+
711+
[Parameter(ParameterSetName='VMExtensionFromLocal')]
712+
[Parameter(ParameterSetName='VMExtesionFromAzure')]
713+
[String] $location = 'local',
714+
715+
[Parameter(Mandatory=$true, ParameterSetName='VMExtensionFromLocal')]
716+
[Parameter(Mandatory=$true, ParameterSetName='VMExtesionFromAzure')]
717+
[System.Management.Automation.PSCredential] $azureStackCredentials,
718+
719+
[Parameter(ParameterSetName='VMExtensionFromLocal')]
720+
[Parameter(ParameterSetName='VMExtesionFromAzure')]
721+
[string] $ArmEndpoint = 'https://adminmanagement.local.azurestack.external'
722+
)
723+
724+
$resourceGroupName = "addvmextresourcegroup"
725+
$storageAccountName = "addvmextstorageaccount"
726+
$containerName = "addvmextensioncontainer"
727+
728+
$subscription, $headers = (Get-AzureStackAdminSubTokenHeader -TenantId $tenantId -AzureStackCredentials $azureStackCredentials -ArmEndpoint $ArmEndpoint)
729+
730+
#potentially the RG was not cleaned up when exception happened in previous run. Test for exist
731+
if (-not (Get-AzureRmResourceGroup -Name $resourceGroupName -Location $location -ErrorAction SilentlyContinue)) {
732+
New-AzureRmResourceGroup -Name $resourceGroupName -Location $location
663733
}
664734

735+
#same for storage
736+
$storageAccount = Get-AzureRmStorageAccount -Name $storageAccountName -ResourceGroupName $resourceGroupName -ErrorAction SilentlyContinue
737+
if (-not ($storageAccount)) {
738+
$storageAccount = New-AzureRmStorageAccount -Name $storageAccountName -Location $location -ResourceGroupName $resourceGroupName -Type Standard_LRS
739+
}
740+
741+
Set-AzureRmCurrentStorageAccount -StorageAccountName $storageAccountName -ResourceGroupName $resourceGroupName
742+
743+
#same for container
744+
$container = Get-AzureStorageContainer -Name $containerName -ErrorAction SilentlyContinue
745+
if (-not ($container)) {
746+
$container = New-AzureStorageContainer -Name $containerName -Permission Blob
747+
}
748+
749+
if($pscmdlet.ParameterSetName -eq "VMExtensionFromLocal")
750+
{
751+
$storageAccount.PrimaryEndpoints.Blob
752+
$script:extensionName = Split-Path $extensionLocalPath -Leaf
753+
$script:extensionBlobURIFromLocal = '{0}{1}/{2}' -f $storageAccount.PrimaryEndpoints.Blob.AbsoluteUri, $containerName,$extensionName
754+
Set-AzureStorageBlobContent -File $extensionLocalPath -Container $containerName -Blob $extensionName
755+
}
756+
757+
$ArmEndpoint = $ArmEndpoint.TrimEnd("/")
758+
$uri = $armEndpoint + '/subscriptions/' + $subscription + '/providers/Microsoft.Compute.Admin/locations/' + $location + '/artifactTypes/VMExtension/publishers/' + $publisher
759+
$uri = $uri + '/types/' + $type + '/versions/' + $version + '?api-version=2015-12-01-preview'
760+
761+
#building request body JSON
762+
if($pscmdlet.ParameterSetName -eq "VMExtensionFromLocal") {
763+
$sourceBlobJSON = '"SourceBlob" : {"Uri" :"' + $extensionBlobURIFromLocal + '"}'
764+
}
765+
else {
766+
$sourceBlobJSON = '"SourceBlob" : {"Uri" :"' + $extensionBlobURI + '"}'
767+
}
768+
769+
$osTypeJSON = '"VmOsType" : "' + $osType + '"'
770+
$ComputeRoleJSON = '"ComputeRole" : "N/A"'
771+
$VMScaleSetEnabledJSON = '"VMScaleSetEnabled" : "' + $vmScaleSetEnabled + '"'
772+
$SupportMultipleExtensionsJSON = '"SupportMultipleExtensions" : "' + $supportMultipleExtensions + '"'
773+
$IsSystemExtensionJSON = '"IsSystemExtension" : "false"'
774+
775+
$propertyBody = $sourceBlobJSON + "," + $osTypeJSON + ',' + $ComputeRoleJSON + "," + $VMScaleSetEnabledJSON + "," + $SupportMultipleExtensionsJSON + "," + $IsSystemExtensionJSON
776+
777+
#building ARMResource
778+
779+
$RequestBody = '{"Properties":{'+$propertyBody+'}}'
780+
781+
Invoke-RestMethod -Method PUT -Uri $uri -Body $RequestBody -ContentType 'application/json' -Headers $Headers
782+
783+
$extensionHandler = Invoke-RestMethod -Method GET -Uri $uri -ContentType 'application/json' -Headers $Headers
784+
785+
while($extensionHandler.Properties.ProvisioningState -ne 'Succeeded')
786+
{
787+
if($extensionHandler.Properties.ProvisioningState -eq 'Failed')
788+
{
789+
Write-Error -Message "VM extension download failed." -ErrorAction Stop
790+
}
791+
792+
if($extensionHandler.Properties.ProvisioningState -eq 'Canceled')
793+
{
794+
Write-Error -Message "VM extension download was canceled." -ErrorAction Stop
795+
}
796+
797+
Write-Host "Downloading";
798+
Start-Sleep -Seconds 4
799+
$extensionHandler = Invoke-RestMethod -Method GET -Uri $uri -ContentType 'application/json' -Headers $Headers
800+
}
801+
802+
Remove-AzureStorageContainer –Name $containerName -Force
803+
Remove-AzureRmStorageAccount -ResourceGroupName $resourceGroupName -AccountName $storageAccountName
804+
Remove-AzureRmResourceGroup -Name $resourceGroupName -Force
805+
}
806+
807+
Function Remove-VMExtension{
808+
Param(
809+
[ValidatePattern([a-zA-Z0-9-]{3,})]
810+
[String] $publisher,
811+
812+
[Parameter(Mandatory=$true)]
813+
[ValidatePattern(\d+\.\d+\.\d+)]
814+
[String] $version,
815+
816+
[String] $type = "CustomScriptExtension",
817+
818+
[Parameter(Mandatory=$true)]
819+
[ValidateSet('Windows' ,'Linux')]
820+
[String] $osType,
821+
822+
[Parameter(Mandatory=$true)]
823+
[ValidateNotNullorEmpty()]
824+
[String] $tenantID,
825+
826+
[String] $location = 'local',
827+
828+
[Parameter(Mandatory=$true)]
829+
[System.Management.Automation.PSCredential] $azureStackCredentials,
830+
831+
[string] $ArmEndpoint = 'https://adminmanagement.local.azurestack.external'
832+
)
833+
834+
$subscription, $headers = (Get-AzureStackAdminSubTokenHeader -TenantId $tenantId -AzureStackCredentials $azureStackCredentials -ArmEndpoint $ArmEndpoint)
835+
836+
$ArmEndpoint = $ArmEndpoint.TrimEnd("/")
837+
$uri = $armEndpoint + '/subscriptions/' + $subscription + '/providers/Microsoft.Compute.Admin/locations/' + $location + '/artifactTypes/VMExtension/publishers/' + $publisher
838+
$uri = $uri + '/types/' + $type + '/versions/' + $version + '?api-version=2015-12-01-preview'
839+
840+
try{
841+
Invoke-RestMethod -Method DELETE -Uri $uri -ContentType 'application/json' -Headers $headers
842+
}
843+
catch{
844+
Write-Error -Message ('Deletion of VM extension with publisher "{0}" failed with Error:"{1}.' -f $publisher,$Error) -ErrorAction Stop
845+
}
846+
}

ComputeAdmin/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,17 @@ Remove-VMImage -publisher "Canonical" -offer "UbuntuServer" -sku "14.04.3-LTS" -
8383
```
8484

8585
Note: This cmdlet will remove the associated Marketplace item unless the -KeepMarketplaceItem parameter is specified.
86+
87+
## Add a VM extension to the Compute with PowerShell
88+
An example usage is the following:
89+
```powershell
90+
$path = "<Path to vm extension zip>"
91+
Add-VMExtension -publisher $publisher -version $version -extensionLocalPath $path -osType Windows -tenantID $aadTenant -azureStackCredentials $azureStackCredentials -type "CustomVmExtension"
92+
```
93+
94+
# Remove a VM extension with PowerShell
95+
Run the below command to remove an uploaded VM extension.
96+
97+
```powershell
98+
Remove-VMExtension -publisher $publisher -version $version -osType Windows -tenantID $tenantId -azureStackCredentials $azureStackCredentials -type "CustomVmExtension"
99+
```

0 commit comments

Comments
 (0)