|
5 | 5 |
|
6 | 6 | <# |
7 | 7 | .SYNOPSIS |
8 | | - Contains 4 functions. |
| 8 | + Contains 6 functions. |
9 | 9 | Add-VMImage: Uploads a VM Image to your Azure Stack and creates a Marketplace item for it. |
10 | 10 | Remove-VMImage: Removes an existing VM Image from your Azure Stack. Does not delete any |
11 | 11 | maketplace items created by Add-VMImage. |
12 | 12 | New-Server2016VMImage: Creates and Uploads a new Server 2016 Core and / or Full Image and |
13 | 13 | creates a Marketplace item for it. |
14 | 14 | Get-VMImage: Gets a VM Image from your Azure Stack as an Administrator to view the provisioning state of the image. |
| 15 | + Add-VMExtension: Uploads a VM extension to your Azure Stack. |
| 16 | + Remove-VMExtension: Removes an existing VM extension from your Azure Stack. |
15 | 17 | #> |
16 | 18 |
|
17 | 19 | Function Add-VMImage{ |
@@ -789,6 +791,190 @@ Function Get-VMImage{ |
789 | 791 | }catch{ |
790 | 792 | return $null |
791 | 793 | } |
| 794 | +} |
| 795 | + |
| 796 | +Function Add-VMExtension{ |
| 797 | + |
| 798 | + [CmdletBinding(DefaultParameterSetName='VMExtensionFromLocal')] |
| 799 | + Param( |
| 800 | + [Parameter(Mandatory=$true, ParameterSetName='VMExtensionFromLocal')] |
| 801 | + [Parameter(Mandatory=$true, ParameterSetName='VMExtesionFromAzure')] |
| 802 | + [ValidatePattern(“[a-zA-Z0-9-]{3,}”)] |
| 803 | + [String] $publisher, |
| 804 | + |
| 805 | + [Parameter(Mandatory=$true, ParameterSetName='VMExtensionFromLocal')] |
| 806 | + [Parameter(Mandatory=$true, ParameterSetName='VMExtesionFromAzure')] |
| 807 | + [ValidatePattern(“\d+\.\d+\.\d+”)] |
| 808 | + [String] $version, |
| 809 | + |
| 810 | + [Parameter(ParameterSetName='VMExtensionFromLocal')] |
| 811 | + [Parameter(ParameterSetName='VMExtesionFromAzure')] |
| 812 | + [String] $type, |
| 813 | + |
| 814 | + [Parameter(Mandatory=$true, ParameterSetName='VMExtensionFromLocal')] |
| 815 | + [ValidateNotNullorEmpty()] |
| 816 | + [String] $extensionLocalPath, |
| 817 | + |
| 818 | + [Parameter(Mandatory=$true, ParameterSetName='VMExtesionFromAzure')] |
| 819 | + [ValidateNotNullorEmpty()] |
| 820 | + [String] $extensionBlobURI, |
| 821 | + |
| 822 | + [Parameter(Mandatory=$true, ParameterSetName='VMExtensionFromLocal')] |
| 823 | + [Parameter(Mandatory=$true, ParameterSetName='VMExtesionFromAzure')] |
| 824 | + [ValidateSet('Windows' ,'Linux')] |
| 825 | + [String] $osType, |
| 826 | + |
| 827 | + [Parameter(ParameterSetName='VMExtensionFromLocal')] |
| 828 | + [Parameter(ParameterSetName='VMExtesionFromAzure')] |
| 829 | + [bool] $vmScaleSetEnabled = $false, |
| 830 | + |
| 831 | + [Parameter(ParameterSetName='VMExtensionFromLocal')] |
| 832 | + [Parameter(ParameterSetName='VMExtesionFromAzure')] |
| 833 | + [bool] $supportMultipleExtensions = $false, |
| 834 | + |
| 835 | + [Parameter(Mandatory=$true, ParameterSetName='VMExtensionFromLocal')] |
| 836 | + [Parameter(Mandatory=$true, ParameterSetName='VMExtesionFromAzure')] |
| 837 | + [ValidateNotNullorEmpty()] |
| 838 | + [String] $tenantID, |
| 839 | + |
| 840 | + [Parameter(ParameterSetName='VMExtensionFromLocal')] |
| 841 | + [Parameter(ParameterSetName='VMExtesionFromAzure')] |
| 842 | + [String] $location = 'local', |
| 843 | + |
| 844 | + [Parameter(Mandatory=$true, ParameterSetName='VMExtensionFromLocal')] |
| 845 | + [Parameter(Mandatory=$true, ParameterSetName='VMExtesionFromAzure')] |
| 846 | + [System.Management.Automation.PSCredential] $azureStackCredentials, |
| 847 | + |
| 848 | + [Parameter(ParameterSetName='VMExtensionFromLocal')] |
| 849 | + [Parameter(ParameterSetName='VMExtesionFromAzure')] |
| 850 | + [string] $ArmEndpoint = 'https://adminmanagement.local.azurestack.external' |
| 851 | + ) |
| 852 | + |
| 853 | + $resourceGroupName = "addvmextresourcegroup" |
| 854 | + $storageAccountName = "addvmextstorageaccount" |
| 855 | + $containerName = "addvmextensioncontainer" |
| 856 | + |
| 857 | + $subscription, $headers = (Get-AzureStackAdminSubTokenHeader -TenantId $tenantId -AzureStackCredentials $azureStackCredentials -ArmEndpoint $ArmEndpoint) |
| 858 | + |
| 859 | + #potentially the RG was not cleaned up when exception happened in previous run. Test for exist |
| 860 | + if (-not (Get-AzureRmResourceGroup -Name $resourceGroupName -Location $location -ErrorAction SilentlyContinue)) { |
| 861 | + New-AzureRmResourceGroup -Name $resourceGroupName -Location $location |
| 862 | + } |
| 863 | + |
| 864 | + #same for storage |
| 865 | + $storageAccount = Get-AzureRmStorageAccount -Name $storageAccountName -ResourceGroupName $resourceGroupName -ErrorAction SilentlyContinue |
| 866 | + if (-not ($storageAccount)) { |
| 867 | + $storageAccount = New-AzureRmStorageAccount -Name $storageAccountName -Location $location -ResourceGroupName $resourceGroupName -Type Standard_LRS |
| 868 | + } |
| 869 | + |
| 870 | + Set-AzureRmCurrentStorageAccount -StorageAccountName $storageAccountName -ResourceGroupName $resourceGroupName |
| 871 | + |
| 872 | + #same for container |
| 873 | + $container = Get-AzureStorageContainer -Name $containerName -ErrorAction SilentlyContinue |
| 874 | + if (-not ($container)) { |
| 875 | + $container = New-AzureStorageContainer -Name $containerName -Permission Blob |
| 876 | + } |
| 877 | + |
| 878 | + if($pscmdlet.ParameterSetName -eq "VMExtensionFromLocal") |
| 879 | + { |
| 880 | + $storageAccount.PrimaryEndpoints.Blob |
| 881 | + $script:extensionName = Split-Path $extensionLocalPath -Leaf |
| 882 | + $script:extensionBlobURIFromLocal = '{0}{1}/{2}' -f $storageAccount.PrimaryEndpoints.Blob.AbsoluteUri, $containerName,$extensionName |
| 883 | + Set-AzureStorageBlobContent -File $extensionLocalPath -Container $containerName -Blob $extensionName |
| 884 | + } |
| 885 | + |
| 886 | + $ArmEndpoint = $ArmEndpoint.TrimEnd("/") |
| 887 | + $uri = $armEndpoint + '/subscriptions/' + $subscription + '/providers/Microsoft.Compute.Admin/locations/' + $location + '/artifactTypes/VMExtension/publishers/' + $publisher |
| 888 | + $uri = $uri + '/types/' + $type + '/versions/' + $version + '?api-version=2015-12-01-preview' |
| 889 | + |
| 890 | + Log-Info $uri |
792 | 891 |
|
| 892 | + #building request body JSON |
| 893 | + if($pscmdlet.ParameterSetName -eq "VMExtensionFromLocal") { |
| 894 | + $sourceBlobJSON = '"SourceBlob" : {"Uri" :"' + $extensionBlobURIFromLocal + '"}' |
| 895 | + } |
| 896 | + else { |
| 897 | + $sourceBlobJSON = '"SourceBlob" : {"Uri" :"' + $extensionBlobURI + '"}' |
| 898 | + } |
| 899 | + |
| 900 | + $osTypeJSON = '"VmOsType" : "' + $osType + '"' |
| 901 | + $ComputeRoleJSON = '"ComputeRole" : "N/A"' |
| 902 | + $VMScaleSetEnabledJSON = '"VMScaleSetEnabled" : "' + $vmScaleSetEnabled + '"' |
| 903 | + $SupportMultipleExtensionsJSON = '"SupportMultipleExtensions" : "' + $supportMultipleExtensions + '"' |
| 904 | + $IsSystemExtensionJSON = '"IsSystemExtension" : "false"' |
| 905 | + |
| 906 | + $propertyBody = $sourceBlobJSON + "," + $osTypeJSON + ',' + $ComputeRoleJSON + "," + $VMScaleSetEnabledJSON + "," + $SupportMultipleExtensionsJSON + "," + $IsSystemExtensionJSON |
| 907 | + |
| 908 | + #building ARMResource |
| 909 | + |
| 910 | + $RequestBody = '{"Properties":{'+$propertyBody+'}}' |
| 911 | + |
| 912 | + Invoke-RestMethod -Method PUT -Uri $uri -Body $RequestBody -ContentType 'application/json' -Headers $Headers |
| 913 | + |
| 914 | + $extensionHandler = Invoke-RestMethod -Method GET -Uri $uri -ContentType 'application/json' -Headers $Headers |
| 915 | + |
| 916 | + while($extensionHandler.Properties.ProvisioningState -ne 'Succeeded') |
| 917 | + { |
| 918 | + if($extensionHandler.Properties.ProvisioningState -eq 'Failed') |
| 919 | + { |
| 920 | + Write-Error -Message ('VM extension download failed with Error:"{0}.' -f $publisher, $_.Exception.Message ) -ErrorAction Stop |
| 921 | + } |
| 922 | + |
| 923 | + if($extensionHandler.Properties.ProvisioningState -eq 'Canceled') |
| 924 | + { |
| 925 | + Write-Error -Message "VM extension download was canceled." -ErrorAction Stop |
| 926 | + } |
| 927 | + |
| 928 | + Write-Host "Downloading"; |
| 929 | + Start-Sleep -Seconds 4 |
| 930 | + $extensionHandler = Invoke-RestMethod -Method GET -Uri $uri -ContentType 'application/json' -Headers $Headers |
| 931 | + } |
| 932 | + |
| 933 | + Remove-AzureStorageContainer –Name $containerName -Force |
| 934 | + Remove-AzureRmStorageAccount -ResourceGroupName $resourceGroupName -AccountName $storageAccountName |
| 935 | + Remove-AzureRmResourceGroup -Name $resourceGroupName -Force |
| 936 | +} |
| 937 | + |
| 938 | +Function Remove-VMExtension{ |
| 939 | + Param( |
| 940 | + [ValidatePattern(“[a-zA-Z0-9-]{3,}”)] |
| 941 | + [String] $publisher, |
| 942 | + |
| 943 | + [Parameter(Mandatory=$true)] |
| 944 | + [ValidatePattern(“\d+\.\d+\.\d+”)] |
| 945 | + [String] $version, |
| 946 | + |
| 947 | + [String] $type = "CustomScriptExtension", |
| 948 | + |
| 949 | + [Parameter(Mandatory=$true)] |
| 950 | + [ValidateSet('Windows' ,'Linux')] |
| 951 | + [String] $osType, |
| 952 | + |
| 953 | + [Parameter(Mandatory=$true)] |
| 954 | + [ValidateNotNullorEmpty()] |
| 955 | + [String] $tenantID, |
| 956 | + |
| 957 | + [String] $location = 'local', |
| 958 | + |
| 959 | + [Parameter(Mandatory=$true)] |
| 960 | + [System.Management.Automation.PSCredential] $azureStackCredentials, |
| 961 | + |
| 962 | + [string] $ArmEndpoint = 'https://adminmanagement.local.azurestack.external' |
| 963 | + ) |
| 964 | + |
| 965 | + $subscription, $headers = (Get-AzureStackAdminSubTokenHeader -TenantId $tenantId -AzureStackCredentials $azureStackCredentials -ArmEndpoint $ArmEndpoint) |
| 966 | + |
| 967 | + $ArmEndpoint = $ArmEndpoint.TrimEnd("/") |
| 968 | + $uri = $armEndpoint + '/subscriptions/' + $subscription + '/providers/Microsoft.Compute.Admin/locations/' + $location + '/artifactTypes/VMExtension/publishers/' + $publisher |
| 969 | + $uri = $uri + '/types/' + $type + '/versions/' + $version + '?api-version=2015-12-01-preview' |
| 970 | + |
| 971 | + Log-Info $uri |
| 972 | + |
| 973 | + try{ |
| 974 | + Invoke-RestMethod -Method DELETE -Uri $uri -ContentType 'application/json' -Headers $headers |
| 975 | + } |
| 976 | + catch{ |
| 977 | + Write-Error -Message ('Deletion of VM extension with publisher "{0}" failed with Error:"{1}.' -f $publisher, $_.Exception.Message ) -ErrorAction Stop |
| 978 | + } |
793 | 979 | } |
794 | 980 |
|
0 commit comments