|
@ -39,11 +39,11 @@ param (
|
|||
[parameter(HelpMessage="Path for Linux VHD")]
|
||||
[Parameter(ParameterSetName="default", Mandatory=$false)]
|
||||
[Parameter(ParameterSetName="tenant", Mandatory=$false)]
|
||||
[string] $LinuxImagePath = "https://partner-images.canonical.com/azure/azure_stack/ubuntu-14.04-LTS-microsoft_azure_stack-20161208-9.vhd.zip",
|
||||
[string] $LinuxImagePath = "http://cloud-images.ubuntu.com/releases/xenial/release/ubuntu-16.04-server-cloudimg-amd64-disk1.vhd.zip",
|
||||
[parameter(HelpMessage="Linux OS sku")]
|
||||
[Parameter(ParameterSetName="default", Mandatory=$false)]
|
||||
[Parameter(ParameterSetName="tenant", Mandatory=$false)]
|
||||
[string] $LinuxOSSku = "14.04.3-LTS",
|
||||
[string] $LinuxOSSku = "16.04-LTS",
|
||||
[parameter(HelpMessage="Fully qualified domain name of the azure stack environment. Ex: contoso.com")]
|
||||
[Parameter(ParameterSetName="default", Mandatory=$false)]
|
||||
[Parameter(ParameterSetName="tenant", Mandatory=$false)]
|
||||
|
@ -61,12 +61,12 @@ param (
|
|||
[parameter(HelpMessage="Resource group under which all the utilities need to be placed")]
|
||||
[Parameter(ParameterSetName="default", Mandatory=$false)] [Parameter(ParameterSetName="tenant", Mandatory=$false)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$CanaryUtilitiesRG = "canur" + [Random]::new().Next(1,999),
|
||||
[string]$CanaryUtilitiesRG = "cnur" + [Random]::new().Next(1,99),
|
||||
[parameter(HelpMessage="Resource group under which the virtual machines need to be placed")]
|
||||
[Parameter(ParameterSetName="default", Mandatory=$false)]
|
||||
[Parameter(ParameterSetName="tenant", Mandatory=$false)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$CanaryVMRG = "canvr" + [Random]::new().Next(1,999),
|
||||
[string]$CanaryVMRG = "cnvr" + [Random]::new().Next(1,99),
|
||||
[parameter(HelpMessage="Location where all the resource need to deployed and placed")]
|
||||
[Parameter(ParameterSetName="default", Mandatory=$false)]
|
||||
[Parameter(ParameterSetName="tenant", Mandatory=$false)]
|
||||
|
@ -86,41 +86,66 @@ param (
|
|||
[Parameter(ParameterSetName="tenant", Mandatory=$false)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[switch]$NoCleanup,
|
||||
[parameter(HelpMessage="Specifies whether Canary needs to clean up resources when a failure is encountered")]
|
||||
[Parameter(ParameterSetName="default", Mandatory=$false)]
|
||||
[Parameter(ParameterSetName="tenant", Mandatory=$false)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[switch]$NoCleanupOnFailure,
|
||||
[parameter(HelpMessage="Specifies the path for log files")]
|
||||
[Parameter(ParameterSetName="default", Mandatory=$false)]
|
||||
[Parameter(ParameterSetName="tenant", Mandatory=$false)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$CanaryLogPath = $env:TMP + "\CanaryLogs$((Get-Date).Ticks)",
|
||||
[parameter(HelpMessage="Specifies the file name for canary log file")]
|
||||
[parameter(HelpMessage="Specifies the file name for canary log file")]
|
||||
[Parameter(ParameterSetName="default", Mandatory=$false)]
|
||||
[Parameter(ParameterSetName="tenant", Mandatory=$false)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$CanaryLogFileName = "Canary-Basic-$((Get-Date).Ticks).log"
|
||||
[string]$CanaryLogFileName = "Canary-Basic-$((Get-Date).Ticks).log",
|
||||
[parameter(HelpMessage="List of usecases to be excluded from execution")]
|
||||
[Parameter(ParameterSetName="default", Mandatory=$false)]
|
||||
[Parameter(ParameterSetName="tenant", Mandatory=$false)]
|
||||
[string[]]$ExclusionList = ("GetAzureStackInfraRoleInstance"),
|
||||
[parameter(HelpMessage="Lists the available usecases in Canary")]
|
||||
[Parameter(ParameterSetName="listavl", Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[switch]$ListAvailable
|
||||
)
|
||||
|
||||
#requires -Modules AzureRM.Profile, AzureRM.AzureStackAdmin
|
||||
#Requires -RunAsAdministrator
|
||||
Import-Module -Name $PSScriptRoot\Canary.Utilities.psm1 -Force
|
||||
Import-Module -Name $PSScriptRoot\..\Connect\AzureStack.Connect.psm1 -Force
|
||||
Import-Module -Name $PSScriptRoot\..\Infrastructure\AzureStack.Infra.psm1 -Force
|
||||
Import-Module -Name $PSScriptRoot\..\ComputeAdmin\AzureStack.ComputeAdmin.psm1 -Force
|
||||
|
||||
$storageAccName = $CanaryUtilitiesRG + "sa"
|
||||
$storageCtrName = $CanaryUtilitiesRG + "sc"
|
||||
$keyvaultName = $CanaryUtilitiesRG + "kv"
|
||||
$keyvaultCertName = "ASCanaryVMCertificate"
|
||||
$kvSecretName = $keyvaultName.ToLowerInvariant() + "secret"
|
||||
$VMAdminUserName = "CanaryAdmin"
|
||||
$VMAdminUserPass = "CanaryAdmin@123"
|
||||
$canaryUtilPath = Join-Path -Path $env:TEMP -ChildPath "CanaryUtilities$((Get-Date).Ticks)"
|
||||
$linuxImagePublisher = "Canonical"
|
||||
$linuxImageOffer = "UbuntuServer"
|
||||
$linuxImageVersion = "1.0.0"
|
||||
Import-Module -Name $PSScriptRoot\Canary.Utilities.psm1 -Force -DisableNameChecking
|
||||
if (-not $ListAvailable.IsPresent)
|
||||
{
|
||||
#requires -Modules AzureRM.Profile, AzureRM.AzureStackAdmin
|
||||
#Requires -RunAsAdministrator
|
||||
|
||||
Import-Module -Name $PSScriptRoot\..\Connect\AzureStack.Connect.psm1 -Force
|
||||
Import-Module -Name $PSScriptRoot\..\Infrastructure\AzureStack.Infra.psm1 -Force
|
||||
Import-Module -Name $PSScriptRoot\..\ComputeAdmin\AzureStack.ComputeAdmin.psm1 -Force
|
||||
}
|
||||
else
|
||||
{
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
}
|
||||
$runCount = 1
|
||||
$tmpLogname = $CanaryLogFileName
|
||||
while ($runCount -le $NumberOfIterations)
|
||||
{
|
||||
if ($NumberOfIterations -gt 1)
|
||||
{
|
||||
$CanaryUtilitiesRG = $CanaryUtilitiesRG + $runCount
|
||||
$CanaryVMRG = $CanaryVMRG + $runCount
|
||||
}
|
||||
$storageAccName = $CanaryUtilitiesRG + "sa"
|
||||
$storageCtrName = $CanaryUtilitiesRG + "sc"
|
||||
$keyvaultName = $CanaryUtilitiesRG + "kv"
|
||||
$keyvaultCertName = "ASCanaryVMCertificate"
|
||||
$kvSecretName = $keyvaultName.ToLowerInvariant() + "secret"
|
||||
$VMAdminUserName = "CanaryAdmin"
|
||||
$VMAdminUserPass = "CanaryAdmin@123"
|
||||
$canaryUtilPath = Join-Path -Path $env:TEMP -ChildPath "CanaryUtilities$((Get-Date).Ticks)"
|
||||
$linuxImagePublisher = "Canonical"
|
||||
$linuxImageOffer = "UbuntuServer"
|
||||
$linuxImageVersion = "1.0.0"
|
||||
[boolean]$linuxUpload = $false
|
||||
if (Test-Path -Path $canaryUtilPath)
|
||||
{
|
||||
Remove-Item -Path $canaryUtilPath -Force -Recurse
|
||||
|
@ -130,15 +155,15 @@ while ($runCount -le $NumberOfIterations)
|
|||
#
|
||||
# Start Canary
|
||||
#
|
||||
if($ListAvailable){Write-Host "List of scenarios in Canary:" -ForegroundColor Green; $listAvl = $true} else{$listAvl = $false}
|
||||
$CanaryLogFileName = [IO.Path]::GetFileNameWithoutExtension($tmpLogname) + "-$runCount" + [IO.Path]::GetExtension($tmpLogname)
|
||||
$CanaryLogFile = Join-Path -Path $CanaryLogPath -ChildPath $CanaryLogFileName
|
||||
|
||||
Start-Scenario -Name 'Canary' -Type 'Basic' -LogFilename $CanaryLogFile -ContinueOnFailure $ContinueOnFailure
|
||||
Start-Scenario -Name 'Canary' -Type 'Basic' -LogFilename $CanaryLogFile -ContinueOnFailure $ContinueOnFailure -ListAvailable $listAvl -ExclusionList $ExclusionList
|
||||
|
||||
$SvcAdminEnvironmentName = $EnvironmentName + "-SVCAdmin"
|
||||
$TntAdminEnvironmentName = $EnvironmentName + "-Tenant"
|
||||
|
||||
if(-not $EnvironmentDomainFQDN)
|
||||
if((-not $EnvironmentDomainFQDN) -and (-not $listAvl))
|
||||
{
|
||||
$endptres = Invoke-RestMethod "${AdminArmEndpoint}/metadata/endpoints?api-version=1.0" -ErrorAction Stop
|
||||
$EnvironmentDomainFQDN = $endptres.portalEndpoint
|
||||
|
@ -154,6 +179,7 @@ while ($runCount -le $NumberOfIterations)
|
|||
-ResourceManagerEndpoint ($asEndpoints.ResourceManagerEndpoint) `
|
||||
-GalleryEndpoint ($asEndpoints.GalleryEndpoint) `
|
||||
-GraphEndpoint ($asEndpoints.GraphEndpoint) `
|
||||
-GraphAudience ($asEndpoints.GraphEndpoint) `
|
||||
-StorageEndpointSuffix ($asEndpoints.StorageEndpointSuffix) `
|
||||
-AzureKeyVaultDnsSuffix ($asEndpoints.AzureKeyVaultDnsSuffix) `
|
||||
-EnableAdfsAuthentication:$asEndpoints.ActiveDirectoryEndpoint.TrimEnd("/").EndsWith("/adfs", [System.StringComparison]::OrdinalIgnoreCase) `
|
||||
|
@ -173,54 +199,145 @@ while ($runCount -le $NumberOfIterations)
|
|||
$defaultSubscription | Select-AzureRmSubscription
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Invoke-Usecase -Name 'ListFabricResourceProviderInfo' -Description "List FabricResourceProvider(FRP) information like storage shares, capacity, logical networks etc." -UsecaseBlock `
|
||||
{
|
||||
Invoke-Usecase -Name 'GetAzureStackInfraRole' -Description "List all infrastructure roles" -UsecaseBlock `
|
||||
{
|
||||
Get-AzsInfrastructureRole -Location $ResourceLocation
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'GetAzureStackInfraRoleInstance' -Description "List all infrastructure role instances" -UsecaseBlock `
|
||||
{
|
||||
Get-AzsInfrastructureRoleInstance -Location $ResourceLocation
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'GetAzureStackLogicalNetwork' -Description "List all logical networks" -UsecaseBlock `
|
||||
{
|
||||
Get-AzsLogicalNetwork -Location $ResourceLocation
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'GetAzureStackStorageCapacity' -Description "List storage capacity" -UsecaseBlock `
|
||||
{
|
||||
Get-AzSStorageSubsystem -Location $ResourceLocation
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'GetAzureStackStorageShare' -Description "List all storage file shares" -UsecaseBlock `
|
||||
{
|
||||
Get-AzsStorageShare -Location $ResourceLocation
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'GetAzureStackScaleUnit' -Description "List Azure Stack scale units in specified Region" -UsecaseBlock `
|
||||
{
|
||||
Get-AzsScaleUnit -Location $ResourceLocation
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'GetAzureStackScaleUnitNode' -Description "List nodes in scale unit" -UsecaseBlock `
|
||||
{
|
||||
Get-AzsScaleUnitNode -Location $ResourceLocation
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'GetAzureStackIPPool' -Description "List all IP pools" -UsecaseBlock `
|
||||
{
|
||||
Get-AzsIpPool -Location $ResourceLocation
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'GetAzureStackMacPool' -Description "List all MAC address pools " -UsecaseBlock `
|
||||
{
|
||||
Get-AzsMacPool -Location $ResourceLocation
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'GetAzureStackGatewayPool' -Description "List all gateway pools" -UsecaseBlock `
|
||||
{
|
||||
Get-AzsGatewayPool -Location $ResourceLocation
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'GetAzureStackSLBMux' -Description "List all SLB MUX instances" -UsecaseBlock `
|
||||
{
|
||||
Get-AzsSlbMux -Location $ResourceLocation
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'GetAzureStackGateway' -Description "List all gateway" -UsecaseBlock `
|
||||
{
|
||||
Get-AzsGateway -Location $ResourceLocation
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'ListHealthResourceProviderAlerts' -Description "List all HealthResourceProvider(HRP) alerts " -UsecaseBlock `
|
||||
{
|
||||
Invoke-Usecase -Name 'GetAzureStackAlert' -Description "List all alerts" -UsecaseBlock `
|
||||
{
|
||||
Get-AzsAlert -Location $ResourceLocation
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'ListUpdatesResourceProviderInfo' -Description "List URP information like summary of updates available, update to be applied, last update applied etc." -UsecaseBlock `
|
||||
{
|
||||
Invoke-Usecase -Name 'GetAzureStackUpdateSummary' -Description "List summary of updates status" -UsecaseBlock `
|
||||
{
|
||||
Get-AzSUpdateLocation -Location $ResourceLocation
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'GetAzureStackUpdateToApply' -Description "List all updates that can be applied" -UsecaseBlock `
|
||||
{
|
||||
Get-AzsUpdate -Location $ResourceLocation
|
||||
}
|
||||
}
|
||||
|
||||
if ($WindowsISOPath)
|
||||
{
|
||||
Invoke-Usecase -Name 'UploadWindows2016ImageToPIR' -Description "Uploads a windows server 2016 image to the PIR" -UsecaseBlock `
|
||||
{
|
||||
if (-not (Get-AzureRmVMImage -Location $ResourceLocation -PublisherName "MicrosoftWindowsServer" -Offer "WindowsServer" -Sku "2016-Datacenter-Core" -ErrorAction SilentlyContinue))
|
||||
{
|
||||
New-Server2016VMImage -ISOPath $WindowsISOPath -TenantId $TenantID -EnvironmentName $SvcAdminEnvironmentName -Location $ResourceLocation -Version Core -AzureStackCredentials $ServiceAdminCredentials -CreateGalleryItem $false
|
||||
New-AzsServer2016VMImage -ISOPath $WindowsISOPath -Location $ResourceLocation -Version Core -CreateGalleryItem $false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((Get-Volume ((Get-Item -Path $ENV:TMP).PSDrive.Name)).SizeRemaining/1GB -gt 35)
|
||||
{
|
||||
Invoke-Usecase -Name 'UploadLinuxImageToPIR' -Description "Uploads Linux image to the PIR" -UsecaseBlock `
|
||||
[boolean]$invalidUri = $false
|
||||
try {Invoke-WebRequest -Uri $LinuxImagePath -UseBasicParsing -DisableKeepAlive -Method Head -ErrorAction SilentlyContinue | Out-Null}
|
||||
catch {$invalidUri = $true}
|
||||
if (-not $invalidUri)
|
||||
{
|
||||
try
|
||||
Invoke-Usecase -Name 'UploadLinuxImageToPIR' -Description "Uploads Linux image to the PIR" -UsecaseBlock `
|
||||
{
|
||||
if (-not (Get-AzureRmVMImage -Location $ResourceLocation -PublisherName $linuxImagePublisher -Offer $linuxImageOffer -Sku $LinuxOSSku -ErrorAction SilentlyContinue))
|
||||
try
|
||||
{
|
||||
$CanaryCustomImageFolder = Join-Path -Path $env:TMP -childPath "CanaryCustomImage$((Get-Date).Ticks)"
|
||||
if (Test-Path -Path $CanaryCustomImageFolder)
|
||||
if (-not (Get-AzureRmVMImage -Location $ResourceLocation -PublisherName $linuxImagePublisher -Offer $linuxImageOffer -Sku $LinuxOSSku -ErrorAction SilentlyContinue))
|
||||
{
|
||||
Remove-Item -Path $CanaryCustomImageFolder -Force -Recurse
|
||||
}
|
||||
New-Item -Path $CanaryCustomImageFolder -ItemType Directory
|
||||
$CustomVHDPath = CopyImage -ImagePath $LinuxImagePath -OutputFolder $CanaryCustomImageFolder
|
||||
Add-VMImage -publisher $linuxImagePublisher -offer $linuxImageOffer -sku $LinuxOSSku -version $linuxImageVersion -osDiskLocalPath $CustomVHDPath -osType Linux -tenantID $TenantID -azureStackCredentials $ServiceAdminCredentials -Location $ResourceLocation -CreateGalleryItem $false -EnvironmentName $SvcAdminEnvironmentName
|
||||
Remove-Item $CanaryCustomImageFolder -Force -Recurse
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Remove-Item -Path $CanaryCustomImageFolder -Force -Recurse
|
||||
throw [System.Exception]"Failed to upload the linux image to PIR. `n$($_.Exception.Message)"
|
||||
$CanaryCustomImageFolder = Join-Path -Path $env:TMP -childPath "CanaryCustomImage$((Get-Date).Ticks)"
|
||||
if (Test-Path -Path $CanaryCustomImageFolder)
|
||||
{
|
||||
Remove-Item -Path $CanaryCustomImageFolder -Force -Recurse
|
||||
}
|
||||
New-Item -Path $CanaryCustomImageFolder -ItemType Directory
|
||||
$CustomVHDPath = CopyImage -ImagePath $LinuxImagePath -OutputFolder $CanaryCustomImageFolder
|
||||
Add-AzsVMImage -publisher $linuxImagePublisher -offer $linuxImageOffer -sku $LinuxOSSku -version $linuxImageVersion -osDiskLocalPath $CustomVHDPath -osType Linux -Location $ResourceLocation -CreateGalleryItem $false
|
||||
Remove-Item $CanaryCustomImageFolder -Force -Recurse
|
||||
$linuxUpload = $true
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Remove-Item -Path $CanaryCustomImageFolder -Force -Recurse
|
||||
throw [System.Exception]"Failed to upload the linux image to PIR. `n$($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($TenantAdminCredentials)
|
||||
if (($TenantAdminCredentials) -or ($ListAvailable))
|
||||
{
|
||||
$subscriptionRGName = "ascansubscrrg" + [Random]::new().Next(1,999)
|
||||
$tenantPlanName = "ascantenantplan" + [Random]::new().Next(1,999)
|
||||
$tenantOfferName = "ascantenantoffer" + [Random]::new().Next(1,999)
|
||||
$tenantSubscriptionName = "ascanarytenantsubscription" + [Random]::new().Next(1,999)
|
||||
$canaryDefaultTenantSubscription = "canarytenantdefaultsubscription" + [Random]::new().Next(1,999)
|
||||
$subscriptionRGName = $CanaryUtilitiesRG + "subscrrg" + [Random]::new().Next(1,999)
|
||||
$tenantPlanName = $CanaryUtilitiesRG + "tenantplan" + [Random]::new().Next(1,999)
|
||||
$tenantOfferName = $CanaryUtilitiesRG + "tenantoffer" + [Random]::new().Next(1,999)
|
||||
$tenantSubscriptionName = $CanaryUtilitiesRG + "tenantsubscription" + [Random]::new().Next(1,999)
|
||||
$canaryDefaultTenantSubscription = $CanaryUtilitiesRG + "tenantdefaultsubscription" + [Random]::new().Next(1,999)
|
||||
|
||||
if (-not $TenantArmEndpoint)
|
||||
if ((-not $TenantArmEndpoint) -and (-not $ListAvailable.IsPresent))
|
||||
{
|
||||
throw [System.Exception] "Tenant ARM endpoint is required."
|
||||
}
|
||||
|
@ -234,11 +351,13 @@ while ($runCount -le $NumberOfIterations)
|
|||
-ResourceManagerEndpoint ($asEndpoints.ResourceManagerEndpoint) `
|
||||
-GalleryEndpoint ($asEndpoints.GalleryEndpoint) `
|
||||
-GraphEndpoint ($asEndpoints.GraphEndpoint) `
|
||||
-GraphAudience ($asEndpoints.GraphEndpoint) `
|
||||
-StorageEndpointSuffix ($asEndpoints.StorageEndpointSuffix) `
|
||||
-AzureKeyVaultDnsSuffix ($asEndpoints.AzureKeyVaultDnsSuffix) `
|
||||
-EnableAdfsAuthentication:$asEndpoints.ActiveDirectoryEndpoint.TrimEnd("/").EndsWith("/adfs", [System.StringComparison]::OrdinalIgnoreCase) `
|
||||
-ErrorAction Stop
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'CreateResourceGroupForTenantSubscription' -Description "Create a resource group $subscriptionRGName for the tenant subscription" -UsecaseBlock `
|
||||
{
|
||||
if (Get-AzureRmResourceGroup -Name $subscriptionRGName -ErrorAction SilentlyContinue)
|
||||
|
@ -290,6 +409,162 @@ while ($runCount -le $NumberOfIterations)
|
|||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'RoleAssignmentAndCustomRoleDefinition' -Description "Assign a reader role and create a custom role definition" -UsecaseBlock `
|
||||
{
|
||||
if (-not $ListAvailable.IsPresent)
|
||||
{
|
||||
$servicePrincipal = (Get-AzureRmADServicePrincipal)[0]
|
||||
$customRoleName = "CustomCanaryRole-" + [Random]::new().Next(1,99)
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'ListAssignedRoles' -Description "List assigned roles to Service Principle - $($servicePrincipal.DisplayName)" -UsecaseBlock `
|
||||
{
|
||||
Get-AzureRmRoleAssignment -ObjectId $servicePrincipal.Id -ErrorAction Stop
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'ListExistingRoleDefinitions' -Description "List existing Role Definitions" -UsecaseBlock `
|
||||
{
|
||||
$availableRoles = Get-AzureRmRoleDefinition -ErrorAction Stop
|
||||
if (-not $availableRoles)
|
||||
{
|
||||
throw [System.Exception] "No roles are available."
|
||||
}
|
||||
else
|
||||
{
|
||||
$availableRoles
|
||||
$availableRolesNames = $availableRoles.Name
|
||||
$mustHaveRoles = @("Owner", "Reader", "Contributor")
|
||||
$match = Compare-Object $mustHaveRoles $availableRolesNames
|
||||
if ($match -and ($match | Where-Object {$_.SideIndicator -eq "<="}))
|
||||
{
|
||||
$notAvailableRoles = ($match | Where-Object {$_.SideIndicator -eq "<="}).InputObject
|
||||
throw [System.Exception] "Some must have Role Definitions are not available. Number of missing Role Definitions - $($notAvailableRoles.Count). Missing Role Definitions - $notAvailableRoles"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'GetProviderOperations' -Description "Get provider operations for all resource providers" -UsecaseBlock `
|
||||
{
|
||||
$resourceProviders = Get-AzureRmResourceProvider -ListAvailable
|
||||
# Some of the RPs have not implemented their operations API yet. So update this exclusion list whenever any RP implements its operations API
|
||||
$rpOperationsExclusionList = @("Microsoft.Commerce", "Microsoft.Gallery", "Microsoft.Insights")
|
||||
$totalOperationsPerRP = @()
|
||||
foreach($rp in $resourceProviders)
|
||||
{
|
||||
$operations = Get-AzureRMProviderOperation "$($rp.ProviderNamespace)/*" -ErrorAction Stop
|
||||
$operationObj = New-Object -TypeName System.Object
|
||||
$operationObj | Add-Member -Type NoteProperty -Name ResourceProvider -Value $rp.ProviderNamespace
|
||||
if (-not $operations)
|
||||
{
|
||||
$operationObj | Add-Member -Type NoteProperty -Name TotalProviderOperations -Value 0
|
||||
}
|
||||
else
|
||||
{
|
||||
$operationObj | Add-Member -Type NoteProperty -Name TotalProviderOperations -Value $operations.Count
|
||||
}
|
||||
$totalOperationsPerRP += $operationObj
|
||||
}
|
||||
$totalOperationsPerRP
|
||||
if ($totalOperationsPerRP -and ($totalOperationsPerRP | Where-Object {$_.TotalProviderOperations -eq 0}))
|
||||
{
|
||||
$rpWithNoOperations = ($totalOperationsPerRP | Where-Object {$_.TotalProviderOperations -eq 0}).ResourceProvider
|
||||
$match = Compare-Object $rpOperationsExclusionList $rpWithNoOperations
|
||||
if ($match -and ($match | Where-Object {$_.SideIndicator -eq "=>"}))
|
||||
{
|
||||
$missed = ($match | Where-Object {$_.SideIndicator -eq "=>"}).InputObject
|
||||
throw [System.Exception] "Some Resource Providers have zero Provider Operations. Number of Resource Providers with zero Provider Operations - $($missed.Count). Resource Providers with zero Provider Operations - $missed"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'AssignReaderRole' -Description "Assign Reader role to Service Principle - $($servicePrincipal.DisplayName)" -UsecaseBlock `
|
||||
{
|
||||
$readerRole = Get-AzureRmRoleDefinition -Name Reader
|
||||
$subscriptionID = (Get-AzureRmSubscription -SubscriptionName $tenantSubscriptionName).SubscriptionId
|
||||
$allAssignedRoles = Get-AzureRmRoleAssignment -ObjectId $servicePrincipal.Id -ErrorAction Stop
|
||||
if ($subscriptionID -and $readerRole -and (-not $allAssignedRoles -or ($allAssignedRoles -and -not ($allAssignedRoles | Where-Object {$_.RoleDefinitionName -eq $readerRole.Name}))))
|
||||
{
|
||||
New-AzureRmRoleAssignment -Scope "/Subscriptions/$subscriptionID" -RoleDefinitionName $readerRole.Name -ObjectId $servicePrincipal.Id -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'VerifyReaderRoleAssignment' -Description "Verify if the Service Principle has got Reader role assigned successfully" -UsecaseBlock `
|
||||
{
|
||||
$readerRole = Get-AzureRmRoleDefinition -Name Reader
|
||||
$subscriptionID = (Get-AzureRmSubscription -SubscriptionName $tenantSubscriptionName).SubscriptionId
|
||||
if ($subscriptionID -and $readerRole -and (-not (Get-AzureRmRoleAssignment -RoleDefinitionName $readerRole.Name -Scope "/Subscriptions/$subscriptionID" -ErrorAction Stop)))
|
||||
{
|
||||
throw [System.Exception] "Unable to assign role ($readerRole.Name) to Service Principle ($servicePrincipal.Id) for subscription $tenantSubscriptionName"
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'RemoveReaderRoleAssignment' -Description "Remove Reader role assignment from Service Principle - $($servicePrincipal.DisplayName)" -UsecaseBlock `
|
||||
{
|
||||
$readerRole = Get-AzureRmRoleDefinition -Name Reader
|
||||
$subscriptionID = (Get-AzureRmSubscription -SubscriptionName $tenantSubscriptionName).SubscriptionId
|
||||
if ($subscriptionID -and $readerRole -and (Get-AzureRmRoleAssignment -RoleDefinitionName $readerRole.Name -Scope "/Subscriptions/$subscriptionID" -ErrorAction Stop))
|
||||
{
|
||||
Remove-AzureRmRoleAssignment -Scope "/Subscriptions/$subscriptionID" -RoleDefinitionName $readerRole.Name -ObjectId $servicePrincipal.Id -Force -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'CustomRoleDefinition' -Description "Create a custom Role Definition - $customRoleName" -UsecaseBlock `
|
||||
{
|
||||
$subscriptionID = (Get-AzureRmSubscription -SubscriptionName $tenantSubscriptionName).SubscriptionId
|
||||
if (Get-AzureRmRoleDefinition -Name $customRoleName)
|
||||
{
|
||||
Remove-AzureRmRoleDefinition -Name $customRoleName -Scope "/Subscriptions/$subscriptionID" -Force -ErrorAction Stop
|
||||
}
|
||||
$role = Get-AzureRmRoleDefinition -Name Reader
|
||||
$role.Id = $null
|
||||
$role.Name = $customRoleName
|
||||
$role.Description = "Custom role definition for Canary"
|
||||
$role.Actions.Clear()
|
||||
$role.Actions.Add("Microsoft.Authorization/*/Read")
|
||||
$role.AssignableScopes.Clear()
|
||||
$role.AssignableScopes.Add("/Subscriptions/$subscriptionID")
|
||||
New-AzureRmRoleDefinition -Role $role -ErrorAction Stop
|
||||
if (-not (Get-AzureRmRoleDefinition -Name $customRoleName -Scope "/Subscriptions/$subscriptionID" -ErrorAction Stop))
|
||||
{
|
||||
throw [System.Exception] "Unable to create custom role definition ($customRoleName) for subscription $tenantSubscriptionName"
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'ListRoleDefinitionsAfterCustomRoleCreation' -Description "List existing Role Definitions" -UsecaseBlock `
|
||||
{
|
||||
$availableRoles = Get-AzureRmRoleDefinition -ErrorAction Stop
|
||||
if (-not $availableRoles)
|
||||
{
|
||||
throw [System.Exception] "No roles are available."
|
||||
}
|
||||
else
|
||||
{
|
||||
$availableRoles
|
||||
$availableRolesNames = $availableRoles.Name
|
||||
$mustHaveRoles = @("Owner", "Reader", "Contributor")
|
||||
$match = Compare-Object $mustHaveRoles $availableRolesNames
|
||||
if ($match -and ($match | Where-Object {$_.SideIndicator -eq "<="}))
|
||||
{
|
||||
$notAvailableRoles = ($match | Where-Object {$_.SideIndicator -eq "<="}).InputObject
|
||||
throw [System.Exception] "Some must have Role Definitions are not available. Number of missing Role Definitions - $($notAvailableRoles.Count). Missing Role Definitions - $notAvailableRoles"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'RemoveCustomRoleDefinition' -Description "Remove custom role definition - $customRoleName" -UsecaseBlock `
|
||||
{
|
||||
$subscriptionID = (Get-AzureRmSubscription -SubscriptionName $tenantSubscriptionName).SubscriptionId
|
||||
if(Get-AzureRmRoleDefinition -Name $customRoleName -Scope "/Subscriptions/$subscriptionID" -ErrorAction Stop)
|
||||
{
|
||||
Remove-AzureRmRoleDefinition -Name $customRoleName -Scope "/Subscriptions/$subscriptionID" -Force -ErrorAction Stop
|
||||
}
|
||||
else
|
||||
{
|
||||
throw [System.Exception] "Custom role definition ($customRoleName) for subscription $tenantSubscriptionName is not available"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'RegisterResourceProviders' -Description "Register resource providers" -UsecaseBlock `
|
||||
{
|
||||
Get-AzureRmResourceProvider -ListAvailable | Register-AzureRmResourceProvider -Force
|
||||
|
@ -440,40 +715,69 @@ while ($runCount -le $NumberOfIterations)
|
|||
New-AzureRmResourceGroup -Name $CanaryVMRG -Location $ResourceLocation -ErrorAction Stop
|
||||
}
|
||||
|
||||
$pirQueryRes = Invoke-Usecase -Name 'QueryImagesFromPIR' -Description "Queries the images in Platform Image Repository to retrieve the OS Version to deploy on the VMs" -UsecaseBlock `
|
||||
{
|
||||
$osVersion = ""
|
||||
[boolean]$linuxImgExists = $false
|
||||
$sw = [system.diagnostics.stopwatch]::startNew()
|
||||
while (([string]::IsNullOrEmpty($osVersion)) -and ($sw.ElapsedMilliseconds -lt 300000))
|
||||
{
|
||||
# Returns all the images that are available in the PIR
|
||||
$pirImages = Get-AzureRmVMImagePublisher -Location $ResourceLocation | Get-AzureRmVMImageOffer | Get-AzureRmVMImageSku | Get-AzureRMVMImage | Get-AzureRmVMImage
|
||||
|
||||
foreach($image in $pirImages)
|
||||
{
|
||||
# Canary specific check to see if the required Ubuntu image was successfully uploaded and available in PIR
|
||||
if ($image.PublisherName.Equals("Canonical") -and $image.Offer.Equals("UbuntuServer") -and $image.Skus.Equals($LinuxOSSku))
|
||||
{
|
||||
$linuxImgExists = $true
|
||||
}
|
||||
|
||||
if ($image.PublisherName.Equals("MicrosoftWindowsServer") -and $image.Offer.Equals("WindowsServer") -and $image.Skus.Equals("2016-Datacenter-Core"))
|
||||
{
|
||||
$osVersion = "2016-Datacenter-Core"
|
||||
}
|
||||
elseif ($image.PublisherName.Equals("MicrosoftWindowsServer") -and $image.Offer.Equals("WindowsServer") -and $image.Skus.Equals("2016-Datacenter"))
|
||||
{
|
||||
$osVersion = "2016-Datacenter"
|
||||
}
|
||||
elseif ($image.PublisherName.Equals("MicrosoftWindowsServer") -and $image.Offer.Equals("WindowsServer") -and $image.Skus.Equals("2012-R2-Datacenter"))
|
||||
{
|
||||
$osVersion = "2012-R2-Datacenter"
|
||||
}
|
||||
}
|
||||
Start-Sleep -Seconds 20
|
||||
}
|
||||
$sw.Stop()
|
||||
if (($linuxUpload) -and (-not $linuxImgExists))
|
||||
{
|
||||
throw [System.Exception] "Unable to find Ubuntu image (Ubuntu $LinuxOSSku) in PIR or failed to retrieve the image from PIR"
|
||||
}
|
||||
if ([string]::IsNullOrEmpty($osVersion))
|
||||
{
|
||||
throw [System.Exception] "Unable to find windows image in PIR or failed to retrieve the image from PIR"
|
||||
}
|
||||
$osVersion, $linuxImgExists
|
||||
}
|
||||
[string]$osVersion = $pirQueryRes[2]
|
||||
[boolean]$linuxImgExists = $pirQueryRes[3]
|
||||
|
||||
Invoke-Usecase -Name 'DeployARMTemplate' -Description "Deploy ARM template to setup the virtual machines" -UsecaseBlock `
|
||||
{
|
||||
$kvSecretId = (Get-AzureKeyVaultSecret -VaultName $keyVaultName -Name $kvSecretName -IncludeVersions -ErrorAction Stop).Id
|
||||
$osVersion = ""
|
||||
if (Get-AzureRmVMImage -Location $ResourceLocation -PublisherName "MicrosoftWindowsServer" -Offer "WindowsServer" -Sku "2016-Datacenter-Core" -ErrorAction SilentlyContinue)
|
||||
{
|
||||
$osVersion = "2016-Datacenter-Core"
|
||||
}
|
||||
elseif (Get-AzureRmVMImage -Location $ResourceLocation -PublisherName "MicrosoftWindowsServer" -Offer "WindowsServer" -Sku "2016-Datacenter" -ErrorAction SilentlyContinue)
|
||||
{
|
||||
$osVersion = "2016-Datacenter"
|
||||
}
|
||||
elseif (Get-AzureRmVMImage -Location $ResourceLocation -PublisherName "MicrosoftWindowsServer" -Offer "WindowsServer" -Sku "2012-R2-Datacenter" -ErrorAction SilentlyContinue)
|
||||
{
|
||||
$osVersion = "2012-R2-Datacenter"
|
||||
}
|
||||
$linuxImgExists = $false
|
||||
if (Get-AzureRmVMImage -Location $ResourceLocation -PublisherName "Canonical" -Offer "UbuntuServer" -Sku $LinuxOSSku -ErrorAction SilentlyContinue)
|
||||
{
|
||||
$linuxImgExists = $true
|
||||
}
|
||||
|
||||
$templateDeploymentName = "CanaryVMDeployment"
|
||||
$parameters = @{"VMAdminUserName" = $VMAdminUserName;
|
||||
"VMAdminUserPassword" = $VMAdminUserPass;
|
||||
"ASCanaryUtilRG" = $CanaryUtilitiesRG;
|
||||
"ASCanaryUtilSA" = $storageAccName;
|
||||
"ASCanaryUtilSC" = $storageCtrName;
|
||||
"vaultName" = $keyvaultName;
|
||||
"windowsOSVersion" = $osVersion;
|
||||
"secretUrlWithVersion" = $kvSecretId;
|
||||
"LinuxImagePublisher" = $linuxImagePublisher;
|
||||
"LinuxImageOffer" = $linuxImageOffer;
|
||||
"LinuxImageSku" = $LinuxOSSku}
|
||||
$parameters = @{"VMAdminUserName" = $VMAdminUserName;
|
||||
"VMAdminUserPassword" = $VMAdminUserPass;
|
||||
"ASCanaryUtilRG" = $CanaryUtilitiesRG;
|
||||
"ASCanaryUtilSA" = $storageAccName;
|
||||
"ASCanaryUtilSC" = $storageCtrName;
|
||||
"vaultName" = $keyvaultName;
|
||||
"windowsOSVersion" = $osVersion;
|
||||
"secretUrlWithVersion" = $kvSecretId;
|
||||
"LinuxImagePublisher" = $linuxImagePublisher;
|
||||
"LinuxImageOffer" = $linuxImageOffer;
|
||||
"LinuxImageSku" = $LinuxOSSku;
|
||||
"storageAccountEndPoint" = "https://$EnvironmentDomainFQDN/"}
|
||||
if (-not $linuxImgExists)
|
||||
{
|
||||
$templateError = Test-AzureRmResourceGroupDeployment -ResourceGroupName $CanaryVMRG -TemplateFile $PSScriptRoot\azuredeploy.json -TemplateParameterObject $parameters
|
||||
|
@ -496,6 +800,12 @@ while ($runCount -le $NumberOfIterations)
|
|||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'RetrieveResourceDeploymentTimes' -Description "Retrieves the resources deployment times from the ARM template deployment" -UsecaseBlock `
|
||||
{
|
||||
$templateDeploymentName = "CanaryVMDeployment"
|
||||
(Get-AzureRmResourceGroupDeploymentOperation -Deploymentname $templateDeploymentName -ResourceGroupName $CanaryVMRG).Properties | Select-Object ProvisioningOperation,Duration,ProvisioningState,StatusCode,TargetResource | Format-Table -AutoSize
|
||||
}
|
||||
|
||||
$canaryWindowsVMList = @()
|
||||
$canaryWindowsVMList = Invoke-Usecase -Name 'QueryTheVMsDeployed' -Description "Queries for the VMs that were deployed using the ARM template" -UsecaseBlock `
|
||||
{
|
||||
|
@ -559,18 +869,24 @@ while ($runCount -le $NumberOfIterations)
|
|||
if (($pubVMObject = Get-AzureRmVM -ResourceGroupName $CanaryVMRG -Name $publicVMName -ErrorAction Stop) -and ($pvtVMObject = Get-AzureRmVM -ResourceGroupName $CanaryVMRG -Name $privateVMName -ErrorAction Stop))
|
||||
{
|
||||
Set-item wsman:\localhost\Client\TrustedHosts -Value $publicVMIP -Force -Confirm:$false
|
||||
if ($publicVMSession = New-PSSession -ComputerName $publicVMIP -Credential $vmCreds -ErrorAction Stop)
|
||||
$sw = [system.diagnostics.stopwatch]::startNew()
|
||||
while (-not($publicVMSession = New-PSSession -ComputerName $publicVMIP -Credential $vmCreds -ErrorAction SilentlyContinue)){if (($sw.ElapsedMilliseconds -gt 240000) -and (-not($publicVMSession))){$sw.Stop(); throw [System.Exception]"Unable to establish a remote session to the tenant VM using public IP: $publicVMIP"}; Start-Sleep -Seconds 15}
|
||||
if ($publicVMSession)
|
||||
{
|
||||
Invoke-Command -Session $publicVMSession -Script{param ($privateIP) Set-item wsman:\localhost\Client\TrustedHosts -Value $privateIP -Force -Confirm:$false} -ArgumentList $privateVMIP | Out-Null
|
||||
$privateVMResponseFromRemoteSession = Invoke-Command -Session $publicVMSession -Script{param ($privateIP, $vmCreds, $scriptToRun) $privateSess = New-PSSession -ComputerName $privateIP -Credential $vmCreds; Invoke-Command -Session $privateSess -Script{param($script) Invoke-Expression $script} -ArgumentList $scriptToRun} -ArgumentList $privateVMIP, $vmCreds, $vmCommsScriptBlock
|
||||
$privateVMResponseFromRemoteSession = Invoke-Command -Session $publicVMSession -Script{param ($privateIP, $vmCreds, $scriptToRun) $sw = [system.diagnostics.stopwatch]::startNew(); while (-not($privateSess = New-PSSession -ComputerName $privateIP -Credential $vmCreds -ErrorAction SilentlyContinue)){if (($sw.ElapsedMilliseconds -gt 240000) -and (-not($privateSess))){$sw.Stop(); throw [System.Exception]"Unable to establish a remote session to the tenant VM using private IP: $privateIP"}; Start-Sleep -Seconds 15}; Invoke-Command -Session $privateSess -Script{param($script) Invoke-Expression $script} -ArgumentList $scriptToRun} -ArgumentList $privateVMIP, $vmCreds, $vmCommsScriptBlock -ErrorVariable remoteExecError 2>$null
|
||||
$publicVMSession | Remove-PSSession -Confirm:$false
|
||||
if ($remoteExecError)
|
||||
{
|
||||
throw [System.Exception]"$remoteExecError"
|
||||
}
|
||||
if ($privateVMResponseFromRemoteSession)
|
||||
{
|
||||
$publicVMSession | Remove-PSSession -Confirm:$false
|
||||
$privateVMResponseFromRemoteSession
|
||||
}
|
||||
else
|
||||
{
|
||||
throw [System.Exception]"Public VM was not able to talk to the Private VM via the private IP"
|
||||
throw [System.Exception]"The expected certificate from KV was not found on the tenant VM with private IP: $privateVMIP"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -707,18 +1023,24 @@ while ($runCount -le $NumberOfIterations)
|
|||
if (($pubVMObject = Get-AzureRmVM -ResourceGroupName $CanaryVMRG -Name $publicVMName -ErrorAction Stop) -and ($pvtVMObject = Get-AzureRmVM -ResourceGroupName $CanaryVMRG -Name $privateVMName -ErrorAction Stop))
|
||||
{
|
||||
Set-item wsman:\localhost\Client\TrustedHosts -Value $publicVMIP -Force -Confirm:$false
|
||||
if ($publicVMSession = New-PSSession -ComputerName $publicVMIP -Credential $vmCreds -ErrorAction Stop)
|
||||
$sw = [system.diagnostics.stopwatch]::startNew()
|
||||
while (-not($publicVMSession = New-PSSession -ComputerName $publicVMIP -Credential $vmCreds -ErrorAction SilentlyContinue)){if (($sw.ElapsedMilliseconds -gt 240000) -and (-not($publicVMSession))){$sw.Stop(); throw [System.Exception]"Unable to establish a remote session to the tenant VM using public IP: $publicVMIP"}; Start-Sleep -Seconds 15}
|
||||
if ($publicVMSession)
|
||||
{
|
||||
Invoke-Command -Session $publicVMSession -Script{param ($privateIP) Set-item wsman:\localhost\Client\TrustedHosts -Value $privateIP -Force -Confirm:$false} -ArgumentList $privateVMIP | Out-Null
|
||||
$privateVMResponseFromRemoteSession = Invoke-Command -Session $publicVMSession -Script{param ($privateIP, $vmCreds, $scriptToRun) $privateSess = New-PSSession -ComputerName $privateIP -Credential $vmCreds; Invoke-Command -Session $privateSess -Script{param($script) Invoke-Expression $script} -ArgumentList $scriptToRun} -ArgumentList $privateVMIP, $vmCreds, $vmCommsScriptBlock
|
||||
$privateVMResponseFromRemoteSession = Invoke-Command -Session $publicVMSession -Script{param ($privateIP, $vmCreds, $scriptToRun) $sw = [system.diagnostics.stopwatch]::startNew(); while (-not($privateSess = New-PSSession -ComputerName $privateIP -Credential $vmCreds -ErrorAction SilentlyContinue)){if (($sw.ElapsedMilliseconds -gt 240000) -and (-not($privateSess))){$sw.Stop(); throw [System.Exception]"Unable to establish a remote session to the tenant VM using private IP: $privateIP"}; Start-Sleep -Seconds 15}; Invoke-Command -Session $privateSess -Script{param($script) Invoke-Expression $script} -ArgumentList $scriptToRun} -ArgumentList $privateVMIP, $vmCreds, $vmCommsScriptBlock -ErrorVariable remoteExecError 2>$null
|
||||
$publicVMSession | Remove-PSSession -Confirm:$false
|
||||
if ($remoteExecError)
|
||||
{
|
||||
throw [System.Exception]"$remoteExecError"
|
||||
}
|
||||
if ($privateVMResponseFromRemoteSession)
|
||||
{
|
||||
$publicVMSession | Remove-PSSession -Confirm:$false
|
||||
$privateVMResponseFromRemoteSession
|
||||
}
|
||||
else
|
||||
{
|
||||
throw [System.Exception]"Public VM was not able to talk to the Private VM via the private IP"
|
||||
throw [System.Exception]"Host name could not be retrieved from the tenant VM with private IP: $privateVMIP"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -743,69 +1065,82 @@ while ($runCount -le $NumberOfIterations)
|
|||
|
||||
if (-not $NoCleanup)
|
||||
{
|
||||
Invoke-Usecase -Name 'DeleteVMWithPrivateIP' -Description "Delete the VM with private IP" -UsecaseBlock `
|
||||
if (-not ($NoCleanupOnFailure -and (Get-CanaryFailureStatus)))
|
||||
{
|
||||
if ($vmObject = Get-AzureRmVM -ResourceGroupName $CanaryVMRG -Name $privateVMName -ErrorAction Stop)
|
||||
Invoke-Usecase -Name 'DeleteVMWithPrivateIP' -Description "Delete the VM with private IP" -UsecaseBlock `
|
||||
{
|
||||
$deleteVM = $vmObject | Remove-AzureRmVM -Force -ErrorAction Stop
|
||||
if (-not (($deleteVM.StatusCode -eq "OK") -and ($deleteVM.IsSuccessStatusCode)))
|
||||
if ($vmObject = Get-AzureRmVM -ResourceGroupName $CanaryVMRG -Name $privateVMName -ErrorAction Stop)
|
||||
{
|
||||
throw [System.Exception]"Failed to delete the VM $privateVMName"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'DeleteVMResourceGroup' -Description "Delete the resource group that contains all the VMs and corresponding resources" -UsecaseBlock `
|
||||
{
|
||||
if ($removeRG = Get-AzureRmResourceGroup -Name $CanaryVMRG -ErrorAction Stop)
|
||||
{
|
||||
$removeRG | Remove-AzureRmResourceGroup -Force -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'DeleteUtilitiesResourceGroup' -Description "Delete the resource group that contains all the utilities and corresponding resources" -UsecaseBlock `
|
||||
{
|
||||
if ($removeRG = Get-AzureRmResourceGroup -Name $CanaryUtilitiesRG -ErrorAction Stop)
|
||||
{
|
||||
$removeRG | Remove-AzureRmResourceGroup -Force -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
if ($TenantAdminCredentials)
|
||||
{
|
||||
Invoke-Usecase -Name 'TenantRelatedcleanup' -Description "Remove all the tenant related stuff" -UsecaseBlock `
|
||||
{
|
||||
Invoke-Usecase -Name 'DeleteTenantSubscriptions' -Description "Remove all the tenant related subscriptions" -UsecaseBlock `
|
||||
{
|
||||
if ($subs = Get-AzureRmTenantSubscription -ErrorAction Stop | Where-Object DisplayName -eq $tenantSubscriptionName)
|
||||
$deleteVM = $vmObject | Remove-AzureRmVM -Force -ErrorAction Stop
|
||||
if (-not (($deleteVM.StatusCode -eq "OK") -and ($deleteVM.IsSuccessStatusCode)))
|
||||
{
|
||||
Remove-AzureRmTenantSubscription -TargetSubscriptionId $subs.SubscriptionId -ErrorAction Stop
|
||||
}
|
||||
if ($subs = Get-AzureRmTenantSubscription -ErrorAction Stop | Where-Object DisplayName -eq $canaryDefaultTenantSubscription)
|
||||
{
|
||||
Remove-AzureRmTenantSubscription -TargetSubscriptionId $subs.SubscriptionId -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'LoginToAzureStackEnvAsSvcAdminForCleanup' -Description "Login to $SvcAdminEnvironmentName as service administrator to remove the subscription resource group" -UsecaseBlock `
|
||||
{
|
||||
Add-AzureRmAccount -EnvironmentName $SvcAdminEnvironmentName -Credential $ServiceAdminCredentials -TenantId $TenantID -ErrorAction Stop
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'DeleteSubscriptionResourceGroup' -Description "Delete the resource group that contains subscription resources" -UsecaseBlock `
|
||||
{
|
||||
if ($removeRG = Get-AzureRmResourceGroup -Name $subscriptionRGName -ErrorAction Stop)
|
||||
{
|
||||
$removeRG | Remove-AzureRmResourceGroup -Force -ErrorAction Stop
|
||||
throw [System.Exception]"Failed to delete the VM $privateVMName"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'DeleteVMResourceGroup' -Description "Delete the resource group that contains all the VMs and corresponding resources" -UsecaseBlock `
|
||||
{
|
||||
if ($removeRG = Get-AzureRmResourceGroup -Name $CanaryVMRG -ErrorAction Stop)
|
||||
{
|
||||
$removeRG | Remove-AzureRmResourceGroup -Force -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'DeleteUtilitiesResourceGroup' -Description "Delete the resource group that contains all the utilities and corresponding resources" -UsecaseBlock `
|
||||
{
|
||||
if ($removeRG = Get-AzureRmResourceGroup -Name $CanaryUtilitiesRG -ErrorAction Stop)
|
||||
{
|
||||
$removeRG | Remove-AzureRmResourceGroup -Force -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
if (($TenantAdminCredentials) -or ($listAvl))
|
||||
{
|
||||
Invoke-Usecase -Name 'TenantRelatedcleanup' -Description "Remove all the tenant related resources" -UsecaseBlock `
|
||||
{
|
||||
Invoke-Usecase -Name 'DeleteTenantSubscriptions' -Description "Remove all the tenant related subscriptions" -UsecaseBlock `
|
||||
{
|
||||
if ($subs = Get-AzureRmTenantSubscription -ErrorAction Stop | Where-Object DisplayName -eq $tenantSubscriptionName)
|
||||
{
|
||||
Remove-AzureRmTenantSubscription -TargetSubscriptionId $subs.SubscriptionId -ErrorAction Stop
|
||||
}
|
||||
if ($subs = Get-AzureRmTenantSubscription -ErrorAction Stop | Where-Object DisplayName -eq $canaryDefaultTenantSubscription)
|
||||
{
|
||||
Remove-AzureRmTenantSubscription -TargetSubscriptionId $subs.SubscriptionId -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'LoginToAzureStackEnvAsSvcAdminForCleanup' -Description "Login to $SvcAdminEnvironmentName as service administrator to remove the subscription resource group" -UsecaseBlock `
|
||||
{
|
||||
Add-AzureRmAccount -EnvironmentName $SvcAdminEnvironmentName -Credential $ServiceAdminCredentials -TenantId $TenantID -ErrorAction Stop
|
||||
}
|
||||
|
||||
Invoke-Usecase -Name 'RemoveLinuxImageFromPIR' -Description "Remove the Linux image uploaded during setup from the Platform Image Respository" -UsecaseBlock `
|
||||
{
|
||||
if (Get-AzureRmVMImage -Location $ResourceLocation -PublisherName $linuxImagePublisher -Offer $linuxImageOffer -Sku $LinuxOSSku -ErrorAction SilentlyContinue)
|
||||
{
|
||||
Remove-AzsVMImage -publisher $linuxImagePublisher -offer $linuxImageOffer -sku $LinuxOSSku -version $linuxImageVersion -Location $ResourceLocation -Force
|
||||
}
|
||||
}
|
||||
Invoke-Usecase -Name 'DeleteSubscriptionResourceGroup' -Description "Delete the resource group that contains subscription resources" -UsecaseBlock `
|
||||
{
|
||||
if ($removeRG = Get-AzureRmResourceGroup -Name $subscriptionRGName -ErrorAction Stop)
|
||||
{
|
||||
$removeRG | Remove-AzureRmResourceGroup -Force -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
End-Scenario
|
||||
$runCount += 1
|
||||
Get-CanaryResult
|
||||
if (-not $ListAvailable)
|
||||
{
|
||||
Get-CanaryResult
|
||||
}
|
||||
}
|
||||
|
||||
if ($NumberOfIterations -gt 1)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
$Global:ContinueOnFailure = $false
|
||||
$Global:JSONLogFile = "Run-Canary.JSON"
|
||||
$Global:TxtLogFile = "AzureStackCanaryLog.Log"
|
||||
$Global:wttLogFileName= ""
|
||||
$Global:ContinueOnFailure = $false
|
||||
$Global:JSONLogFile = "Run-Canary.JSON"
|
||||
$Global:TxtLogFile = "AzureStackCanaryLog.Log"
|
||||
$Global:wttLogFileName = ""
|
||||
$Global:listAvailableUsecases = $false
|
||||
$Global:exclusionList = @()
|
||||
if (Test-Path -Path "$PSScriptRoot\..\WTTLog.ps1")
|
||||
{
|
||||
Import-Module -Name "$PSScriptRoot\..\WTTLog.ps1" -Force
|
||||
|
@ -10,7 +12,7 @@ if (Test-Path -Path "$PSScriptRoot\..\WTTLog.ps1")
|
|||
|
||||
$CurrentUseCase = @{}
|
||||
[System.Collections.Stack] $UseCaseStack = New-Object System.Collections.Stack
|
||||
filter timestamp {"$(Get-Date -Format HH:mm:ss.ffff): $_"}
|
||||
filter timestamp {"$(Get-Date -Format "yyyy-MM-dd HH:mm:ss.ffff") $_"}
|
||||
|
||||
|
||||
function Log-Info
|
||||
|
@ -49,14 +51,11 @@ function Log-JSONReport
|
|||
[string] $Message
|
||||
)
|
||||
if ($Message)
|
||||
{
|
||||
if ($Message.Contains(": ["))
|
||||
{
|
||||
$time = $Message.Substring(0, $Message.IndexOf(": ["))
|
||||
}
|
||||
{
|
||||
if ($Message.Contains("[START]"))
|
||||
{
|
||||
$name = $Message.Substring($Message.LastIndexOf(":") + 1).Trim().Replace("######", "").Trim()
|
||||
$time = $Message.Substring(0, $Message.IndexOf("[")).Trim()
|
||||
$name = $Message.Substring($Message.LastIndexOf(":") + 1).Trim()
|
||||
if ($UseCaseStack.Count)
|
||||
{
|
||||
$nestedUseCase = @{
|
||||
|
@ -79,14 +78,19 @@ function Log-JSONReport
|
|||
}
|
||||
elseif ($Message.Contains("[END]"))
|
||||
{
|
||||
$time = $Message.Substring(0, $Message.IndexOf("[")).Trim()
|
||||
$result = ""
|
||||
if ($UseCaseStack.Peek().UseCase -and ($UseCaseStack.Peek().UseCase | Where-Object {$_.Result -eq "FAIL"}))
|
||||
{
|
||||
$result = "FAIL"
|
||||
}
|
||||
else
|
||||
elseif ($Message.Contains("[RESULT = PASS]"))
|
||||
{
|
||||
$result = $Message.Substring($Message.LastIndexOf("=") + 1).Trim().Replace("] ######", "").Trim()
|
||||
$result = "PASS"
|
||||
}
|
||||
elseif ($Message.Contains("[RESULT = FAIL]"))
|
||||
{
|
||||
$result = "FAIL"
|
||||
}
|
||||
$UseCaseStack.Peek().Add("Result", $result)
|
||||
$UseCaseStack.Peek().Add("EndTime", $time)
|
||||
|
@ -114,11 +118,53 @@ function Log-JSONReport
|
|||
|
||||
function Get-CanaryResult
|
||||
{
|
||||
$logContent = Get-Content -Raw -Path $Global:JSONLogFile | ConvertFrom-Json
|
||||
Log-Info ($logContent.UseCases | Format-Table -AutoSize @{Expression = {$_.Name}; Label = "Name"; Align = "Left"},
|
||||
@{Expression = {$_.Result}; Label="Result"; Align = "Left"},
|
||||
@{Expression = {((Get-Date $_.EndTime) - (Get-Date $_.StartTime)).TotalSeconds}; Label = "Duration`n[Seconds]"; Align = "Left"},
|
||||
@{Expression = {$_.Description}; Label = "Description"; Align = "Left"})
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[parameter(Mandatory=$false)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$LogFilename
|
||||
)
|
||||
|
||||
if ($LogFilename)
|
||||
{
|
||||
$logContent = Get-Content -Raw -Path $LogFilename | ConvertFrom-Json
|
||||
}
|
||||
else
|
||||
{
|
||||
$logContent = Get-Content -Raw -Path $Global:JSONLogFile | ConvertFrom-Json
|
||||
}
|
||||
$results = @()
|
||||
foreach ($usecase in $logContent.UseCases)
|
||||
{
|
||||
$ucObj = New-Object -TypeName PSObject
|
||||
if ([bool]($usecase.PSobject.Properties.name -match "UseCase"))
|
||||
{
|
||||
$ucObj | Add-Member -Type NoteProperty -Name Name -Value $usecase.Name
|
||||
$ucObj | Add-Member -Type NoteProperty -Name Result -Value $usecase.Result
|
||||
$ucObj | Add-Member -Type NoteProperty -Name "Duration`n[Seconds]" -Value ((Get-Date $usecase.EndTime) - (Get-Date $usecase.StartTime)).TotalSeconds
|
||||
$ucObj | Add-Member -Type NoteProperty -Name Description -Value $usecase.Description
|
||||
$results += $ucObj
|
||||
|
||||
foreach ($subusecase in $usecase.UseCase)
|
||||
{
|
||||
$ucObj = New-Object -TypeName PSObject
|
||||
$ucObj | Add-Member -Type NoteProperty -Name Name -Value ("|-- $($subusecase.Name)")
|
||||
$ucObj | Add-Member -Type NoteProperty -Name Result -Value $subusecase.Result
|
||||
$ucObj | Add-Member -Type NoteProperty -Name "Duration`n[Seconds]" -Value ((Get-Date $subusecase.EndTime) - (Get-Date $subusecase.StartTime)).TotalSeconds
|
||||
$ucObj | Add-Member -Type NoteProperty -Name Description -Value ("|-- $($subusecase.Description)")
|
||||
$results += $ucObj
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$ucObj | Add-Member -Type NoteProperty -Name Name -Value $usecase.Name
|
||||
$ucObj | Add-Member -Type NoteProperty -Name Result -Value $usecase.Result
|
||||
$ucObj | Add-Member -Type NoteProperty -Name "Duration`n[Seconds]" -Value ((Get-Date $usecase.EndTime) - (Get-Date $usecase.StartTime)).TotalSeconds
|
||||
$ucObj | Add-Member -Type NoteProperty -Name Description -Value $usecase.Description
|
||||
$results += $ucObj
|
||||
}
|
||||
}
|
||||
Log-Info($results | Format-Table -AutoSize)
|
||||
}
|
||||
|
||||
function Get-CanaryLonghaulResult
|
||||
|
@ -147,6 +193,16 @@ function Get-CanaryLonghaulResult
|
|||
@{Expression={$pCount = ($_.Group | Where-Object Result -eq "PASS").Count; $times = ($_.Group | Where-Object Result -eq "PASS" | ForEach-Object {((Get-Date $_.EndTime) - (Get-Date $_.StartTime)).TotalMilliseconds}); $avgTime = ($times | Measure-Object -Average).Average; $sd = 0; foreach ($time in $times){$sd += [math]::Pow(($time - $avgTime), 2)}; [math]::Round(([math]::Round([math]::Sqrt($sd/$pCount), 0)/$avgTime), 0) * 100};Label="RelativeStdDev`n[Goal: <50%]"; Align = "Left"}
|
||||
}
|
||||
|
||||
function Get-CanaryFailureStatus
|
||||
{
|
||||
$logContent = Get-Content -Raw -Path $Global:JSONLogFile | ConvertFrom-Json
|
||||
if ($logContent.Usecases.Result -contains "FAIL")
|
||||
{
|
||||
return $true
|
||||
}
|
||||
return $false
|
||||
}
|
||||
|
||||
function Start-Scenario
|
||||
{
|
||||
[CmdletBinding()]
|
||||
|
@ -161,7 +217,11 @@ function Start-Scenario
|
|||
[ValidateNotNullOrEmpty()]
|
||||
[string]$LogFilename,
|
||||
[parameter(Mandatory=$false)]
|
||||
[bool] $ContinueOnFailure = $false
|
||||
[bool]$ContinueOnFailure = $false,
|
||||
[parameter(Mandatory=$false)]
|
||||
[bool]$ListAvailable = $false,
|
||||
[parameter(Mandatory=$false)]
|
||||
[string[]]$ExclusionList
|
||||
)
|
||||
|
||||
if ($LogFileName)
|
||||
|
@ -181,14 +241,25 @@ function Start-Scenario
|
|||
{
|
||||
OpenWTTLogger $Global:wttLogFileName
|
||||
}
|
||||
|
||||
New-Item -Path $Global:JSONLogFile -Type File -Force
|
||||
New-Item -Path $Global:TxtLogFile -Type File -Force
|
||||
$jsonReport = @{
|
||||
"Scenario" = ($Name + "-" + $Type)
|
||||
"UseCases" = @()
|
||||
}
|
||||
$jsonReport | ConvertTo-Json -Depth 10 | Out-File -FilePath $Global:JSONLogFile
|
||||
if ($ListAvailable)
|
||||
{
|
||||
$Global:listAvailableUsecases = $true
|
||||
}
|
||||
if ($ExclusionList)
|
||||
{
|
||||
$Global:exclusionList = $ExclusionList
|
||||
}
|
||||
if (-not $ListAvailable)
|
||||
{
|
||||
New-Item -Path $Global:JSONLogFile -Type File -Force
|
||||
New-Item -Path $Global:TxtLogFile -Type File -Force
|
||||
$jsonReport = @{
|
||||
"Scenario" = ($Name + "-" + $Type)
|
||||
"UseCases" = @()
|
||||
}
|
||||
$jsonReport | ConvertTo-Json -Depth 10 | Out-File -FilePath $Global:JSONLogFile
|
||||
}
|
||||
|
||||
$Global:ContinueOnFailure = $ContinueOnFailure
|
||||
}
|
||||
|
||||
|
@ -214,7 +285,33 @@ function Invoke-Usecase
|
|||
[ValidateNotNullOrEmpty()]
|
||||
[ScriptBlock]$UsecaseBlock
|
||||
)
|
||||
Log-Info ("###### [START] Usecase: $Name ######`n")
|
||||
|
||||
if ($Global:listAvailableUsecases)
|
||||
{
|
||||
$parentUsecase = $Name
|
||||
if ((Get-PSCallStack)[1].Arguments.Contains($parentUsecase))
|
||||
{
|
||||
" `t"*([math]::Floor((Get-PSCallStack).Count/3)) + "|-- " + $Name
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
"`t" + $Name
|
||||
}
|
||||
if ($UsecaseBlock.ToString().Contains("Invoke-Usecase"))
|
||||
{
|
||||
try {Invoke-Command -ScriptBlock $UsecaseBlock -ErrorAction SilentlyContinue}
|
||||
catch {}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (($Global:exclusionList).Contains($Name))
|
||||
{
|
||||
Log-Info ("Skipping Usecase: $Name")
|
||||
return
|
||||
}
|
||||
Log-Info ("[START] Usecase: $Name`n")
|
||||
if ($Global:wttLogFileName)
|
||||
{
|
||||
StartTest "CanaryGate:$Name"
|
||||
|
@ -236,7 +333,7 @@ function Invoke-Usecase
|
|||
{
|
||||
EndTest "CanaryGate:$Name" $true
|
||||
}
|
||||
Log-Info ("###### [END] Usecase: $Name ###### [RESULT = PASS] ######`n")
|
||||
Log-Info ("[END] [RESULT = PASS] Usecase: $Name`n")
|
||||
return $result | Out-Null
|
||||
}
|
||||
catch [System.Exception]
|
||||
|
@ -245,7 +342,7 @@ function Invoke-Usecase
|
|||
Log-Info ("###### <FAULTING SCRIPTBLOCK> ######")
|
||||
Log-Info ("$UsecaseBlock")
|
||||
Log-Info ("###### </FAULTING SCRIPTBLOCK> ######")
|
||||
Log-Error ("###### [END] Usecase: $Name ###### [RESULT = FAIL] ######`n")
|
||||
Log-Error ("[END] [RESULT = FAIL] Usecase: $Name`n")
|
||||
if ($Global:wttLogFileName)
|
||||
{
|
||||
EndTest "CanaryGate:$Name" $false
|
||||
|
|
|
@ -4,14 +4,16 @@ Canary validator provides a breadth customer experience with the Azure Stack dep
|
|||
Instructions are relative to the .\CanaryValidator directory.
|
||||
Canary can be invoked either as Service Administrator or Tenant Administrator.
|
||||
|
||||
# Download Canary
|
||||
## Download Canary
|
||||
|
||||
```powershell
|
||||
Invoke-WebRequest https://github.com/Azure/AzureStack-Tools/archive/master.zip -OutFile master.zip
|
||||
Expand-Archive master.zip -DestinationPath . -Force
|
||||
Set-Location -Path ".\AzureStack-Tools-master\CanaryValidator" -PassThru
|
||||
```
|
||||
|
||||
# To execute Canary as Tenant Administrator (if Windows Server 2016 or Windows Server 2012-R2 images are already present in the PIR)
|
||||
## To execute Canary as Tenant Administrator (if Windows Server 2016 or Windows Server 2012-R2 images are already present in the PIR)
|
||||
|
||||
```powershell
|
||||
# Install-Module -Name 'AzureRm.Bootstrapper' -Scope CurrentUser
|
||||
# Install-AzureRmProfile -profile '2017-03-09-profile' -Force -Scope CurrentUser
|
||||
|
@ -21,7 +23,8 @@ $ServiceAdminCreds = New-Object System.Management.Automation.PSCredential "<Ser
|
|||
.\Canary.Tests.ps1 -TenantID "<TenantID from Azure Active Directory>" -AdminArmEndpoint "<Administrative ARM endpoint>" -ServiceAdminCredentials $ServiceAdminCreds -TenantArmEndpoint "<Tenant ARM endpoint>" -TenantAdminCredentials $TenantAdminCreds
|
||||
```
|
||||
|
||||
# To execute Canary as Tenant Administrator (if Windows Server 2016 or Windows Server 2012-R2 images are not present in PIR)
|
||||
## To execute Canary as Tenant Administrator (if Windows Server 2016 or Windows Server 2012-R2 images are not present in PIR)
|
||||
|
||||
```powershell
|
||||
# Download the WS2016 ISO image from: https://www.microsoft.com/en-us/evalcenter/evaluate-windows-server-2016, and place it on your local machine
|
||||
# Install-Module -Name 'AzureRm.Bootstrapper' -Scope CurrentUser
|
||||
|
@ -32,7 +35,8 @@ $ServiceAdminCreds = New-Object System.Management.Automation.PSCredential "<Ser
|
|||
.\Canary.Tests.ps1 -TenantID "<TenantID from Azure Active Directory>" -AdminArmEndpoint "<Administrative ARM endpoint>" -ServiceAdminCredentials $ServiceAdminCreds -TenantArmEndpoint "<Tenant ARM endpoint>" -TenantAdminCredentials $TenantAdminCreds -WindowsISOPath "<path where the WS2016 ISO is present>"
|
||||
```
|
||||
|
||||
# To execute Canary as Service Administrator
|
||||
## To execute Canary as Service Administrator
|
||||
|
||||
```powershell
|
||||
# Install-Module -Name 'AzureRm.Bootstrapper' -Scope CurrentUser
|
||||
# Install-AzureRmProfile -profile '2017-03-09-profile' -Force -Scope CurrentUser
|
||||
|
@ -40,10 +44,110 @@ $ServiceAdminCreds = New-Object System.Management.Automation.PSCredential "<Ser
|
|||
$ServiceAdminCreds = New-Object System.Management.Automation.PSCredential "<Service Admin username>", (ConvertTo-SecureString "<Service Admin password>" -AsPlainText -Force)
|
||||
.\Canary.Tests.ps1 -TenantID "<TenantID from Azure Active Directory>" -AdminArmEndpoint "<Administrative ARM endpoint>" -ServiceAdminCredentials $ServiceAdminCreds
|
||||
```
|
||||
# Reading the results & logs
|
||||
|
||||
## To list the usecases in Canary
|
||||
|
||||
```powershell
|
||||
# Install-Module -Name 'AzureRm.Bootstrapper' -Scope CurrentUser
|
||||
# Install-AzureRmProfile -profile '2017-03-09-profile' -Force -Scope CurrentUser
|
||||
# Install-Module -Name AzureStack -RequiredVersion 1.2.9 -Scope CurrentUser
|
||||
.\Canary.Tests.ps1 -ListAvailable
|
||||
|
||||
Sample output:
|
||||
PS C:\AzureStack-Tools-vnext\CanaryValidator> .\Canary.Tests.ps1 -ListAvailable
|
||||
List of scenarios in Canary:
|
||||
CreateAdminAzureStackEnv
|
||||
LoginToAzureStackEnvAsSvcAdmin
|
||||
SelectDefaultProviderSubscription
|
||||
ListFabricResourceProviderInfo
|
||||
|--GetAzureStackInfraRole
|
||||
|--GetAzureStackInfraRoleInstance
|
||||
|--GetAzureStackLogicalNetwork
|
||||
|--GetAzureStackStorageCapacity
|
||||
|--GetAzureStackStorageShare
|
||||
|--GetAzureStackScaleUnit
|
||||
|--GetAzureStackScaleUnitNode
|
||||
|--GetAzureStackIPPool
|
||||
|--GetAzureStackMacPool
|
||||
|--GetAzureStackGatewayPool
|
||||
|--GetAzureStackSLBMux
|
||||
|--GetAzureStackGateway
|
||||
ListHealthResourceProviderAlerts
|
||||
|--GetAzureStackAlert
|
||||
ListUpdatesResourceProviderInfo
|
||||
|--GetAzureStackUpdateSummary
|
||||
|--GetAzureStackUpdateToApply
|
||||
CreateTenantAzureStackEnv
|
||||
CreateResourceGroupForTenantSubscription
|
||||
CreateTenantPlan
|
||||
CreateTenantOffer
|
||||
CreateTenantDefaultManagedSubscription
|
||||
LoginToAzureStackEnvAsTenantAdmin
|
||||
CreateTenantSubscription
|
||||
RoleAssignmentAndCustomRoleDefinition
|
||||
|--ListAssignedRoles
|
||||
|--ListExistingRoleDefinitions
|
||||
|--GetProviderOperations
|
||||
|--AssignReaderRole
|
||||
|--VerifyReaderRoleAssignment
|
||||
|--RemoveReaderRoleAssignment
|
||||
|--CustomRoleDefinition
|
||||
|--ListRoleDefinitionsAfterCustomRoleCreation
|
||||
|--RemoveCustomRoleDefinition
|
||||
RegisterResourceProviders
|
||||
CreateResourceGroupForUtilities
|
||||
CreateStorageAccountForUtilities
|
||||
CreateStorageContainerForUtilities
|
||||
CreateDSCScriptResourceUtility
|
||||
CreateCustomScriptResourceUtility
|
||||
CreateDataDiskForVM
|
||||
UploadUtilitiesToBlobStorage
|
||||
CreateKeyVaultStoreForCertSecret
|
||||
CreateResourceGroupForVMs
|
||||
DeployARMTemplate
|
||||
RetrieveResourceDeploymentTimes
|
||||
QueryTheVMsDeployed
|
||||
CheckVMCommunicationPreVMReboot
|
||||
AddDatadiskToVMWithPrivateIP
|
||||
|--StopDeallocateVMWithPrivateIPBeforeAddingDatadisk
|
||||
|--AddTheDataDiskToVMWithPrivateIP
|
||||
|--StartVMWithPrivateIPAfterAddingDatadisk
|
||||
ApplyDataDiskCheckCustomScriptExtensionToVMWithPrivateIP
|
||||
|--CheckForExistingCustomScriptExtensionOnVMWithPrivateIP
|
||||
|--ApplyCustomScriptExtensionToVMWithPrivateIP
|
||||
RestartVMWithPublicIP
|
||||
StopDeallocateVMWithPrivateIP
|
||||
StartVMWithPrivateIP
|
||||
CheckVMCommunicationPostVMReboot
|
||||
CheckExistenceOfScreenShotForVMWithPrivateIP
|
||||
EnumerateAllResources
|
||||
DeleteVMWithPrivateIP
|
||||
DeleteVMResourceGroup
|
||||
DeleteUtilitiesResourceGroup
|
||||
TenantRelatedcleanup
|
||||
|--DeleteTenantSubscriptions
|
||||
|--LoginToAzureStackEnvAsSvcAdminForCleanup
|
||||
|--RemoveLinuxImageFromPIR
|
||||
|--DeleteSubscriptionResourceGroup
|
||||
```
|
||||
|
||||
## To exclude certain usecases from getting executed
|
||||
|
||||
```powershell
|
||||
# Install-Module -Name 'AzureRm.Bootstrapper' -Scope CurrentUser
|
||||
# Install-AzureRmProfile -profile '2017-03-09-profile' -Force -Scope CurrentUser
|
||||
# Install-Module -Name AzureStack -RequiredVersion 1.2.9 -Scope CurrentUser
|
||||
# A new paramter called ExclusionList has been added which is a string array. Pass in the list of usecases you don't want to execute to this parameter.
|
||||
$ServiceAdminCreds = New-Object System.Management.Automation.PSCredential "<Service Admin username>", (ConvertTo-SecureString "<Service Admin password>" -AsPlainText -Force)
|
||||
.\Canary.Tests.ps1 -TenantID "<TenantID from Azure Active Directory>" -AdminArmEndpoint "<Administrative ARM endpoint>" -ServiceAdminCredentials $ServiceAdminCreds -ExclusionList "ListFabricResourceProviderInfo","ListUpdateResourceProviderInfo"
|
||||
```
|
||||
|
||||
## Reading the results & logs
|
||||
|
||||
Canary generates log files in the TMP directory ($env:TMP). The logs can be found under the directory "CanaryLogs[DATETIME]". There are two types of logs generated, a text log and a JSON log. JSON log provides a quick and easy view of all the usecases and their corresponding results. Text log provides a more detailed output of each usecase execution, its output and results.
|
||||
|
||||
Each usecase entry in the JSON log consists of the following fields.
|
||||
|
||||
- Name
|
||||
- Description
|
||||
- StartTime
|
||||
|
@ -51,5 +155,4 @@ Each usecase entry in the JSON log consists of the following fields.
|
|||
- Result
|
||||
- Exception (in case a scenario fails)
|
||||
|
||||
The exception field is helpful to debug failed usecases.
|
||||
|
||||
The exception field is helpful to debug failed use cases.
|
||||
|
|
|
@ -83,6 +83,12 @@
|
|||
"metadata": {
|
||||
"description": "Maps to the sku in the Azure Stack Platform Image Repository manifest file Eg: 12.SP1, 6.7 , 7.2"
|
||||
}
|
||||
},
|
||||
"storageAccountEndPoint": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Storage account endpoint to be used to collect the diagnostic information from the VMs"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -662,7 +668,7 @@
|
|||
"protectedSettings": {
|
||||
"storageAccountName": "[variables('storageAccountName3')]",
|
||||
"storageAccountKey": "[listKeys(variables('storageAccountName3ID'), variables('apiVersionSRP')).key1]",
|
||||
"storageAccountEndPoint": "http://azurestack.local"
|
||||
"storageAccountEndPoint": "[parameters('storageAccountEndPoint')]"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -86,6 +86,12 @@
|
|||
"description": "Maps to the sku in the Azure Stack Platform Image Repository manifest file Eg: 12.SP1, 6.7 , 7.2"
|
||||
},
|
||||
"defaultValue": "14.04.3-LTS"
|
||||
},
|
||||
"storageAccountEndPoint": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Storage account endpoint to be used to collect the diagnostic information from the VMs"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -561,7 +567,7 @@
|
|||
"protectedSettings": {
|
||||
"storageAccountName": "[variables('storageAccountName3')]",
|
||||
"storageAccountKey": "[listKeys(variables('storageAccountName3ID'), variables('apiVersionSRP')).key1]",
|
||||
"storageAccountEndPoint": "http://azurestack.local"
|
||||
"storageAccountEndPoint": "[parameters('storageAccountEndPoint')]"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -5,186 +5,159 @@
|
|||
<#
|
||||
|
||||
.SYNOPSIS
|
||||
|
||||
|
||||
Get Cloud Capabilities (ARM resources, Api-version, VM Extensions, VM Images, VMSizes etc) for Azure Stack and Azure.
|
||||
|
||||
#>
|
||||
|
||||
function Get-AzureRMCloudCapabilities()
|
||||
{
|
||||
[CmdletBinding()]
|
||||
function Get-AzureRMCloudCapability() {
|
||||
[CmdletBinding()]
|
||||
[OutputType([string])]
|
||||
Param(
|
||||
[Parameter(HelpMessage = 'Json output file')]
|
||||
[Parameter(HelpMessage = 'Json output file')]
|
||||
[String] $OutputPath = "AzureCloudCapabilities.Json",
|
||||
|
||||
[Parameter(HelpMessage='Cloud Capabilities for the specified location')]
|
||||
[String] $Location,
|
||||
[Parameter(HelpMessage = 'Cloud Capabilities for the specified location')]
|
||||
[String] $Location,
|
||||
|
||||
[Parameter(HelpMessage = 'Set this to get compute resource provider Capabilities like Extensions, Images, Sizes')]
|
||||
[Switch] $IncludeComputeCapabilities,
|
||||
[Parameter(HelpMessage = 'Set this to get compute resource provider Capabilities like Extensions, Images, Sizes')]
|
||||
[Switch] $IncludeComputeCapabilities,
|
||||
|
||||
[Parameter(HelpMessage = 'Set this to get storage resource provider Capabilities like Sku')]
|
||||
[Switch] $IncludeStorageCapabilities
|
||||
[Parameter(HelpMessage = 'Set this to get storage resource provider Capabilities like Sku')]
|
||||
[Switch] $IncludeStorageCapabilities
|
||||
)
|
||||
$sw = [Diagnostics.Stopwatch]::StartNew()
|
||||
Write-Verbose "Getting CloudCapabilities for location: '$location'"
|
||||
$providerNamespaces = (Get-AzureRmResourceProvider -ListAvailable -Location $location -ErrorAction Stop).ProviderNamespace
|
||||
$resources = @()
|
||||
foreach ($providerNamespace in $providerNamespaces)
|
||||
{
|
||||
Write-Verbose "Working on $providerNamespace provider namespace"
|
||||
try
|
||||
{
|
||||
$resourceTypes = (Get-AzureRmResourceProvider -ProviderNamespace $providerNamespace -Location $location -ErrorAction Stop).ResourceTypes
|
||||
foreach ($resourceType in $resourceTypes)
|
||||
{
|
||||
$result = "" | Select-Object ProviderNamespace, ResourceTypeName, Locations, ApiVersions
|
||||
$result.ProviderNamespace = $providerNamespace
|
||||
$result.ResourceTypeName = $resourceType.ResourceTypeName
|
||||
$result.Locations = $resourceType.Locations
|
||||
$result.ApiVersions = $resourceType.ApiVersions
|
||||
$resources += , $result
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Error "Error occurred processing $providerNamespace provider namespace.Exception: " $_.Exception.Message
|
||||
}
|
||||
}
|
||||
|
||||
$capabilities = @{}
|
||||
$capabilities.Add("resources", $resources) | Out-Null
|
||||
|
||||
if ($IncludeComputeCapabilities)
|
||||
{
|
||||
Write-Verbose "Getting VMSizes for $location"
|
||||
try
|
||||
{
|
||||
$vmSizes = (Get-AzureRmVMSize -Location $location -ErrorAction Stop| Where-Object {$_.Name -like "*"}).Name
|
||||
if ($vmSizes)
|
||||
{
|
||||
$capabilities.Add("VMSizes", $vmSizes)
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose "No VMSizes found for $location"
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Error "Error occurred processing VMSizes for $location. Exception: " $_.Exception.Message
|
||||
}
|
||||
|
||||
Write-Verbose "Getting VMImages and Extensions for location $location"
|
||||
try
|
||||
{
|
||||
$publishers = Get-AzureRmVMImagePublisher -Location $location | Where-Object { $_.PublisherName -like "*" }
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Error "Error occurred processing VMimagePublisher for $location. Exception: " $_.Exception.Message
|
||||
}
|
||||
if ($publishers)
|
||||
{
|
||||
$imageList = New-Object System.Collections.ArrayList
|
||||
$extensionList = New-Object System.Collections.ArrayList
|
||||
foreach ($publisherObj in $publishers)
|
||||
{
|
||||
$publisher = $publisherObj.PublisherName
|
||||
$offers = Get-AzureRmVMImageOffer -Location $location -PublisherName $publisher
|
||||
if ($offers -ne $null)
|
||||
{
|
||||
$offerList = New-Object System.Collections.ArrayList
|
||||
foreach ($offerObj in $offers)
|
||||
{
|
||||
$offer = $offerObj.Offer
|
||||
$skuList = New-Object System.Collections.ArrayList
|
||||
$skus = Get-AzureRmVMImageSku -Location $location -PublisherName $publisher -Offer $offer
|
||||
foreach ($skuObj in $skus)
|
||||
{
|
||||
$sku = $skuObj.Skus
|
||||
Write-Verbose "Getting VMImage for publisher:$publisher , Offer:$offer , sku:$sku , location: $location"
|
||||
$images = Get-AzureRmVMImage -Location $location -PublisherName $publisher -Offer $offer -sku $sku
|
||||
$versions = $images.Version
|
||||
if ($versions.Count -le 1)
|
||||
{
|
||||
$versions = @($versions)
|
||||
}
|
||||
$skuDict = @{"skuName" = $sku; "versions" = $versions}
|
||||
$skuList.Add($skuDict) | Out-Null
|
||||
}
|
||||
$sw = [Diagnostics.Stopwatch]::StartNew()
|
||||
Write-Verbose "Getting CloudCapabilities for location: '$location'"
|
||||
$providerNamespaces = (Get-AzureRmResourceProvider -ListAvailable -Location $location -ErrorAction Stop).ProviderNamespace
|
||||
$resources = @()
|
||||
foreach ($providerNamespace in $providerNamespaces) {
|
||||
Write-Verbose "Working on $providerNamespace provider namespace"
|
||||
try {
|
||||
$resourceTypes = (Get-AzureRmResourceProvider -ProviderNamespace $providerNamespace -Location $location -ErrorAction Stop).ResourceTypes
|
||||
foreach ($resourceType in $resourceTypes) {
|
||||
$result = "" | Select-Object ProviderNamespace, ResourceTypeName, Locations, ApiVersions
|
||||
$result.ProviderNamespace = $providerNamespace
|
||||
$result.ResourceTypeName = $resourceType.ResourceTypeName
|
||||
$result.Locations = $resourceType.Locations
|
||||
$result.ApiVersions = $resourceType.ApiVersions
|
||||
$resources += , $result
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Error "Error occurred processing $providerNamespace provider namespace.Exception: " $_.Exception.Message
|
||||
}
|
||||
}
|
||||
|
||||
$offerDict = @{ "offerName" = $offer; "skus" = $skuList }
|
||||
$offerList.Add($offerDict) | Out-Null
|
||||
}
|
||||
$capabilities = @{}
|
||||
$capabilities.Add("resources", $resources) | Out-Null
|
||||
|
||||
$publisherDict = @{ "publisherName" = $publisher; "offers"= $offerList;"location" = $location }
|
||||
$imageList.Add($publisherDict) | Out-Null
|
||||
}
|
||||
else
|
||||
{
|
||||
$types = Get-AzureRmVMExtensionImageType -Location $location -PublisherName $publisher
|
||||
$typeList = New-Object System.Collections.ArrayList
|
||||
if ($types -ne $null)
|
||||
{
|
||||
foreach ($type in $types.Type)
|
||||
{
|
||||
Write-Verbose "Getting VMExtension for publisher:$publisher , Type:$type , location: $location"
|
||||
$extensions = Get-AzureRmVMExtensionImage -Location $location -PublisherName $publisher -Type $type
|
||||
$versions = $extensions.Version
|
||||
if ($versions.Count -le 1)
|
||||
{
|
||||
$versions = @($versions)
|
||||
}
|
||||
$typeDict = @{ "type" = $type; "versions" = $versions }
|
||||
$typeList.Add($typeDict) | Out-Null
|
||||
}
|
||||
$publisherDict = @{ "publisher" = $publisher; "types" = $typeList;"location" = $location }
|
||||
$extensionList.Add($publisherDict) | Out-Null
|
||||
}
|
||||
else
|
||||
{
|
||||
"none @ " + $publisher
|
||||
}
|
||||
}
|
||||
}
|
||||
$capabilities.Add("VMExtensions", $extensionList)
|
||||
$capabilities.Add("VMImages", $imageList)
|
||||
}
|
||||
}
|
||||
if ($IncludeStorageCapabilities)
|
||||
{
|
||||
Write-Verbose "Getting Storage Sku supported for $location"
|
||||
try
|
||||
{
|
||||
$storageSkus = Get-AzureRmResource -ResourceType "Microsoft.Storage/Skus" -ResourceName "/"
|
||||
if ($storageSkus)
|
||||
{
|
||||
$skuList = New-Object System.Collections.ArrayList
|
||||
$storageKind = $storageSkus| Select-Object Kind | Get-Unique -AsString
|
||||
foreach ($kind in $storageKind.Kind)
|
||||
{
|
||||
$skus= ($storageSkus | Where-Object { $_.Kind -eq $kind }).Name
|
||||
$kindDict = @{ "kind" = $kind; "skus" = $skus }
|
||||
$skuList.Add($kindDict) | Out-Null
|
||||
}
|
||||
$capabilities.Add("StorageSkus", $skuList)
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose "No StorageSkus found for $location"
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Error "Error occurred processing StorageSkus for $location. Exception: " $_.Exception.Message
|
||||
}
|
||||
}
|
||||
$capabilitiesJson = ConvertTo-Json $capabilities -Depth 10
|
||||
$capabilitiesJson | Out-File $OutputPath
|
||||
if ($IncludeComputeCapabilities) {
|
||||
Write-Verbose "Getting VMSizes for $location"
|
||||
try {
|
||||
$vmSizes = (Get-AzureRmVMSize -Location $location -ErrorAction Stop| Where-Object {$_.Name -like "*"}).Name
|
||||
if ($vmSizes) {
|
||||
$capabilities.Add("VMSizes", $vmSizes)
|
||||
}
|
||||
else {
|
||||
Write-Verbose "No VMSizes found for $location"
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Error "Error occurred processing VMSizes for $location. Exception: " $_.Exception.Message
|
||||
}
|
||||
|
||||
$sw.Stop()
|
||||
$time = $sw.Elapsed
|
||||
"Cloud Capabilities JSON Generation Complete"
|
||||
"Time Elapsed = " + [math]::floor($time.TotalMinutes) + " min " + $time.Seconds + " sec"
|
||||
Write-Verbose "Getting VMImages and Extensions for location $location"
|
||||
try {
|
||||
$publishers = Get-AzureRmVMImagePublisher -Location $location | Where-Object { $_.PublisherName -like "*" }
|
||||
}
|
||||
catch {
|
||||
Write-Error "Error occurred processing VMimagePublisher for $location. Exception: " $_.Exception.Message
|
||||
}
|
||||
if ($publishers) {
|
||||
$imageList = New-Object System.Collections.ArrayList
|
||||
$extensionList = New-Object System.Collections.ArrayList
|
||||
foreach ($publisherObj in $publishers) {
|
||||
$publisher = $publisherObj.PublisherName
|
||||
$offers = Get-AzureRmVMImageOffer -Location $location -PublisherName $publisher
|
||||
if ($offers) {
|
||||
$offerList = New-Object System.Collections.ArrayList
|
||||
foreach ($offerObj in $offers) {
|
||||
$offer = $offerObj.Offer
|
||||
$skuList = New-Object System.Collections.ArrayList
|
||||
$skus = Get-AzureRmVMImageSku -Location $location -PublisherName $publisher -Offer $offer
|
||||
foreach ($skuObj in $skus) {
|
||||
$sku = $skuObj.Skus
|
||||
Write-Verbose "Getting VMImage for publisher:$publisher , Offer:$offer , sku:$sku , location: $location"
|
||||
$images = Get-AzureRmVMImage -Location $location -PublisherName $publisher -Offer $offer -sku $sku
|
||||
$versions = $images.Version
|
||||
if ($versions.Count -le 1) {
|
||||
$versions = @($versions)
|
||||
}
|
||||
$skuDict = @{"skuName" = $sku; "versions" = $versions}
|
||||
$skuList.Add($skuDict) | Out-Null
|
||||
}
|
||||
|
||||
$offerDict = @{ "offerName" = $offer; "skus" = $skuList }
|
||||
$offerList.Add($offerDict) | Out-Null
|
||||
}
|
||||
|
||||
$publisherDict = @{ "publisherName" = $publisher; "offers" = $offerList; "location" = $location }
|
||||
$imageList.Add($publisherDict) | Out-Null
|
||||
}
|
||||
else {
|
||||
$types = Get-AzureRmVMExtensionImageType -Location $location -PublisherName $publisher
|
||||
$typeList = New-Object System.Collections.ArrayList
|
||||
if ($types) {
|
||||
foreach ($type in $types.Type) {
|
||||
Write-Verbose "Getting VMExtension for publisher:$publisher , Type:$type , location: $location"
|
||||
$extensions = Get-AzureRmVMExtensionImage -Location $location -PublisherName $publisher -Type $type
|
||||
$versions = $extensions.Version
|
||||
if ($versions.Count -le 1) {
|
||||
$versions = @($versions)
|
||||
}
|
||||
$typeDict = @{ "type" = $type; "versions" = $versions }
|
||||
$typeList.Add($typeDict) | Out-Null
|
||||
}
|
||||
$publisherDict = @{ "publisher" = $publisher; "types" = $typeList; "location" = $location }
|
||||
$extensionList.Add($publisherDict) | Out-Null
|
||||
}
|
||||
else {
|
||||
"none @ " + $publisher
|
||||
}
|
||||
}
|
||||
}
|
||||
$capabilities.Add("VMExtensions", $extensionList)
|
||||
$capabilities.Add("VMImages", $imageList)
|
||||
}
|
||||
}
|
||||
if ($IncludeStorageCapabilities) {
|
||||
Write-Verbose "Getting Storage Sku supported for $location"
|
||||
try {
|
||||
$storageSkus = Get-AzureRmResource -ResourceType "Microsoft.Storage/Skus" -ResourceName "/"
|
||||
if ($storageSkus) {
|
||||
$skuList = New-Object System.Collections.ArrayList
|
||||
$storageKind = $storageSkus| Select-Object Kind | Get-Unique -AsString
|
||||
foreach ($kind in $storageKind.Kind) {
|
||||
$skus = ($storageSkus | Where-Object { $_.Kind -eq $kind }).Name
|
||||
$kindDict = @{ "kind" = $kind; "skus" = $skus }
|
||||
$skuList.Add($kindDict) | Out-Null
|
||||
}
|
||||
$capabilities.Add("StorageSkus", $skuList)
|
||||
}
|
||||
else {
|
||||
Write-Verbose "No StorageSkus found for $location"
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Error "Error occurred processing StorageSkus for $location. Exception: " $_.Exception.Message
|
||||
}
|
||||
}
|
||||
$capabilitiesJson = ConvertTo-Json $capabilities -Depth 10
|
||||
$capabilitiesJson | Out-File $OutputPath
|
||||
|
||||
$sw.Stop()
|
||||
$time = $sw.Elapsed
|
||||
"Cloud Capabilities JSON Generation Complete"
|
||||
"Time Elapsed = " + [math]::floor($time.TotalMinutes) + " min " + $time.Seconds + " sec"
|
||||
}
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
# Get Cloud Capabilities
|
||||
|
||||
Instructions below are relative to the .\CloudCapabilities folder of the [AzureStack-Tools repo](..).
|
||||
To get VMImages, Extensions & Sizes available in the cloud, add -IncludeComputeCapabilities
|
||||
To get StorageSkus available in the cloud, add -IncludeStorageCapabilities
|
||||
|
||||
```powershell
|
||||
|
||||
Import-Module ".\AzureRM.CloudCapabilities.psm1"
|
||||
```
|
||||
# Prerequisites
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Connected Azure or AzureStack powershell environment (Refer [AzureStack-Tools repo/Connect](../Connect) for connecting to an Azure Stack instance. )
|
||||
|
||||
```powershell
|
||||
|
|
После Ширина: | Высота: | Размер: 418 KiB |
|
@ -1,4 +1,7 @@
|
|||
# Azure Stack Compute Administration
|
||||
![Adding an image in an ADFS environment](/ComputeAdmin/ComputeAdmin.gif)
|
||||
|
||||
|
||||
Instructions below are relative to the .\ComputeAdmin folder of the [AzureStack-Tools repo](..).
|
||||
|
||||
Make sure you have the following module prerequisites installed:
|
||||
|
@ -6,45 +9,53 @@ Make sure you have the following module prerequisites installed:
|
|||
```powershell
|
||||
Install-Module -Name 'AzureRm.Bootstrapper' -Scope CurrentUser
|
||||
Install-AzureRmProfile -profile '2017-03-09-profile' -Force -Scope CurrentUser
|
||||
Install-Module -Name AzureStack -RequiredVersion 1.2.9 -Scope CurrentUser
|
||||
Install-Module -Name AzureStack -RequiredVersion 1.2.10 -Scope CurrentUser
|
||||
```
|
||||
|
||||
Then make sure the following modules are imported:
|
||||
|
||||
```powershell
|
||||
Import-Module ..\Connect\AzureStack.Connect.psm1
|
||||
Import-Module .\AzureStack.ComputeAdmin.psm1
|
||||
```
|
||||
|
||||
You will need to reference your Azure Stack Administrator environment. To create an administrator environment use the below. The ARM endpoint below is the administrator default for a one-node environment.
|
||||
## Add PowerShell environment
|
||||
|
||||
You will need to login to your Azure Stack Administrator environment. To create an administrator environment use the below. The ARM endpoint below is the administrator default for a one-node environment.
|
||||
|
||||
```powershell
|
||||
Add-AzureStackAzureRmEnvironment -Name "AzureStackAdmin" -ArmEndpoint "https://adminmanagement.local.azurestack.external"
|
||||
Add-AzureRMEnvironment -Name "AzureStackAdmin" -ArmEndpoint "https://adminmanagement.local.azurestack.external"
|
||||
```
|
||||
|
||||
Adding a VM Image requires that you obtain the value of your Directory Tenant ID. For **Azure Active Directory** environments provide your directory tenant name:
|
||||
Then login:
|
||||
|
||||
```powershell
|
||||
$TenantID = Get-DirectoryTenantID -AADTenantName "<mydirectorytenant>.onmicrosoft.com" -EnvironmentName AzureStackAdmin
|
||||
Login-AzureRmAccount -EnvironmentName "AzureStackAdmin"
|
||||
```
|
||||
----
|
||||
If you are **not** using your home directory tenant, you will need to supply the tenant ID to your login command. You may find it easiest to obtain using the Connect tool. For **Azure Active Directory** environments provide your directory tenant name:
|
||||
|
||||
```powershell
|
||||
$TenantID = Get-AzsDirectoryTenantId -AADTenantName "<mydirectorytenant>.onmicrosoft.com" -EnvironmentName AzureStackAdmin
|
||||
```
|
||||
|
||||
For **ADFS** environments use the following:
|
||||
|
||||
```powershell
|
||||
$TenantID = Get-DirectoryTenantID -ADFS -EnvironmentName AzureStackAdmin
|
||||
$TenantID = Get-AzsDirectoryTenantId -ADFS -EnvironmentName AzureStackAdmin
|
||||
```
|
||||
|
||||
## Add the WS2016 Evaluation VM Image
|
||||
|
||||
The New-Server2016VMImage allows you to add a Windows Server 2016 Evaluation VM Image to your Azure Stack Marketplace.
|
||||
The New-AzsServer2016VMImage allows you to add a Windows Server 2016 Evaluation VM Image to your Azure Stack Marketplace.
|
||||
|
||||
As a prerequisite, you need to obtain the Windows Server 2016 Evaluation ISO which can be found [here](https://www.microsoft.com/en-us/evalcenter/evaluate-windows-server-2016).
|
||||
|
||||
An example usage is the following:
|
||||
|
||||
```powershell
|
||||
|
||||
$ISOPath = "<Path to ISO>"
|
||||
New-Server2016VMImage -ISOPath $ISOPath -TenantId $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
New-AzsServer2016VMImage -ISOPath $ISOPath
|
||||
```
|
||||
Please make sure to specify the correct administrator ARM endpoint for your environment.
|
||||
|
||||
This command may show a **popup prompt that can be ignored** without issue.
|
||||
|
||||
|
@ -55,31 +66,25 @@ Please note that to use this image for **installing additional Azure Stack servi
|
|||
## Add a VM image to the Marketplace with PowerShell
|
||||
|
||||
1. Prepare a Windows or Linux operating system virtual hard disk image in VHD format (not VHDX).
|
||||
- For Windows images, the article [Upload a Windows VM image to Azure for Resource Manager deployments](https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-windows-upload-image/) contains image preparation instructions in the **Prepare the VHD for upload** section.
|
||||
- For Linux images, follow the steps to
|
||||
|
||||
- For Windows images, the article [Upload a Windows VM image to Azure for Resource Manager deployments](https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-windows-upload-image/) contains image preparation instructions in the **Prepare the VHD for upload** section.
|
||||
- For Linux images, follow the steps to
|
||||
prepare the image or use an existing Azure Stack Linux image as described in
|
||||
the article [Deploy Linux virtual machines on Azure
|
||||
Stack](https://azure.microsoft.com/en-us/documentation/articles/azure-stack-linux/).
|
||||
|
||||
2. Add the VM image by invoking the Add-VMImage cmdlet.
|
||||
- Include the publisher, offer, SKU, and version for the VM image. These parameters are used by Azure Resource Manager templates that reference the VM image.
|
||||
- Specify osType as Windows or Linux.
|
||||
- Include your Azure Active Directory tenant ID in the form *<mydirectory>*.onmicrosoft.com.
|
||||
- The following is an example invocation of the script:
|
||||
1. Add the VM image by invoking the Add-AzsVMImage cmdlet.
|
||||
|
||||
You will need to reference your Azure Stack Administrator environment. To create an administrator environment use the below. The ARM endpoint below is the administrator default for a one-node environment.
|
||||
- Include the publisher, offer, SKU, and version for the VM image. These parameters are used by Azure Resource Manager templates that reference the VM image.
|
||||
- Specify osType as Windows or Linux.
|
||||
- The following is an example invocation of the script:
|
||||
|
||||
```powershell
|
||||
Add-AzureStackAzureRmEnvironment -Name "AzureStackAdmin" -ArmEndpoint "https://adminmanagement.local.azurestack.external"
|
||||
Add-AzsVMImage -publisher "Canonical" -offer "UbuntuServer" -sku "14.04.3-LTS" -version "1.0.0" -osType Linux -osDiskLocalPath 'C:\Users\<me>\Desktop\UbuntuServer.vhd'
|
||||
```
|
||||
|
||||
```powershell
|
||||
Add-VMImage -publisher "Canonical" -offer "UbuntuServer" -sku "14.04.3-LTS" -version "1.0.0" -osType Linux -osDiskLocalPath 'C:\Users\<me>\Desktop\UbuntuServer.vhd' -tenantID <GUID AADTenant> -EnvironmentName "AzureStackAdmin"
|
||||
```
|
||||
|
||||
Note: The cmdlet requests credentials for adding the VM image. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Uploads the local VHD to a newly created temporary storage account
|
||||
- Adds the VM image to the VM image repository
|
||||
|
@ -88,79 +93,49 @@ The command does the following:
|
|||
To verify that the command ran successfully, go to Marketplace in the portal, and then verify that the VM image is available in the **Virtual Machines** category.
|
||||
|
||||
## Remove a VM Image with PowerShell
|
||||
|
||||
Run the below command to remove an uploaded VM image. After removal, tenants will no longer be able to deploy virtual machines with this image.
|
||||
|
||||
You will need to reference your Azure Stack Administrator environment. To create an administrator environment use the below. The ARM endpoint below is the administrator default for a one-node environment.
|
||||
|
||||
```powershell
|
||||
Add-AzureStackAzureRmEnvironment -Name "AzureStackAdmin" -ArmEndpoint "https://adminmanagement.local.azurestack.external"
|
||||
```
|
||||
|
||||
```powershell
|
||||
Remove-VMImage -publisher "Canonical" -offer "UbuntuServer" -sku "14.04.3-LTS" -version "1.0.0" -tenantID <GUID AADTenant> -EnvironmentName "AzureStackAdmin"
|
||||
Remove-AzsVMImage -publisher "Canonical" -offer "UbuntuServer" -sku "14.04.3-LTS" -version "1.0.0"
|
||||
```
|
||||
|
||||
Note: This cmdlet will remove the associated Marketplace item unless the -KeepMarketplaceItem parameter is specified.
|
||||
|
||||
## Add a VM extension to the Compute with PowerShell
|
||||
You will need to reference your Azure Stack Administrator environment. To create an administrator environment use the below. The ARM endpoint below is the administrator default for a one-node environment.
|
||||
|
||||
```powershell
|
||||
Add-AzureStackAzureRmEnvironment -Name "AzureStackAdmin" -ArmEndpoint "https://adminmanagement.local.azurestack.external"
|
||||
```
|
||||
An example usage is the following:
|
||||
|
||||
```powershell
|
||||
$path = "<Path to vm extension zip>"
|
||||
Add-VMExtension -publisher "Publisher" -type "Type" -version "1.0.0.0" -extensionLocalPath $path -osType Windows -tenantID $TenantID -azureStackCredentials $azureStackCredentials -EnvironmentName "AzureStackAdmin"
|
||||
```
|
||||
|
||||
|
||||
# Remove a VM extension with PowerShell
|
||||
|
||||
You will need to reference your Azure Stack Administrator environment. To create an administrator environment use the below. The ARM endpoint below is the administrator default for a one-node environment.
|
||||
|
||||
```powershell
|
||||
Add-AzureStackAzureRmEnvironment -Name "AzureStackAdmin" -ArmEndpoint "https://adminmanagement.local.azurestack.external"
|
||||
```
|
||||
Run the below command to remove an uploaded VM extension.
|
||||
|
||||
```powershell
|
||||
Remove-VMExtension -publisher "Publisher" -type "Type" -version "1.0.0.0" -osType Windows -tenantID $TenantID -azureStackCredentials $azureStackCredentials -EnvironmentName "AzureStackAdmin"
|
||||
```
|
||||
|
||||
## VM Scale Set gallery item
|
||||
|
||||
VM Scale Set allows deployment of multi-VM collections. To add a gallery item with VM Scale Set:
|
||||
|
||||
1. Add evaluation Windows Server 2016 image using New-Server2016VMImage as described above.
|
||||
1. Add evaluation Windows Server 2016 image using New-AzsServer2016VMImage as described above.
|
||||
|
||||
2. For linux support, download Ubuntu Server 16.04 and add it using Add-VmImage with the following parameters -publisher "Canonical" -offer "UbuntuServer" -sku "16.04-LTS"
|
||||
1. For linux support, download Ubuntu Server 16.04 and add it using Add-AzsVMImage with the following parameters -publisher "Canonical" -offer "UbuntuServer" -sku "16.04-LTS"
|
||||
|
||||
3. Add VM Scale Set gallery item as follows
|
||||
1. Add VM Scale Set gallery item as follows
|
||||
|
||||
```powershell
|
||||
$TenantId = "<AAD Tenant Id used to connect to AzureStack>"
|
||||
$Arm = "<AzureStack administrative Azure Resource Manager endpoint URL>"
|
||||
$Location = "<The location name of your AzureStack Environment>"
|
||||
|
||||
Add-AzureStackAzureRmEnvironment -Name AzureStackAdmin -ArmEndpoint $Arm
|
||||
Add-AzsEnvironment -Name AzureStackAdmin -ArmEndpoint $Arm
|
||||
|
||||
$Password = ConvertTo-SecureString -AsPlainText -Force "<your AzureStack admin user password>"
|
||||
$User = "<your AzureStack admin user name>"
|
||||
$Creds = New-Object System.Management.Automation.PSCredential $User, $Password
|
||||
|
||||
Login-AzureRmAccount -EnvironmentName AzureStackAdmin -Credential $Creds -TenantId $TenantId
|
||||
$AzsEnv = Get-AzureRmEnvironment AzureStackAdmin
|
||||
$AzsEnvContext = Add-AzureRmAccount -Environment $AzsEnv -Credential $Creds
|
||||
Select-AzureRmProfile -Profile $AzsEnvContext
|
||||
|
||||
Select-AzureRmSubscription -SubscriptionName "Default Provider Subscription"
|
||||
|
||||
Add-AzureStackVMSSGalleryItem -Location $Location
|
||||
```
|
||||
Add-AzsVMSSGalleryItem -Location $Location
|
||||
|
||||
To remove VM Scale Set gallery item run the following command:
|
||||
|
||||
```powershell
|
||||
Remove-AzureStackVMSSGalleryItem
|
||||
|
||||
Remove-AzsVMSSGalleryItem
|
||||
|
||||
```
|
||||
|
||||
Note that gallery item is not removed immediately. You could run the above command several times to determine when the item is actually gone.
|
||||
|
||||
|
|
|
@ -11,13 +11,13 @@ Describe $script:ModuleName {
|
|||
Should Not Be $null
|
||||
}
|
||||
|
||||
It 'Add-VMImage should be exported' {
|
||||
Get-Command -Name Add-VMImage -ErrorAction SilentlyContinue |
|
||||
It 'Add-AzsVMImage should be exported' {
|
||||
Get-Command -Name Add-AzsVMImage -ErrorAction SilentlyContinue |
|
||||
Should Not Be $null
|
||||
}
|
||||
|
||||
It 'Remove-VMImage should be exported' {
|
||||
Get-Command -Name Remove-VMImage -ErrorAction SilentlyContinue |
|
||||
It 'Remove-AzsVMImage should be exported' {
|
||||
Get-Command -Name Remove-AzsVMImage -ErrorAction SilentlyContinue |
|
||||
Should Not Be $null
|
||||
}
|
||||
}
|
||||
|
@ -28,17 +28,11 @@ InModuleScope $script:ModuleName {
|
|||
$HostComputer = $global:HostComputer
|
||||
$ArmEndpoint = $global:ArmEndpoint
|
||||
$natServer = $global:natServer
|
||||
$AdminUser= $global:AdminUser
|
||||
$AdminUser = $global:AdminUser
|
||||
$AadServiceAdmin = $global:AadServiceAdmin
|
||||
|
||||
$AdminPassword = $global:AdminPassword
|
||||
$AadServiceAdminPassword = $global:AadServiceAdminPassword
|
||||
$stackLoginCreds = $global:AzureStackLoginCredentials
|
||||
|
||||
$VPNConnectionName = $global:VPNConnectionName
|
||||
|
||||
$AadTenant = $global:AadTenantID
|
||||
|
||||
$EnvironmentName = $global:EnvironmentName
|
||||
|
||||
# Generate Fake VHD for testing image upload
|
||||
|
@ -59,38 +53,38 @@ InModuleScope $script:ModuleName {
|
|||
|
||||
Describe 'ComputeAdmin - Functional Tests' {
|
||||
It 'CreateGalleryItem = "$false" -and title = specified should throw' {
|
||||
{ Add-VMImage -publisher $publisher -offer $offer -sku $sku -version $version -osType $osType -osDiskLocalPath $osDiskPath -tenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredential $stackLoginCreds -CreateGalleryItem $false -title 'testTitle' } |
|
||||
{ Add-AzsVMImage -publisher $publisher -offer $offer -sku $sku -version $version -osType $osType -osDiskLocalPath $osDiskPath -CreateGalleryItem $false -title 'testTitle' } |
|
||||
Should Throw
|
||||
}
|
||||
|
||||
It 'CreateGalleryItem = "$false" -and description = specified should throw' {
|
||||
{ Add-VMImage -publisher $publisher -offer $offer -sku $sku -version $version -osType $osType -osDiskLocalPath $osDiskPath -tenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredential $stackLoginCreds -CreateGalleryItem $false -title 'testTitle' -CreateGalleryItem $false -description 'testdescription' } | Should Throw
|
||||
{ Add-AzsVMImage -publisher $publisher -offer $offer -sku $sku -version $version -osType $osType -osDiskLocalPath $osDiskPath -CreateGalleryItem $false -title 'testTitle' -CreateGalleryItem $false -description 'testdescription' } | Should Throw
|
||||
}
|
||||
|
||||
It 'Add-VMImage via local path and upload to storage account should succeed' {
|
||||
{ Add-VMImage -publisher $publisher -offer $offer -sku $sku -version $version -osType $osType -osDiskLocalPath $osDiskPath -tenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredential $stackLoginCreds -CreateGalleryItem $false } |
|
||||
It 'Add-AzsVMImage via local path and upload to storage account should succeed' {
|
||||
{ Add-AzsVMImage -publisher $publisher -offer $offer -sku $sku -version $version -osType $osType -osDiskLocalPath $osDiskPath -CreateGalleryItem $false } |
|
||||
Should Not Throw
|
||||
}
|
||||
|
||||
It 'Remove-VMImage should successfully remove added VM Image' {
|
||||
{ Remove-VMImage -publisher $publisher -offer $offer -sku $sku -version $version -tenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredential $stackLoginCreds} |
|
||||
It 'Remove-AzsVMImage should successfully remove added VM Image' {
|
||||
{ Remove-AzsVMImage -publisher $publisher -offer $offer -sku $sku -version $version} |
|
||||
Should Not Throw
|
||||
}
|
||||
|
||||
It 'Add-VMImage via local path and upload to storage account with gallery item should succeed' {
|
||||
{ Add-VMImage -publisher $publisher -offer $offer -sku $gallerySku -version $version -osType $osType -osDiskLocalPath $osDiskPath -tenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredential $stackLoginCreds } |
|
||||
It 'Add-AzsVMImage via local path and upload to storage account with gallery item should succeed' {
|
||||
{ Add-AzsVMImage -publisher $publisher -offer $offer -sku $gallerySku -version $version -osType $osType -osDiskLocalPath $osDiskPath } |
|
||||
Should Not Throw
|
||||
}
|
||||
|
||||
It 'Remove-VMImage and Removing Marketplace Item should successfully complete' {
|
||||
It 'Remove-AzsVMImage and Removing Marketplace Item should successfully complete' {
|
||||
{
|
||||
Remove-VMImage -publisher $publisher -offer $offer -sku $gallerySku -version $version -tenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredential $stackLoginCreds
|
||||
Remove-AzsVMImage -publisher $publisher -offer $offer -sku $gallerySku -version $version
|
||||
Get-AzureRMGalleryItem | Where-Object {$_.Name -contains "$publisher.$offer$gallerySku.$version"} | Remove-AzureRMGalleryItem
|
||||
} | Should Not Throw
|
||||
}
|
||||
|
||||
It 'Adding Ubuntu Linux 16.04 Image and Marketplace Item Succeeds' {
|
||||
{ Add-VMImage -publisher "Canonical" -offer "UbuntuServer" -sku "16.04.1-LTS" -version "1.0.4" -osType Linux -EnvironmentName $EnvironmentName -osDiskLocalPath $ubuntuPath -tenantID $AadTenant -AzureStackCredential $stackLoginCreds} |
|
||||
{ Add-AzsVMImage -publisher "Canonical" -offer "UbuntuServer" -sku "16.04.1-LTS" -version "1.0.4" -osType Linux -osDiskLocalPath $ubuntuPath} |
|
||||
Should Not Throw
|
||||
}
|
||||
|
||||
|
@ -100,9 +94,10 @@ InModuleScope $script:ModuleName {
|
|||
$newOffer = "UbuntuServer"
|
||||
$newSKU = "16.04.1-LTS"
|
||||
$newVersion = "1.0.4"
|
||||
Remove-VMImage -publisher $newPub -offer $newOffer -sku $newSKU -version $newVersion -tenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredential $stackLoginCreds
|
||||
Remove-AzsVMImage -publisher $newPub -offer $newOffer -sku $newSKU -version $newVersion
|
||||
|
||||
$GalleryItemName = "$newOffer$newSKU"
|
||||
$GalleryItemName = $GalleryItemName -replace "\.","-"
|
||||
$GalleryItemName = $GalleryItemName -replace "\.", "-"
|
||||
Get-AzureRMGalleryItem | Where-Object {$_.Name -contains "$newPub.$GalleryItemName.$newVersion"} | Remove-AzureRMGalleryItem
|
||||
} | Should Not Throw
|
||||
}
|
||||
|
@ -112,4 +107,4 @@ InModuleScope $script:ModuleName {
|
|||
Remove-Item $ubuntuPath
|
||||
Remove-Item $osDiskPath
|
||||
Remove-Item $dataDiskPath
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,198 +4,25 @@
|
|||
#requires -Version 4.0
|
||||
#requires -Modules AzureRM.Profile, VpnClient, AzureRM.AzureStackAdmin
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Registers all providers on the all subscription
|
||||
#>
|
||||
function Register-AllAzureRmProvidersOnAllSubscriptions {
|
||||
foreach($s in (Get-AzureRmSubscription)) {
|
||||
Select-AzureRmSubscription -SubscriptionId $s.SubscriptionId | Out-Null
|
||||
Write-Progress $($s.SubscriptionId + " : " + $s.SubscriptionName)
|
||||
Register-AllAzureRmProviders
|
||||
}
|
||||
}
|
||||
|
||||
Export-ModuleMember Register-AllAzureRmProvidersOnAllSubscriptions
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Registers all providers on the newly created subscription
|
||||
#>
|
||||
function Register-AllAzureRmProviders {
|
||||
Get-AzureRmResourceProvider -ListAvailable | Register-AzureRmResourceProvider -Force
|
||||
}
|
||||
|
||||
Export-ModuleMember Register-AllAzureRmProviders
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Obtains Aazure Active Directory tenant that was used when deploying the Azure Stack instance
|
||||
#>
|
||||
function Get-AzureStackAadTenant {
|
||||
param (
|
||||
[parameter(mandatory=$true, HelpMessage="Azure Stack One Node host address or name such as '1.2.3.4'")]
|
||||
[string] $HostComputer,
|
||||
[Parameter(HelpMessage="The Domain suffix of the environment VMs")]
|
||||
[string] $DomainSuffix = 'azurestack.local',
|
||||
[parameter(HelpMessage="Administrator user name of this Azure Stack Instance")]
|
||||
[string] $User = "administrator",
|
||||
[parameter(mandatory=$true, HelpMessage="Administrator password used to deploy this Azure Stack instance")]
|
||||
[securestring] $Password
|
||||
)
|
||||
|
||||
$Domain = $DomainSuffix
|
||||
|
||||
$UserCred = "$Domain\$User"
|
||||
$credential = New-Object System.Management.Automation.PSCredential -ArgumentList $UserCred, $Password
|
||||
|
||||
Write-Verbose "Remoting to the Azure Stack host $HostComputer..." -Verbose
|
||||
return Invoke-Command -ComputerName "$HostComputer" -Credential $credential -ScriptBlock `
|
||||
{
|
||||
Write-Verbose "Retrieving Azure Stack configuration..." -Verbose
|
||||
$configFile = Get-ChildItem -Path C:\EceStore -Recurse | Where-Object {-not $_.PSIsContainer} | Sort-Object Length -Descending | Select-Object -First 1
|
||||
$customerConfig = [xml] (Get-Content -Path $configFile.FullName)
|
||||
|
||||
$Parameters = $customerConfig.CustomerConfiguration
|
||||
$fabricRole = $Parameters.Role.Roles.Role | Where-Object {$_.Id -eq "Fabric"}
|
||||
$allFabricRoles = $fabricRole.Roles.ChildNodes
|
||||
$idProviderRole = $allFabricRoles | Where-Object {$_.Id -eq "IdentityProvider"}
|
||||
$idProviderRole.PublicInfo.AADTenant.Id
|
||||
}
|
||||
}
|
||||
|
||||
Export-ModuleMember Get-AzureStackAadTenant
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Adds Azure Stack environment to use with AzureRM command-lets when targeting Azure Stack
|
||||
#>
|
||||
function Add-AzureStackAzureRmEnvironment {
|
||||
param (
|
||||
[Parameter(mandatory=$true, HelpMessage="The Admin ARM endpoint of the Azure Stack Environment")]
|
||||
[string] $ArmEndpoint,
|
||||
[parameter(mandatory=$true, HelpMessage="Azure Stack environment name for use with AzureRM commandlets")]
|
||||
[string] $Name
|
||||
)
|
||||
|
||||
if(!$ARMEndpoint.Contains('https://')){
|
||||
if($ARMEndpoint.Contains('http://')){
|
||||
$ARMEndpoint = $ARMEndpoint.Substring(7)
|
||||
$ARMEndpoint = 'https://' + $ARMEndpoint
|
||||
|
||||
}else{
|
||||
$ARMEndpoint = 'https://' + $ARMEndpoint
|
||||
}
|
||||
}
|
||||
|
||||
$ArmEndpoint = $ArmEndpoint.TrimEnd("/")
|
||||
|
||||
$Domain = ""
|
||||
try {
|
||||
$uriARMEndpoint = [System.Uri] $ArmEndpoint
|
||||
$i = $ArmEndpoint.IndexOf('.')
|
||||
$Domain = ($ArmEndpoint.Remove(0,$i+1)).TrimEnd('/')
|
||||
}
|
||||
catch {
|
||||
Write-Error "The specified ARM endpoint was invalid"
|
||||
}
|
||||
|
||||
$ResourceManagerEndpoint = $ArmEndpoint
|
||||
$stackdomain = $Domain
|
||||
|
||||
Write-Verbose "Retrieving endpoints from the $ResourceManagerEndpoint..." -Verbose
|
||||
$endpoints = Invoke-RestMethod -Method Get -Uri "$($ResourceManagerEndpoint.ToString().TrimEnd('/'))/metadata/endpoints?api-version=2015-01-01" -ErrorAction Stop
|
||||
|
||||
$AzureKeyVaultDnsSuffix="vault.$($stackdomain)".ToLowerInvariant()
|
||||
$AzureKeyVaultServiceEndpointResourceId= $("https://vault.$stackdomain".ToLowerInvariant())
|
||||
$StorageEndpointSuffix = ($stackdomain).ToLowerInvariant()
|
||||
$aadAuthorityEndpoint = $endpoints.authentication.loginEndpoint
|
||||
|
||||
$azureEnvironmentParams = @{
|
||||
Name = $Name
|
||||
ActiveDirectoryEndpoint = $endpoints.authentication.loginEndpoint.TrimEnd('/') + "/"
|
||||
ActiveDirectoryServiceEndpointResourceId = $endpoints.authentication.audiences[0]
|
||||
ResourceManagerEndpoint = $ResourceManagerEndpoint
|
||||
GalleryEndpoint = $endpoints.galleryEndpoint
|
||||
GraphEndpoint = $endpoints.graphEndpoint
|
||||
GraphAudience = $endpoints.graphEndpoint
|
||||
StorageEndpointSuffix = $StorageEndpointSuffix
|
||||
AzureKeyVaultDnsSuffix = $AzureKeyVaultDnsSuffix
|
||||
AzureKeyVaultServiceEndpointResourceId = $AzureKeyVaultServiceEndpointResourceId
|
||||
EnableAdfsAuthentication = $aadAuthorityEndpoint.TrimEnd("/").EndsWith("/adfs", [System.StringComparison]::OrdinalIgnoreCase)
|
||||
}
|
||||
|
||||
$armEnv = Get-AzureRmEnvironment -Name $Name
|
||||
if($armEnv -ne $null) {
|
||||
Write-Verbose "Updating AzureRm environment $Name" -Verbose
|
||||
Remove-AzureRmEnvironment -Name $Name -Force | Out-Null
|
||||
}
|
||||
else {
|
||||
Write-Verbose "Adding AzureRm environment $Name" -Verbose
|
||||
}
|
||||
|
||||
return Add-AzureRmEnvironment @azureEnvironmentParams
|
||||
}
|
||||
|
||||
Export-ModuleMember Add-AzureStackAzureRmEnvironment
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Obtains Azure Stack NAT address from the Azure Stack One Node instance
|
||||
#>
|
||||
function Get-AzureStackNatServerAddress {
|
||||
param (
|
||||
[parameter(mandatory=$true, HelpMessage="Azure Stack One Node host address or name such as '1.2.3.4'")]
|
||||
[string] $HostComputer,
|
||||
[Parameter(HelpMessage="The Domain suffix of the environment VMs")]
|
||||
[string] $DomainSuffix = 'azurestack.local',
|
||||
[parameter(HelpMessage="NAT computer name in this Azure Stack Instance")]
|
||||
[string] $natServer = "mas-bgpnat01",
|
||||
[parameter(HelpMessage="Administrator user name of this Azure Stack Instance")]
|
||||
[string] $User = "administrator",
|
||||
[parameter(mandatory=$true, HelpMessage="Administrator password used to deploy this Azure Stack instance")]
|
||||
[securestring] $Password
|
||||
)
|
||||
|
||||
$Domain = $DomainSuffix
|
||||
|
||||
$UserCred = "$Domain\$User"
|
||||
$credential = New-Object System.Management.Automation.PSCredential -ArgumentList $UserCred, $Password
|
||||
|
||||
$nat = "$natServer.$Domain"
|
||||
|
||||
Write-Verbose "Remoting to the Azure Stack host $HostComputer..." -Verbose
|
||||
return Invoke-Command -ComputerName "$HostComputer" -Credential $credential -ScriptBlock `
|
||||
{
|
||||
Write-Verbose "Remoting to the Azure Stack NAT server $using:nat..." -Verbose
|
||||
Invoke-Command -ComputerName "$using:nat" -Credential $using:credential -ScriptBlock `
|
||||
{
|
||||
Write-Verbose "Obtaining external IP..." -Verbose
|
||||
Get-NetIPConfiguration | Where-Object { $_.IPv4DefaultGateway -ne $null } | ForEach-Object { $_.IPv4Address.IPAddress }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Export-ModuleMember Get-AzureStackNatServerAddress
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Add VPN connection to an Azure Stack instance
|
||||
#>
|
||||
function Add-AzureStackVpnConnection {
|
||||
|
||||
function Add-AzsVpnConnection {
|
||||
param (
|
||||
[parameter(HelpMessage="Azure Stack VPN Connection Name such as 'my-poc'")]
|
||||
[parameter(HelpMessage = "Azure Stack VPN Connection Name such as 'my-poc'")]
|
||||
[string] $ConnectionName = "azurestack",
|
||||
|
||||
[parameter(mandatory=$true, HelpMessage="External IP of the Azure Stack NAT VM such as '1.2.3.4'")]
|
||||
|
||||
[parameter(mandatory = $true, HelpMessage = "External IP of the Azure Stack NAT VM such as '1.2.3.4'")]
|
||||
[string] $ServerAddress,
|
||||
|
||||
[parameter(mandatory=$true, HelpMessage="Administrator password used to deploy this Azure Stack instance")]
|
||||
[parameter(mandatory = $true, HelpMessage = "Administrator password used to deploy this Azure Stack instance")]
|
||||
[securestring] $Password
|
||||
)
|
||||
|
||||
$existingConnection = Get-VpnConnection -Name $ConnectionName -ErrorAction Ignore
|
||||
if ($existingConnection -ne $null) {
|
||||
if ($existingConnection) {
|
||||
Write-Verbose "Updating Azure Stack VPN connection named $ConnectionName" -Verbose
|
||||
rasdial $ConnectionName /d
|
||||
Remove-VpnConnection -name $ConnectionName -Force -ErrorAction Ignore
|
||||
|
@ -216,28 +43,25 @@ function Add-AzureStackVpnConnection {
|
|||
return $connection
|
||||
}
|
||||
|
||||
Export-ModuleMember Add-AzureStackVpnConnection
|
||||
Export-ModuleMember -Function 'Add-AzsVpnConnection'
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Connects to Azure Stack via VPN
|
||||
#>
|
||||
function Connect-AzureStackVpn {
|
||||
|
||||
function Connect-AzsVpn {
|
||||
param (
|
||||
[parameter(HelpMessage="Azure Stack VPN Connection Name such as 'my-poc'")]
|
||||
[parameter(HelpMessage = "Azure Stack VPN Connection Name such as 'my-poc'")]
|
||||
[string] $ConnectionName = "azurestack",
|
||||
[Parameter(HelpMessage="The Domain suffix of the environment VMs")]
|
||||
[string] $DomainSuffix = 'azurestack.local',
|
||||
[parameter(HelpMessage="Certificate Authority computer name in this Azure Stack Instance")]
|
||||
[string] $Remote = "mas-ca01",
|
||||
[parameter(HelpMessage="Administrator user name of this Azure Stack Instance")]
|
||||
[parameter(HelpMessage = "Administrator user name of this Azure Stack Instance")]
|
||||
[string] $User = "administrator",
|
||||
[parameter(mandatory=$true, HelpMessage="Administrator password used to deploy this Azure Stack instance")]
|
||||
[securestring] $Password
|
||||
[parameter(mandatory = $true, HelpMessage = "Administrator password used to deploy this Azure Stack instance")]
|
||||
[securestring] $Password,
|
||||
[parameter(HelpMessage = "Indicate whether to retrieve and trust certificates from the environment after establishing a VPN connection")]
|
||||
[bool] $RetrieveCertificates = $true
|
||||
)
|
||||
|
||||
$Domain = $DomainSuffix
|
||||
|
||||
Write-Verbose "Connecting to Azure Stack VPN using connection named $ConnectionName..." -Verbose
|
||||
|
||||
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
|
||||
|
@ -248,150 +72,73 @@ function Connect-AzureStackVpn {
|
|||
|
||||
$azshome = "$env:USERPROFILE\Documents\$ConnectionName"
|
||||
|
||||
Write-Verbose "Connection-specific files will be saved in $azshome" -Verbose
|
||||
if ($RetrieveCertificates) {
|
||||
Write-Verbose "Connection-specific files will be saved in $azshome" -Verbose
|
||||
|
||||
New-Item $azshome -ItemType Directory -Force | Out-Null
|
||||
New-Item $azshome -ItemType Directory -Force | Out-Null
|
||||
|
||||
$UserCred = "$Domain\$User"
|
||||
$credential = New-Object System.Management.Automation.PSCredential -ArgumentList $UserCred, $Password
|
||||
$hostIP = (Get-VpnConnection -Name $ConnectionName).ServerAddress
|
||||
|
||||
Write-Verbose "Retrieving Azure Stack Root Authority certificate..." -Verbose
|
||||
$cert = Invoke-Command -ComputerName "$Remote.$Domain" -ScriptBlock { Get-ChildItem cert:\currentuser\root | where-object {$_.Subject -eq "CN=AzureStackCertificationAuthority, DC=AzureStack, DC=local"} } -Credential $credential
|
||||
$UserCred = ".\$User"
|
||||
$credential = New-Object System.Management.Automation.PSCredential -ArgumentList $UserCred, $Password
|
||||
|
||||
if($cert -ne $null) {
|
||||
if($cert.GetType().IsArray) {
|
||||
$cert = $cert[0] # take any that match the subject if multiple certs were deployed
|
||||
Write-Verbose "Retrieving Azure Stack Root Authority certificate..." -Verbose
|
||||
$cert = Invoke-Command -ComputerName "$hostIP" -ScriptBlock { Get-ChildItem cert:\currentuser\root | where-object {$_.Subject -like "*AzureStackSelfSignedRootCert*"} } -Credential $credential
|
||||
|
||||
if ($cert) {
|
||||
if ($cert.GetType().IsArray) {
|
||||
$cert = $cert[0] # take any that match the subject if multiple certs were deployed
|
||||
}
|
||||
|
||||
$certFilePath = "$azshome\CA.cer"
|
||||
|
||||
Write-Verbose "Saving Azure Stack Root certificate in $certFilePath..." -Verbose
|
||||
|
||||
Export-Certificate -Cert $cert -FilePath $certFilePath -Force | Out-Null
|
||||
|
||||
Write-Verbose "Installing Azure Stack Root certificate for the current user..." -Verbose
|
||||
|
||||
Write-Progress "LOOK FOR CERT ACCEPTANCE PROMPT ON YOUR SCREEN!"
|
||||
|
||||
Import-Certificate -CertStoreLocation cert:\currentuser\root -FilePath $certFilePath
|
||||
}
|
||||
else {
|
||||
Write-Error "Certificate has not been retrieved!"
|
||||
}
|
||||
|
||||
$certFilePath = "$azshome\CA.cer"
|
||||
|
||||
Write-Verbose "Saving Azure Stack Root certificate in $certFilePath..." -Verbose
|
||||
|
||||
Export-Certificate -Cert $cert -FilePath $certFilePath -Force | Out-Null
|
||||
|
||||
Write-Verbose "Installing Azure Stack Root certificate for the current user..." -Verbose
|
||||
|
||||
Write-Progress "LOOK FOR CERT ACCEPTANCE PROMPT ON YOUR SCREEN!"
|
||||
|
||||
Import-Certificate -CertStoreLocation cert:\currentuser\root -FilePath $certFilePath
|
||||
}
|
||||
else {
|
||||
Write-Error "Certificate has not been retrieved!"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Export-ModuleMember Connect-AzureStackVpn
|
||||
Export-ModuleMember -Function 'Connect-AzsVpn'
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Retrieve the admin token and subscription ID needed to make REST calls directly to Azure Resource Manager
|
||||
Connecting to your environment requires that you obtain the value of your Directory Tenant ID.
|
||||
For **Azure Active Directory** environments provide your directory tenant name.
|
||||
#>
|
||||
function Get-AzureStackAdminSubTokenHeader {
|
||||
param (
|
||||
[parameter(mandatory=$true, HelpMessage="Name of the Azure Stack Environment")]
|
||||
[string] $EnvironmentName,
|
||||
|
||||
[parameter(mandatory=$true, HelpMessage="TenantID of Identity Tenant")]
|
||||
[string] $tenantID,
|
||||
|
||||
[parameter(HelpMessage="Credentials to retrieve token header for")]
|
||||
[System.Management.Automation.PSCredential] $azureStackCredentials,
|
||||
|
||||
[parameter(HelpMessage="Name of the Administrator subscription")]
|
||||
[string] $subscriptionName = "Default Provider Subscription"
|
||||
)
|
||||
|
||||
$azureStackEnvironment = Get-AzureRmEnvironment -Name $EnvironmentName -ErrorAction SilentlyContinue
|
||||
if($azureStackEnvironment -ne $null) {
|
||||
$ARMEndpoint = $azureStackEnvironment.ResourceManagerUrl
|
||||
}
|
||||
else {
|
||||
Write-Error "The Azure Stack Admin environment with the name $EnvironmentName does not exist. Create one with Add-AzureStackAzureRmEnvironment." -ErrorAction Stop
|
||||
}
|
||||
|
||||
if(-not $azureStackCredentials){
|
||||
$azureStackCredentials = Get-Credential
|
||||
}
|
||||
|
||||
try{
|
||||
Invoke-RestMethod -Method Get -Uri "$($ARMEndpoint.ToString().TrimEnd('/'))/metadata/endpoints?api-version=2015-01-01" -ErrorAction Stop | Out-Null
|
||||
}catch{
|
||||
Write-Error "The specified ARM endpoint: $ArmEndpoint is not valid for this environment. Please make sure you are using the correct administrator ARM endpoint for this environment." -ErrorAction Stop
|
||||
}
|
||||
|
||||
$authority = $azureStackEnvironment.ActiveDirectoryAuthority
|
||||
$activeDirectoryServiceEndpointResourceId = $azureStackEnvironment.ActiveDirectoryServiceEndpointResourceId
|
||||
|
||||
Login-AzureRmAccount -EnvironmentName $EnvironmentName -TenantId $tenantID -Credential $azureStackCredentials | Out-Null
|
||||
|
||||
try {
|
||||
$subscription = Get-AzureRmSubscription -SubscriptionName $subscriptionName
|
||||
}
|
||||
catch {
|
||||
Write-Error "Verify that the login credentials are for the administrator and that the specified ARM endpoint: $ArmEndpoint is the valid administrator ARM endpoint for this environment." -ErrorAction Stop
|
||||
}
|
||||
|
||||
$subscription | Select-AzureRmSubscription | Out-Null
|
||||
|
||||
$powershellClientId = "0a7bdc5c-7b57-40be-9939-d4c5fc7cd417"
|
||||
|
||||
$savedWarningPreference = $WarningPreference
|
||||
$WarningPreference = 'SilentlyContinue'
|
||||
|
||||
$adminToken = Get-AzureStackToken `
|
||||
-Authority $authority `
|
||||
-Resource $activeDirectoryServiceEndpointResourceId `
|
||||
-AadTenantId $tenantID `
|
||||
-ClientId $powershellClientId `
|
||||
-Credential $azureStackCredentials
|
||||
|
||||
$WarningPreference = $savedWarningPreference
|
||||
|
||||
$headers = @{ Authorization = ("Bearer $adminToken") }
|
||||
|
||||
return $subscription.SubscriptionId, $headers
|
||||
}
|
||||
|
||||
Export-ModuleMember Get-AzureStackAdminSubTokenHeader
|
||||
|
||||
function Get-AADTenantGUID () {
|
||||
function Get-AzsDirectoryTenantId () {
|
||||
[CmdletBinding(DefaultParameterSetName = 'AzureActiveDirectory')]
|
||||
param(
|
||||
[parameter(mandatory=$true, HelpMessage="AAD Directory Tenant <myaadtenant.onmicrosoft.com>")]
|
||||
[string] $AADTenantName = "",
|
||||
[parameter(mandatory=$false, HelpMessage="Azure Cloud")]
|
||||
[ValidateSet("AzureCloud","AzureChinaCloud","AzureUSGovernment","AzureGermanCloud")]
|
||||
[string] $AzureCloud = "AzureCloud"
|
||||
)
|
||||
$ADauth = (Get-AzureRmEnvironment -Name $AzureCloud).ActiveDirectoryAuthority
|
||||
$endpt = "{0}{1}/.well-known/openid-configuration" -f $ADauth, $AADTenantName
|
||||
$OauthMetadata = (Invoke-WebRequest -UseBasicParsing $endpt).Content | ConvertFrom-Json
|
||||
$AADid = $OauthMetadata.Issuer.Split('/')[3]
|
||||
$AADid
|
||||
}
|
||||
|
||||
Export-ModuleMember Get-AADTenantGUID
|
||||
|
||||
function Get-DirectoryTenantID () {
|
||||
[CmdletBinding(DefaultParameterSetName='AzureActiveDirectory')]
|
||||
param(
|
||||
[Parameter(Mandatory=$true, ParameterSetName='ADFS')]
|
||||
[Parameter(Mandatory = $true, ParameterSetName = 'ADFS')]
|
||||
[switch] $ADFS,
|
||||
|
||||
[parameter(mandatory=$true,ParameterSetName='AzureActiveDirectory', HelpMessage="AAD Directory Tenant <myaadtenant.onmicrosoft.com>")]
|
||||
[string] $AADTenantName = "",
|
||||
[parameter(mandatory = $true, ParameterSetName = 'AzureActiveDirectory', HelpMessage = "AAD Directory Tenant <myaadtenant.onmicrosoft.com>")]
|
||||
[string] $AADTenantName,
|
||||
|
||||
[Parameter(Mandatory=$true, ParameterSetName='ADFS')]
|
||||
[Parameter(Mandatory=$true, ParameterSetName='AzureActiveDirectory')]
|
||||
[Parameter(Mandatory = $true, ParameterSetName = 'ADFS')]
|
||||
[Parameter(Mandatory = $true, ParameterSetName = 'AzureActiveDirectory')]
|
||||
[string] $EnvironmentName
|
||||
)
|
||||
|
||||
$ADauth = (Get-AzureRmEnvironment -Name $EnvironmentName).ActiveDirectoryAuthority
|
||||
if($ADFS -eq $true){
|
||||
if(-not (Get-AzureRmEnvironment -Name $EnvironmentName).EnableAdfsAuthentication){
|
||||
if ($ADFS -eq $true) {
|
||||
if (-not (Get-AzureRmEnvironment -Name $EnvironmentName).EnableAdfsAuthentication) {
|
||||
Write-Error "This environment is not configured to do ADFS authentication." -ErrorAction Stop
|
||||
}
|
||||
return $(Invoke-RestMethod $("{0}/.well-known/openid-configuration" -f $ADauth.TrimEnd('/'))).issuer.TrimEnd('/').Split('/')[-1]
|
||||
}else{
|
||||
}
|
||||
else {
|
||||
$endpt = "{0}{1}/.well-known/openid-configuration" -f $ADauth, $AADTenantName
|
||||
$OauthMetadata = (Invoke-WebRequest -UseBasicParsing $endpt).Content | ConvertFrom-Json
|
||||
$AADid = $OauthMetadata.Issuer.Split('/')[3]
|
||||
|
@ -399,4 +146,4 @@ function Get-DirectoryTenantID () {
|
|||
}
|
||||
}
|
||||
|
||||
Export-ModuleMember Get-DirectoryTenantID
|
||||
Export-ModuleMember Get-AzsDirectoryTenantId
|
||||
|
|
После Ширина: | Высота: | Размер: 2.8 MiB |
|
@ -1,12 +1,14 @@
|
|||
# Connection Scripts
|
||||
|
||||
As a prerequisite, make sure that you installed the correct PowerShell modules and versions:
|
||||
|
||||
```powershell
|
||||
Install-Module -Name 'AzureRm.Bootstrapper' -Scope CurrentUser
|
||||
Install-AzureRmProfile -profile '2017-03-09-profile' -Force -Scope CurrentUser
|
||||
Install-Module -Name AzureStack -RequiredVersion 1.2.9 -Scope CurrentUser
|
||||
Install-Module -Name AzureStack -RequiredVersion 1.2.10 -Scope CurrentUser
|
||||
```
|
||||
|
||||
This tool set allows you to connect to an Azure Stack PoC (Proof of Concept) instance from an external personal laptop. You can then access the portal or log into that environment via PowerShell.
|
||||
This tool set allows you to connect to an Azure Stack Development Kit (ASDK) instance from an external personal laptop. You can then access the portal or log into that environment via PowerShell.
|
||||
|
||||
Instructions below are relative to the .\Connect folder of the [AzureStack-Tools repo](..).
|
||||
|
||||
|
@ -14,27 +16,25 @@ Instructions below are relative to the .\Connect folder of the [AzureStack-Tools
|
|||
Import-Module .\AzureStack.Connect.psm1
|
||||
```
|
||||
|
||||
# VPN to Azure Stack Proof of Concept
|
||||
## VPN to Azure Stack Development Kit
|
||||
|
||||
The [Connect to Azure Stack](https://docs.microsoft.com/en-us/azure/azure-stack/azure-stack-connect-azure-stack) document describes ways to connect to your Azure Stack Proof of Concept environment.
|
||||
![VPN to Azure Stack Development Kit](/Connect/VPNConnection.gif)
|
||||
|
||||
One method is to establish a split tunnel VPN connection to an Azure Stack PoC.
|
||||
This allows your client computer to become part of the Azure Stack PoC network system and therefore resolve Azure Stack endpoints.
|
||||
The [Connect to Azure Stack](https://docs.microsoft.com/en-us/azure/azure-stack/azure-stack-connect-azure-stack) document describes ways to connect to your Azure Stack Development Kit environment.
|
||||
|
||||
The tool will also download root certificate of the targeted Azure Stack PoC instance locally to your client computer.
|
||||
One method is to establish a split tunnel VPN connection to an Azure Stack Development Kit.
|
||||
This allows your client computer to become part of the Azure Stack Development Kit network system and therefore resolve Azure Stack endpoints.
|
||||
|
||||
The tool will also download the root certificate of the targeted Azure Stack Development Kit instance locally to your client computer.
|
||||
This will ensure that SSL sites of the target Azure Stack installation are trusted by your client when accessed from the browser or from the command-line tools.
|
||||
|
||||
To connect to Azure Stack PoC via VPN, first locate the external BGP-NAT01 address of the target installation.
|
||||
If you specified a static IP for the BGP-NAT during deployment of the Azure Stack PoC, then use it in the connection example below.
|
||||
To connect to an Azure Stack Development Kit via VPN, you will need to know the host IP address of the target installation.
|
||||
|
||||
If you did not specify a static IP then the BGP-NAT was configured with DHCP. In that case, **read the below section** to obtain your BGP-NAT VM IP by using the IP address of the Azure Stack PoC host (which should be known to you after deployment).
|
||||
|
||||
The commands below need to access the Azure Stack PoC host computer and Azure Stack CA, so they need to be trusted hosts in PowerShell. Run PowerShell as administrator and modify TrustedHosts as follows.
|
||||
The commands below need to access the Azure Stack Development Kit host computer, so it needs to be a trusted host in PowerShell. Run PowerShell as administrator and modify TrustedHosts as follows.
|
||||
|
||||
```powershell
|
||||
# Add Azure Stack PoC host to the trusted hosts on your client computer
|
||||
Set-Item wsman:\localhost\Client\TrustedHosts -Value "<Azure Stack host address>" -Concatenate
|
||||
Set-Item wsman:\localhost\Client\TrustedHosts -Value mas-ca01.azurestack.local -Concatenate
|
||||
# Add Azure Stack Development Kit host to the trusted hosts on your client computer
|
||||
Set-Item wsman:\localhost\Client\TrustedHosts -Value "<Azure Stack host IP address>" -Concatenate
|
||||
```
|
||||
|
||||
For the VPN connection, use the admin password provided at the time of the Azure Stack deployment.
|
||||
|
@ -47,51 +47,43 @@ Then connect your client computer to the environment as follows.
|
|||
|
||||
```powershell
|
||||
# Create VPN connection entry for the current user
|
||||
Add-AzureStackVpnConnection -ServerAddress <NAT IP> -Password $Password
|
||||
Add-AzsVpnConnection -ServerAddress <Host IP Address> -Password $Password
|
||||
|
||||
# Connect to the Azure Stack instance. This command can be used multiple times.
|
||||
Connect-AzureStackVpn -Password $Password
|
||||
Connect-AzsVpn -Password $Password
|
||||
```
|
||||
|
||||
## Obtain the NAT IP address with the Azure Stack PoC host address
|
||||
|
||||
This command is helpful if you do not immediately know the NAT IP of the Azure Stack PoC you are trying to connect to. You must know the host address of your Azure Stack PoC.
|
||||
|
||||
```powershell
|
||||
$natIp = Get-AzureStackNatServerAddress -HostComputer "<Azure Stack host address>" -Password $Password
|
||||
```
|
||||
## Configure Azure Stack PowerShell Environment
|
||||
![Adding Azure Stack Environment](/Connect/EnvironmentAdd.gif)
|
||||
|
||||
|
||||
# Configure Azure Stack PowerShell Environment
|
||||
|
||||
One method of deploying templates and interacting with your Azure Stack PoC is to access it via PowerShell.
|
||||
One method of deploying templates and interacting with your Azure Stack Development Kit is to access it via PowerShell.
|
||||
|
||||
See the [Azure Stack Install PowerShell](https://docs.microsoft.com/en-us/azure/azure-stack/azure-stack-connect-powershell) article to download and install the correct PowerShell modules for Azure Stack.
|
||||
|
||||
AzureRM cmdlets can be targeted at multiple Azure clouds such as Azure China, Government, and Azure Stack.
|
||||
To target your Azure Stack instance as a tenant, an AzureRM environment needs to be registered as follows. The ARM endpoint below is the tenant default for a one-node environment. AzureRM cmdlets can be targeted at multiple Azure clouds such as Azure China, Government, and Azure Stack.
|
||||
|
||||
To target your Azure Stack instance as a tenant, an AzureRM environment needs to be registered as follows. The ARM endpoint below is the tenant default for a one-node environment.
|
||||
|
||||
```powershell
|
||||
Add-AzureStackAzureRmEnvironment -Name AzureStack -ArmEndpoint "https://management.local.azurestack.external"
|
||||
Add-AzureRMEnvironment -Name AzureStack -ArmEndpoint "https://management.local.azurestack.external"
|
||||
```
|
||||
|
||||
To create an administrator environment use the below. The ARM endpoint below is the administrator default for a one-node environment.
|
||||
|
||||
```powershell
|
||||
Add-AzureStackAzureRmEnvironment -Name AzureStackAdmin -ArmEndpoint "https://adminmanagement.local.azurestack.external"
|
||||
Add-AzureRMEnvironment -Name AzureStackAdmin -ArmEndpoint "https://adminmanagement.local.azurestack.external"
|
||||
```
|
||||
|
||||
Connecting to your environment requires that you obtain the value of your Directory Tenant ID. For **Azure Active Directory** environments provide your directory tenant name:
|
||||
|
||||
```powershell
|
||||
$TenantID = Get-DirectoryTenantID -AADTenantName "<mydirectorytenant>.onmicrosoft.com" -EnvironmentName AzureStackAdmin
|
||||
$TenantID = Get-AzsDirectoryTenantId -AADTenantName "<mydirectorytenant>.onmicrosoft.com" -EnvironmentName AzureStackAdmin
|
||||
```
|
||||
|
||||
For **ADFS** environments use the following:
|
||||
|
||||
```powershell
|
||||
$TenantID = Get-DirectoryTenantID -ADFS -EnvironmentName AzureStackAdmin
|
||||
$TenantID = Get-AzsDirectoryTenantId -ADFS -EnvironmentName AzureStackAdmin
|
||||
```
|
||||
|
||||
After registering the AzureRM environment, cmdlets can be easily targeted at your Azure Stack instance. For example:
|
||||
|
@ -105,25 +97,3 @@ Similarly, for targeting the administrator endpoints:
|
|||
```powershell
|
||||
Login-AzureRmAccount -EnvironmentName "AzureStackAdmin" -TenantId $TenantID
|
||||
```
|
||||
|
||||
## Register Azure RM Providers on new subscriptions
|
||||
|
||||
If you are intending to use newly created subscriptions via PowerShell, CLI or direct API calls before deploying any templates or using the Portal, you need to ensure that resource providers are registered on the subscription.
|
||||
To register providers on the current subscription, do the following.
|
||||
|
||||
```powershell
|
||||
Register-AllAzureRmProviders
|
||||
```
|
||||
|
||||
To register all resource providers on all your subscriptions after logging in using Add-AzureRmAccount do the following. Note that this can take a while.
|
||||
|
||||
```powershell
|
||||
Register-AllAzureRmProvidersOnAllSubscriptions
|
||||
```
|
||||
|
||||
These registrations are idempotent and can be run multiple times. If provider has already been registered, it will simply be reported in the output.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -12,39 +12,19 @@ Describe $script:ModuleName {
|
|||
Get-Module -Name $script:ModuleName |
|
||||
Should Not Be $null
|
||||
}
|
||||
|
||||
It 'Register-AllAzureRmProvidersOnAllSubscriptions should be exported' {
|
||||
Get-Command -Name Register-AllAzureRmProvidersOnAllSubscriptions -ErrorAction SilentlyContinue |
|
||||
Should Not Be $null
|
||||
}
|
||||
|
||||
It 'Register-AllAzureRmProviders should be exported' {
|
||||
Get-Command -Name Register-AllAzureRmProviders -ErrorAction SilentlyContinue |
|
||||
Should Not Be $null
|
||||
}
|
||||
|
||||
It 'Get-AzureStackAadTenant should be exported' {
|
||||
Get-Command -Name Get-AzureStackAadTenant -ErrorAction SilentlyContinue |
|
||||
Should Not Be $null
|
||||
}
|
||||
|
||||
It 'Add-AzureStackAzureRmEnvironment should be exported' {
|
||||
Get-Command -Name Add-AzureStackAzureRmEnvironment -ErrorAction SilentlyContinue |
|
||||
It 'Add-AzsEnvironment should be exported' {
|
||||
Get-Command -Name Add-AzsEnvironment -ErrorAction SilentlyContinue |
|
||||
Should Not Be $null
|
||||
}
|
||||
|
||||
It 'Get-AzureStackNatServerAddress should be exported' {
|
||||
Get-Command -Name Get-AzureStackNatServerAddress -ErrorAction SilentlyContinue |
|
||||
It 'Add-AzsVpnConnection should be exported' {
|
||||
Get-Command -Name Add-AzsVpnConnection -ErrorAction SilentlyContinue |
|
||||
Should Not Be $null
|
||||
}
|
||||
|
||||
It 'Add-AzureStackVpnConnection should be exported' {
|
||||
Get-Command -Name Add-AzureStackVpnConnection -ErrorAction SilentlyContinue |
|
||||
Should Not Be $null
|
||||
}
|
||||
|
||||
It 'Connect-AzureStackVpn should be exported' {
|
||||
Get-Command -Name Connect-AzureStackVpn -ErrorAction SilentlyContinue |
|
||||
It 'Connect-AzsVpn should be exported' {
|
||||
Get-Command -Name Connect-AzsVpn -ErrorAction SilentlyContinue |
|
||||
Should Not Be $null
|
||||
}
|
||||
}
|
||||
|
@ -68,36 +48,25 @@ InModuleScope $script:ModuleName {
|
|||
$EnvironmentName = $global:EnvironmentName
|
||||
|
||||
Set-Item wsman:\localhost\Client\TrustedHosts -Value $HostComputer -Concatenate
|
||||
Set-Item wsman:\localhost\Client\TrustedHosts -Value mas-ca01.azurestack.local -Concatenate
|
||||
Set-Item wsman:\localhost\Client\TrustedHosts -Value Azs-ca01.azurestack.local -Concatenate
|
||||
|
||||
Describe 'ConnectModule - Accessing Environment Data' {
|
||||
It 'Recovered AAD Tenant ID should be correct' {
|
||||
$global:AadTenantID = Get-AzureStackAadTenant -HostComputer $HostComputer -User $AdminUser -Password $AdminPassword
|
||||
Write-Verbose "Aad Tenant ID is $global:AadTenantID" -Verbose
|
||||
$global:AadTenantID | Should Not Be $null
|
||||
}
|
||||
|
||||
It 'Get-AzureStackNatServerAddress should return valid NAT address' {
|
||||
$script:NatIPAddress = Get-AzureStackNatServerAddress -natServer $natServer -HostComputer $HostComputer -User $AdminUser -Password $AdminPassword
|
||||
Write-Verbose "Returned NAT IP Address of $natIPAddress" -Verbose
|
||||
[IPAddress]$script:NatIPAddress | Should Not Be $null
|
||||
}
|
||||
|
||||
It 'Add-AzureStackVpnConnection should correctly return a VPN connection to a One Node' {
|
||||
Add-AzureStackVpnConnection -ServerAddress $script:NatIPAddress -ConnectionName $VPNConnectionName -Password $AdminPassword
|
||||
It 'Add-AzsVpnConnection should correctly return a VPN connection to a One Node' {
|
||||
Add-AzsVpnConnection -ServerAddress $script:NatIPAddress -ConnectionName $VPNConnectionName -Password $AdminPassword
|
||||
Get-VpnConnection -Name $VPNConnectionName | Should Not Be $null
|
||||
}
|
||||
|
||||
It 'Connect-AzureStackVpn should successfully connect to a One Node environment' {
|
||||
{Connect-AzureStackVpn -ConnectionName $VPNConnectionName -User $AdminUser -Password $AdminPassword} | Should Not Throw
|
||||
It 'Connect-AzsVpn should successfully connect to a One Node environment' {
|
||||
{Connect-AzsVpn -ConnectionName $VPNConnectionName -User $AdminUser -Password $AdminPassword} | Should Not Throw
|
||||
}
|
||||
|
||||
It 'Add-AzureStackAzureRmEnvironment should successfully add a an administrator environment' {
|
||||
Add-AzureStackAzureRmEnvironment -ArmEndpoint $armEndpoint -Name $EnvironmentName
|
||||
It 'Add-AzsEnvironment should successfully add a an administrator environment' {
|
||||
Add-AzsEnvironment -ArmEndpoint $armEndpoint -Name $EnvironmentName
|
||||
Get-AzureRmEnvironment -Name $EnvironmentName | Should Not Be $null
|
||||
}
|
||||
|
||||
It 'User should be able to login to environment successfully created by Add-AzureStackAzureRmEnvironment' {
|
||||
It 'User should be able to login to environment successfully created by Add-AzsEnvironment' {
|
||||
Write-Verbose "Aad Tenant ID is $global:AadTenantID" -Verbose
|
||||
Write-Verbose "Passing credential to Login-AzureRmAccount" -Verbose
|
||||
{Login-AzureRmAccount -EnvironmentName $EnvironmentName -TenantId $global:AadTenantID -Credential $global:AzureStackLoginCredentials} | Should Not Throw
|
||||
|
@ -107,25 +76,25 @@ InModuleScope $script:ModuleName {
|
|||
Get-AzureRmResourceGroup | Should Not Be $null
|
||||
}
|
||||
|
||||
It 'Get-AzureStackAdminSubTokenHeader should retrieve a valid admin token' {
|
||||
$subID, $headers = Get-AzureStackAdminSubTokenHeader -TenantID $global:AadTenantID -EnvironmentName $EnvironmentName -AzureStackCredentials $stackLoginCreds
|
||||
It 'Get-AzsAdminSubTokenheader should retrieve a valid admin token' {
|
||||
$subID, $headers = Get-AzsAdminSubTokenheader -TenantID $global:AadTenantID -EnvironmentName $EnvironmentName -AzureStackCredentials $stackLoginCreds
|
||||
Write-Verbose "Admin subscription ID was $subID" -Verbose
|
||||
Write-Verbose "Acquired token was $headers.Authorization" -Verbose
|
||||
$headers.Authorization | Should Not Be $null
|
||||
$subID | Should Not Be $null
|
||||
}
|
||||
|
||||
It 'Register-AllAzureRmProviders should register all resource providers for the current subscription' {
|
||||
Register-AllAzureRmProviders
|
||||
It 'Register-AzsProvider should register all resource providers for the current subscription' {
|
||||
Register-AzsProvider
|
||||
$unRegisteredProviders = Get-AzureRmResourceProvider | Where-Object {$_.RegistrationState -ne "Registered"}
|
||||
$unRegisteredProviders | Should Be $null
|
||||
}
|
||||
|
||||
It 'Register-AllAzureRmProvidersOnAllSubscriptions should register all resource providers for all subscriptions' {
|
||||
Register-AllAzureRmProvidersOnAllSubscriptions
|
||||
It 'Register-AzsProviderOnAllSubscriptions should register all resource providers for all subscriptions' {
|
||||
Register-AzsProviderOnAllSubscriptions
|
||||
$unRegisteredProviders = Get-AzureRmResourceProvider | Where-Object {$_.RegistrationState -ne "Registered"}
|
||||
$unRegisteredProviders | Should Be $null
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
После Ширина: | Высота: | Размер: 5.7 MiB |
|
@ -1,71 +0,0 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# See LICENSE.txt in the project root for license information.
|
||||
|
||||
<#
|
||||
|
||||
.SYNOPSIS
|
||||
|
||||
Modify the boot entry and reboot the Azure Stack host back to the base Operating System, so that Azure Stack can be redeployed.
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
BootMenuNoKVM updates the boot configuration with the original entry, and then prompts to reboot the host.
|
||||
Because the default boot entry is set with this script, no KVM or manual selection of the boot entry is required as the machine restarts.
|
||||
|
||||
.EXAMPLE
|
||||
|
||||
Prompt user for the desired boot configuraiton and confirm reboot of the host so a redeployment of Azure Stack can begin.
|
||||
This does not require KVM access to the host for selection of the correct Operating System as the machine restarts.
|
||||
.\BootMenuNoKVM.ps1
|
||||
|
||||
.NOTES
|
||||
|
||||
You will need execute this script in an elevated PS console session.
|
||||
|
||||
#>
|
||||
|
||||
#requires -version 4.0
|
||||
#requires –runasadministrator
|
||||
|
||||
#region Menu
|
||||
$prompt = ('Are you sure you want to configure this onetime boot value and reboot now?' + $title)
|
||||
$Yes = New-Object System.Management.Automation.Host.ChoiceDescription '&Yes','Reboot now'
|
||||
$Abort = New-Object System.Management.Automation.Host.ChoiceDescription '&Abort','Abort'
|
||||
$options = [System.Management.Automation.Host.ChoiceDescription[]] ($Yes,$Abort)
|
||||
#endregion
|
||||
|
||||
|
||||
$bootOptions = bcdedit /enum | Select-String 'path' -Context 2,1
|
||||
cls
|
||||
|
||||
#region Selection
|
||||
write-host 'This script specifies a one-time display order to be used for the next boot. Afterwards, the computer reverts to the original display order.' -ForegroundColor Yellow
|
||||
write-host 'Select the Operating System to boot from:' -ForegroundColor Cyan
|
||||
$menu = @{}
|
||||
for ($i=1;$i -le $bootOptions.count; $i++) {
|
||||
Write-Host "$i. $($bootOptions[$i-1].Context.PostContext[0] -replace '^description +')"
|
||||
$menu.Add($i,($bootOptions[$i-1].Context.PreContext[0]))
|
||||
}
|
||||
|
||||
[int]$ans = Read-Host 'Enter selection'
|
||||
$selection = $menu.Item($ans)
|
||||
#endregion
|
||||
|
||||
$BootEntry = $selection -replace '^identifier +'
|
||||
if($Selection -ne $null)
|
||||
{
|
||||
$choice = $host.ui.PromptForChoice($title,$prompt,$options,0)
|
||||
if ($choice -eq 0)
|
||||
{
|
||||
$BootID = '"' + $BootEntry + '"'
|
||||
bcdedit /bootsequence $BootID
|
||||
Restart-Computer
|
||||
}
|
||||
else
|
||||
{
|
||||
write-host 'No changes are made to the boot configuration. Exiting..' -ForegroundColor Yellow
|
||||
Break
|
||||
}
|
||||
}
|
||||
else
|
||||
{write-host 'Not a valid selection. No changes are made to the boot configuration. Exiting..' -ForegroundColor Yellow}
|
После Ширина: | Высота: | Размер: 3.0 MiB |
|
@ -1,220 +0,0 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# See LICENSE.txt in the project root for license information.
|
||||
|
||||
<#
|
||||
|
||||
.SYNOPSIS
|
||||
|
||||
Prepare the host to boot from the Azure Stack virtual harddisk.
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
PrepareBootFromVHD updates the boot configuration with an Azure Stack entry.
|
||||
It will verify if the disk that hosts the CloudBuilder.vhdx contains the required free disk space, Optionally copy drivers and an unattend.xml that does not require KVM access.
|
||||
|
||||
|
||||
.PARAMETER CloudBuilderDiskPath
|
||||
|
||||
Path to the CloudBuilder.vhdx. This parameter is mandatory.
|
||||
|
||||
.PARAMETER DriverPath
|
||||
|
||||
This optional parameter allows you to add additional drivers for the host in the virtual harddisk. Specify the path that contains the drivers and all its content wil be copied the to CloudBuilder.vhdx.
|
||||
|
||||
.PARAMETER ApplyUnattend
|
||||
|
||||
ApplyUnattend is a switch parameter. If this parameter is specified, the configuration of the Operating System is automated.
|
||||
After the host reboots to the CloudBuilder.vhdx, the Operating System is automatically configured and you can connect to the host with RDP without KVM requirement.
|
||||
If this parameter is specified, you will be prompted for an local administrator password that is used for the unattend.xml.
|
||||
If this parameter is not specified, a minimal unattend.xml is used to enable Remote Desktop. KVM is required to configure the Operating System when booting from vs.vhdx for the first time.
|
||||
|
||||
.PARAMETER AdminPassword
|
||||
|
||||
The AdminPassword parameter is only used when the ApplyUnnatend parameter is set. The Password requires minimal 6 characters.
|
||||
|
||||
.EXAMPLE
|
||||
|
||||
Prepare the host to boot from CloudBuilder.vhdx. This requires KVM access to the host for configuring the Operating System.
|
||||
.\PrepareBootFromVHD.ps1 -CloudBuilderPath c:\CloudBuilder.vhdx -DriverPath c:\VhdDrivers
|
||||
|
||||
.EXAMPLE
|
||||
|
||||
Prepare the host to boot from CloudBuilder.vhdx. The Operating System is automatically configured with an unattend.xml.
|
||||
.\PrepareBootFromVHD.ps1 -CloudBuilderPath c:\CloudBuilder.vhdx -ApplyUnattend
|
||||
|
||||
.NOTES
|
||||
|
||||
You will need at least (120GB - Size of the CloudBuilder.vhdx file) of free disk space on the disk that contains the CloudBuilder.vhdx.
|
||||
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
Param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[String]$CloudBuilderDiskPath,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string[]]$DriverPath = $null,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[switch]$ApplyUnattend,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[String]$AdminPassword,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[String]$VHDLanguage = "en-US"
|
||||
)
|
||||
|
||||
$error.Clear()
|
||||
|
||||
#region Allow for manual override of PS (replace $PSScriptRoot with a path)
|
||||
$currentPath = $PSScriptRoot
|
||||
# $currentPath = 'C:\ForRTMBuilds'
|
||||
# $CloudBuilderDiskPath = 'C:\CloudBuilder.vhdx'
|
||||
#endregion
|
||||
|
||||
#region Check parameters and prerequisites
|
||||
|
||||
if (-not (Test-Path -Path $CloudBuilderDiskPath)) {
|
||||
Write-Host "Can't find CloudBuilder.vhdx." -ForegroundColor Red
|
||||
Exit
|
||||
}
|
||||
|
||||
if ((Get-DiskImage -ImagePath $CloudBuilderDiskPath).Attached) {
|
||||
Write-Host "CloudBuilder.vhdx is already mounted." -ForegroundColor Red
|
||||
Exit
|
||||
}
|
||||
|
||||
# Validate the CloudBuilder.vhdx is in a physical disk
|
||||
$cbhDriveLetter = (Get-Item $CloudBuilderDiskPath).PSDrive.Name
|
||||
|
||||
if (-not $cbhDriveLetter) {
|
||||
Write-Host "The given CloudBuilder.vhdx path is not a local path." -ForegroundColor Red
|
||||
Exit
|
||||
}
|
||||
else {
|
||||
$hostDisk = Get-Partition -DriveLetter $cbhDriveLetter | Get-Disk
|
||||
if ($hostDisk.Model -match 'Virtual Disk') {
|
||||
Write-Host "The CloudBuilder.vhdx is in a virtual hard disk, please place it in a physical disk." -ForegroundColor Red
|
||||
Exit
|
||||
}
|
||||
}
|
||||
|
||||
if ($ApplyUnattend) {
|
||||
# Check if unattend_NoKVM.xml is downloaded
|
||||
$unattendRawFile = Join-Path $currentPath 'unattend_NoKVM.xml'
|
||||
if (-not (Test-Path $unattendRawFile)) {
|
||||
Write-Host "-ApplyUnattend is specified, but unattend_NoKVM.xml is not downloaded to the same directory of this script." -ForegroundColor Red
|
||||
Exit
|
||||
}
|
||||
|
||||
# Check Admin password for unattend
|
||||
if(-not $AdminPassword) {
|
||||
while ($SecureAdminPassword.Length -le 6) {
|
||||
[System.Security.SecureString]$SecureAdminPassword = read-host 'Password for the local administrator account of the Azure Stack host. Requires 6 characters minimum' -AsSecureString
|
||||
}
|
||||
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureAdminPassword)
|
||||
$AdminPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
|
||||
Write-Host "The following password will be configured for the local administrator account of the Azure Stack host:"
|
||||
Write-Host $AdminPassword -ForegroundColor Cyan
|
||||
}
|
||||
}
|
||||
|
||||
# Validate disk space for expanding cloudbuilder.vhdx
|
||||
$cbhDiskSize = [math]::truncate((get-volume -DriveLetter $cbhDriveLetter).Size / 1GB)
|
||||
$cbhDiskRemaining = [math]::truncate((get-volume -DriveLetter $cbhDriveLetter).SizeRemaining / 1GB)
|
||||
$cbDiskSize = [math]::truncate((Get-Item $CloudBuilderDiskPath).Length / 1GB)
|
||||
$cbDiskSizeReq = 120
|
||||
if (($cbDiskSizeReq - $cbDiskSize) -ge $cbhDiskRemaining) {
|
||||
Write-Host 'Error: Insufficient disk space' -BackgroundColor Red
|
||||
Write-Host 'Cloudbuilder.vhdx is placed on' ((Get-Item $CloudBuilderDiskPath).PSDrive.Root) -ForegroundColor Yellow
|
||||
Write-Host 'When you boot from CloudBuilder.vhdx the virtual hard disk will be expanded to its full size of' $cbDiskSizeReq 'GB.' -ForegroundColor Yellow
|
||||
Write-Host ((Get-Item $CloudBuilderDiskPath).PSDrive.Root) 'does not contain enough free space.' -ForegroundColor Yellow
|
||||
Write-Host 'You need' ($cbDiskSizeReq - $cbDiskSize) 'GB of free disk space for a succesfull boot from CloudBuilder.vhdx, but' ((Get-Item $CloudBuilderDiskPath).PSDrive.Root) 'only has' $cbhDiskRemaining 'GB remaining.' -ForegroundColor Yellow
|
||||
Write-Host 'Ensure Cloudbuilder.vhdx is placed on a local disk that contains enough free space and rerun this script.' -ForegroundColor Yellow
|
||||
Write-Host 'Exiting..' -ForegroundColor Yellow
|
||||
Exit
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Prepare Azure Stack virtual harddisk
|
||||
|
||||
Write-Host "Preparing Azure Stack virtual harddisk"
|
||||
$cbdisk = Mount-DiskImage -ImagePath $CloudBuilderDiskPath -PassThru | Get-DiskImage | Get-Disk
|
||||
$partitions = $cbdisk | Get-Partition | Sort-Object -Descending -Property Size
|
||||
$CBDriveLetter = $partitions[0].DriveLetter
|
||||
|
||||
# ApplyUnattend
|
||||
if($ApplyUnattend) {
|
||||
Write-Host "Apply unattend.xml with given password and language" -ForegroundColor Cyan
|
||||
$UnattendedFile = Get-Content ($currentPath + '\unattend_NoKVM.xml')
|
||||
$UnattendedFile = ($UnattendedFile).Replace('%productkey%', '74YFP-3QFB3-KQT8W-PMXWJ-7M648')
|
||||
$UnattendedFile = ($UnattendedFile).Replace('%locale%', $VHDLanguage)
|
||||
$UnattendedFile = ($UnattendedFile).Replace('%adminpassword%', $AdminPassword)
|
||||
$UnattendedFile | Out-File ($CBDriveLetter+":\unattend.xml") -Encoding ascii
|
||||
}
|
||||
else {
|
||||
# Apply defautl unattend.xml if it exists
|
||||
$defaultUnattend = Join-Path $currentPath 'Unattend.xml'
|
||||
if (Test-Path $defaultUnattend) {
|
||||
Write-Host "Apply default unattend.xml to disable IE-ESC and enable remote desktop" -ForegroundColor Cyan
|
||||
Copy-Item $defaultUnattend -Destination ($CBDriveLetter + ':\') -Force
|
||||
}
|
||||
}
|
||||
|
||||
# Add drivers
|
||||
if (-not $DriverPath) {
|
||||
Write-Host "Apply given drivers" -ForegroundColor Cyan
|
||||
foreach ($subdirectory in $DriverPath) {
|
||||
Add-WindowsDriver -Driver $subdirectory -Path "$($CBDriveLetter):\" -Recurse
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Configure boot options
|
||||
|
||||
# Remove boot from previous deployment
|
||||
$bootOptions = bcdedit /enum | Select-String 'path' -Context 2,1
|
||||
$bootOptions | ForEach {
|
||||
if ((($_.Context.PreContext[1] -replace '^device +') -like '*CloudBuilder.vhdx*') `
|
||||
-and ((($_.Context.PostContext[0] -replace '^description +') -eq 'AzureStack TP2') `
|
||||
-or (($_.Context.PostContext[0] -replace '^description +') -eq 'Azure Stack'))) {
|
||||
Write-Host 'The boot configuration contains an existing CloudBuilder.vhdx entry' -ForegroundColor Cyan
|
||||
Write-Host 'Description:' ($_.Context.PostContext[0] -replace '^description +') -ForegroundColor Cyan
|
||||
Write-Host 'Device:' ($_.Context.PreContext[1] -replace '^device +') -ForegroundColor Cyan
|
||||
Write-Host 'Removing the old entry'
|
||||
$BootID = '"' + ($_.Context.PreContext[0] -replace '^identifier +') + '"'
|
||||
Write-Host 'bcdedit /delete' $BootID -ForegroundColor Yellow
|
||||
bcdedit /delete $BootID
|
||||
}
|
||||
}
|
||||
|
||||
# Add boot entry for CloudBuilder.vhdx
|
||||
Write-Host 'Creating new boot entry for CloudBuilder.vhdx' -ForegroundColor Cyan
|
||||
Write-Host 'Running command: bcdboot' $CBDriveLetter':\Windows' -ForegroundColor Yellow
|
||||
bcdboot $CBDriveLetter':\Windows'
|
||||
|
||||
$bootOptions = bcdedit /enum | Select-String 'path' -Context 2,1
|
||||
$bootOptions | ForEach {
|
||||
if ((($_.Context.PreContext[1] -replace '^device +') -eq ('partition='+$CBDriveLetter+':') `
|
||||
-or (($_.Context.PreContext[1] -replace '^device +') -like '*CloudBuilder.vhdx*')) `
|
||||
-and (($_.Context.PostContext[0] -replace '^description +') -ne 'Azure Stack')) {
|
||||
Write-Host 'Updating description for the boot entry' -ForegroundColor Cyan
|
||||
Write-Host 'Description:' ($_.Context.PostContext[0] -replace '^description +') -ForegroundColor Cyan
|
||||
Write-Host 'Device:' ($_.Context.PreContext[1] -replace '^device +') -ForegroundColor Cyan
|
||||
$BootID = '"' + ($_.Context.PreContext[0] -replace '^identifier +') + '"'
|
||||
Write-Host 'bcdedit /set' $BootID 'description "Azure Stack"' -ForegroundColor Yellow
|
||||
bcdedit /set $BootID description "Azure Stack"
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
if(-not $error) {
|
||||
Write-Host "Restart computer to boot from Azure Stack virtual harddisk" -ForegroundColor Cyan
|
||||
### Restart Computer ###
|
||||
Restart-Computer -Confirm
|
||||
}
|
||||
else {
|
||||
Write-Host "Fail to prepare CloudBuilder.vhdx. Errors: $($error)" -ForegroundColor Red
|
||||
}
|
|
@ -1,90 +1,91 @@
|
|||
# Deployment of Azure Stack
|
||||
# Azure Stack Development Kit installer
|
||||
|
||||
Instructions below are relative to the .\Deployment folder of the [AzureStack-Tools repo](..).
|
||||
The Azure Stack Development Kit installer provides a UI with the following features
|
||||
|
||||
## Azure Stack TP3 Support Files
|
||||
- Prepare the SafeOS for deployment
|
||||
- Prepare the Azure Stack Development Kit Installation
|
||||
- Rerun and Gather Logs
|
||||
- Reboot to SafeOS
|
||||
|
||||
To easily download the Azure Stack TP3 support files from this repository, run the following PowerShell script from your POC machine:
|
||||
To install the Azure Stack Development Kit you require
|
||||
|
||||
- A physical server that meets the requirements
|
||||
- The latest cloudbuilder.vhdx
|
||||
- The asdk-installer.ps1 script
|
||||
|
||||
## Download the Azure Stack Development Kit installer
|
||||
|
||||
To easily download the Azure Stack Development Kit installer from this repository, run the following PowerShell script from your SafeOS host:
|
||||
|
||||
```powershell
|
||||
# Variables
|
||||
$Uri = 'https://raw.githubusercontent.com/Azure/AzureStack-Tools/master/Deployment/'
|
||||
$LocalPath = 'c:\AzureStack_TP3_SupportFiles'
|
||||
$Uri = 'https://raw.githubusercontent.com/Azure/AzureStack-Tools/master/Deployment/asdk-installer.ps1'
|
||||
$LocalPath = 'c:\AzureStack_Installer'
|
||||
|
||||
# Create folder
|
||||
New-Item $LocalPath -Type directory
|
||||
|
||||
# Download files
|
||||
'BootMenuNoKVM.ps1', 'PrepareBootFromVHD.ps1', 'Unattend.xml', 'unattend_NoKVM.xml' | foreach { Invoke-WebRequest ($uri + $_) -OutFile ($LocalPath + '\' + $_) }
|
||||
# Download file
|
||||
Invoke-WebRequest $uri -OutFile ($LocalPath + '\' + 'asdk-installer.ps1')
|
||||
```
|
||||
|
||||
## Prepare to Deploy (boot from VHD)
|
||||
## Prepare the SafeOS for deployment
|
||||
|
||||
This tool allows you to easily prepare your Azure Stack Technical Preview deployment, by preparing the host to boot from the provided Azure Stack Technical Preview virtual harddisk (CloudBuilder.vhdx).
|
||||
The installer script can be used to prepare your host for the deployment of the Azure Stack Development Kit. After you have downloaded the cloudbuilder.vhdx, run the script on the server you would like to deploy to.
|
||||
|
||||
PrepareBootFromVHD updates the boot configuration with an **Azure Stack** entry.
|
||||
It will verify if the disk that hosts the CloudBuilder.vhdx contains the required free disk space, and optionally copy drivers and an unattend.xml that does not require KVM access.
|
||||
Select the cloudbuilder.vhdx and optionally specify a path to a folder containing drivers for the host.
|
||||
The host can be configured with the following options:
|
||||
- **Local administrator password** - If you uncheck this option the host will prompt for a password during the oobe setup when rebooting to the cloudbuilder.vhdx. Not specifying a local administrator password requires KVM access to the host to specify the password during boot.
|
||||
- **Computer name** - You can specify the name for the Azure Stack Development Kit host. The name needs to comply with FQDN requirements and cannot be longer than 15 characters. If you do not select the option, Windows generates a computername during OOBE.
|
||||
- **Timezone** - This options sets timezone for the Azure Stack Development Kit host to the selected value. If this option is not selected the timezone will be configred to (UTC-8:00) Pacific Time (US & Canada)
|
||||
- **Static IP Configuration** If the Azure Stack development kit needs to be configured with a static IP address, select this option. The installer will prompt for the networking interface and copy the current values for use in the cloudbuilder.vhdx during reboot. You can override the values that where copied if needed. If you do not select this option the network interfaces will be configured with DHCP when rebooted into the cloudbuilder.vhdx
|
||||
|
||||
You will need at least (120GB - Size of the CloudBuilder.vhdx file) of free disk space on the disk that contains the CloudBuilder.vhdx.
|
||||
A job will perform the following actions:
|
||||
|
||||
### PrepareBootFromVHD.ps1 Execution
|
||||
- Verify if the disk containing the cloudbuilder.vhdx has **enough space** to expand the disk. You will need at least (120GB - Size of the cloudBuilder.vhdx file) of free disk space on the disk that contains the cloudBuilder.vhdx.
|
||||
- Remove previous **Azure Stack** boot entries .
|
||||
- **Mount** the cloudbuilder.vhdx.
|
||||
- Add **bootfiles** to the Operating System disk.
|
||||
- Updates the boot configuration with an **Azure Stack** entry for the virtual hard disk and sets it to the default value.
|
||||
- Adds an **unattend** file to the Operating System on the mounted virtual hard disk, based on the selections made in the wizard.
|
||||
- Adds **drivers** to the operating system, if that option was selected during the wizard.
|
||||
|
||||
There are five parameters for this script:
|
||||
- **CloudBuilderDiskPath** (required) – path to the CloudBuilder.vhdx on the HOST
|
||||
- **DriverPath** (optional) – allows you to add additional drivers for the host in the virtual HD
|
||||
- **ApplyUnattend** (optional) – switch parameter, if specified, the configuration of the OS is automated, and the user will be prompted for the AdminPassword to configure at boot (requires provided accompanying file **unattend_NoKVM.xml**)
|
||||
- If you do not leverage this parameter, the generic **unattend.xml** file is used without further customization
|
||||
- **AdminPassword** (optional) – only used when the **ApplyUnattend** parameter is set, requires a minimum of 6 characters
|
||||
- **VHDLanguage** (optional) – specifies the VHD language, defaulted to “en-US”
|
||||
When the job is completed you finalize the wizard to reboot into the cloudbuilder.vhdx. If you have enabled the local administrator password and have connectivity to the IP address (either the static one specified or based on DHCP), you can remote into the host with RDP after the OOBE completes.
|
||||
|
||||
## Prepare the Azure Stack Development Kit installation
|
||||
|
||||
Once the host has succesfully completed booting from the cloudbuilder.vhdx, logon to the host as administrator and start the same installation script again. The installer script was originally stored on c:\AzureStack_Installer. After the reboot into cloudbuilder.vhdx the SafeOS system disk is presented as a datadisk in the Operating System of the Azure Stack Development Kit host OS. Browse for the script and execute it by righclicking it and select Run with PowerShell. Or browse to the path in a PowerShell session and run;
|
||||
|
||||
```powershell
|
||||
.\PrepareBootFromVHD.ps1 -CloudBuilderDiskPath C:\CloudBuilder.vhdx -ApplyUnattend
|
||||
.\asdk-installer.ps1
|
||||
```
|
||||
|
||||
If you execute this exact command, you will be prompted to enter the **AdminPassword** parameter.
|
||||
Click install to start the deployment wizard. Select the preferred identity provider for your Azure Stack Development Kit deployment.
|
||||
|
||||
During execution of this script, you will have visibility to the **bcdedit** command execution and output.
|
||||
- **Azure Cloud** : Azure Active Directory
|
||||
- **ADFS** : Local ADFS instance as part of the installation
|
||||
|
||||
When the script execution is complete, you will be asked to confirm reboot.
|
||||
If there are other users logged in, this command will fail, run the following command to continue:
|
||||
```powershell
|
||||
Restart-Computer -Force
|
||||
```
|
||||
If you selected Azure Cloud, specify the Azure Active Directory tenant (e.g. azurestack.onmicrosoft.com).
|
||||
|
||||
### HOST Reboot
|
||||
Submit the local administrator password. This value submitted has to match the current configured local administrator password.
|
||||
|
||||
If you used **ApplyUnattend** and provided an **AdminPassword** during the execution of the PrepareBootFromVHD.ps1 script, you will not need KVM to access the HOST once it completes its reboot cycle.
|
||||
In the network interface screen, select the adapter that will be used for the Azure Stack Development Kit. Ensure you have access to the IP address as all other adapters will be disabled by the installer.
|
||||
|
||||
Of course, you may still need KVM (or some other kind of alternate connection to the HOST other than RDP) if you meet one of the following:
|
||||
- You chose not to use **ApplyUnattend**
|
||||
- It will automatically run Windows Setup as the VHD OS is prepared. When asked, provide your country, language, keyboard, and other preferences.
|
||||
- Something goes wrong in the reboot/customization process, and you are not able to RDP to the HOST after some time.
|
||||
The network configuration screen allows you to specify the settings for the BGPNAT vm. The default settings uses DHCP for the BGPNAT vm. You can set it to static, but only use this parameter if DHCP can’t assign a valid IP address for Azure Stack to access the Internet. A static IP address needs to be specified with the subnetmask length (e.g. 10.0.0.5/24). Optionally you can specify the TimeServer, DNS Server and VLAN ID.
|
||||
|
||||
## Prepare to Redeploy (boot back to original/base OS)
|
||||
The summary screen displays the PowerShell script that will be executed. Click deploy start the deployment of the Azure Stack Development Kit.
|
||||
|
||||
This tool allows you to easily initiate a redeployment of your Azure Stack Technical Preview deployment, by presenting you with the boot OS options, and the choice to boot back into the original/base OS (away from the previously created **Azure Stack**).
|
||||
> Note: When you have selected Azure Cloud as the identity provider, you will be prompted 2 to 3 minutes after the deployment has started. Please ensure you submit your Azure AD credentials.
|
||||
|
||||
BootMenuNoKVM updates the boot configuration with the original/base entry, and then prompts to reboot the host.
|
||||
Because the default boot entry is set with this script, no KVM or manual selection of the boot entry is required as the machine restarts.
|
||||
## Rerun and gather logs
|
||||
|
||||
### BootMenuNoKVM.ps1 Execution
|
||||
If during the installation an error occures, you can start the installer script to rerun the installation from where it failed. After 3 failed reruns the installer script will gather the logs for support purposes and stores them in c:\AzureStackLogs
|
||||
|
||||
There are no parameters for this script, but it must be executed in an elevated PowerShell console.
|
||||
If the installation completed succesfully, but you ran into an issue that requires you to gather the log files, you can run the same installer script. The installer will present you with the option to gather the logs and store them in c:\AzureStackLogs
|
||||
|
||||
```powershell
|
||||
.\BootMenuNoKVM.ps1
|
||||
```
|
||||
## Reboot
|
||||
|
||||
During execution of this script, you will be prompted to choose the default OS to boot back into after restart. This will become your new default OS, just like **Azure Stack** became the new default OS during deployment.
|
||||
The installer script allows you to easily initiate a reboot to the SafeOS to start a redeployment of your Azure Stack Development Kit. Start the installer script and select Reboot. You will be presented with the current boot options. Select the entry for the SafeOS and select Reboot. This creates a onetime override in the boot order. The SafeOS boot entry will be select automatically. The next reboot the boot configuration will resume its normal order and the host will boot into the cloudbuilder.vhdx again.
|
||||
|
||||
When the script execution is complete, you will be asked to confirm reboot.
|
||||
If there are other users logged in, this command will fail, run the following command to continue:
|
||||
```powershell
|
||||
Restart-Computer -Force
|
||||
```
|
||||
|
||||
### HOST Reboot
|
||||
|
||||
Because you are choosing the new default OS to boot into, you will not need KVM to access the HOST once it completes its reboot cycle. It will boot into the OS you chose during the execution of the script.
|
||||
|
||||
Once the HOST is rebooted back to the original/base OS, you will need to DELETE the previous/existing CloudBuilder.vhdx file, and then copy down a new one to begin redeployment.
|
||||
### Note
|
||||
The Azure Stack Development Kit installer script is based on PowerShell and the Windows Presentation Foundation. It is published in this public repository so you can make improvements to it by submitting a pull request.
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
<unattend xmlns="urn:schemas-microsoft-com:unattend" xmlns:ms="urn:schemas-microsoft-com:asm.v3">
|
||||
<settings pass="specialize">
|
||||
<component name="Networking-MPSSVC-Svc" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<FirewallGroups>
|
||||
<FirewallGroup wcm:action="add" wcm:keyValue="RemoteDesktop">
|
||||
<Active>true</Active>
|
||||
<Profile>all</Profile>
|
||||
<Group>@FirewallAPI.dll,-28752</Group>
|
||||
</FirewallGroup>
|
||||
</FirewallGroups>
|
||||
</component>
|
||||
<component name="Microsoft-Windows-IE-ESC" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<IEHardenAdmin>false</IEHardenAdmin>
|
||||
<IEHardenUser>false</IEHardenUser>
|
||||
</component>
|
||||
</settings>
|
||||
<settings pass="oobeSystem">
|
||||
<component xmlns="" name="Microsoft-Windows-TerminalServices-LocalSessionManager" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" processorArchitecture="amd64">
|
||||
<fDenyTSConnections>false</fDenyTSConnections>
|
||||
</component>
|
||||
<component xmlns="" name="Microsoft-Windows-TerminalServices-RDP-WinStationExtensions" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" processorArchitecture="amd64">
|
||||
<UserAuthentication>0</UserAuthentication>
|
||||
</component>
|
||||
</settings>
|
||||
</unattend>
|
|
@ -1,76 +0,0 @@
|
|||
<unattend xmlns="urn:schemas-microsoft-com:unattend">
|
||||
<settings pass="windowsPE">
|
||||
<component name="Microsoft-Windows-Setup" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" processorArchitecture="AMD64">
|
||||
<UpgradeData>
|
||||
<Upgrade>false</Upgrade>
|
||||
</UpgradeData>
|
||||
<UserData>
|
||||
<AcceptEula>true</AcceptEula>
|
||||
<FullName>Microsoft</FullName>
|
||||
<Organization>Microsoft</Organization>
|
||||
<ProductKey>
|
||||
<WillShowUI>OnError</WillShowUI>
|
||||
<Key>%productkey%</Key>
|
||||
</ProductKey>
|
||||
</UserData>
|
||||
<Restart>Restart</Restart>
|
||||
</component>
|
||||
<component name="Microsoft-Windows-International-Core-WinPE" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" processorArchitecture="AMD64">
|
||||
<SetupUILanguage>
|
||||
<UILanguage>en-us</UILanguage>
|
||||
<WillShowUI>OnError</WillShowUI>
|
||||
</SetupUILanguage>
|
||||
<UILanguage>%locale%</UILanguage>
|
||||
<SystemLocale>%locale%</SystemLocale>
|
||||
<UserLocale>%locale%</UserLocale>
|
||||
<InputLocale>0409:00000409</InputLocale>
|
||||
</component>
|
||||
</settings>
|
||||
<settings pass="specialize">
|
||||
<component xmlns="" name="Microsoft-Windows-TerminalServices-LocalSessionManager" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" processorArchitecture="amd64">
|
||||
<fDenyTSConnections>false</fDenyTSConnections>
|
||||
</component>
|
||||
<component xmlns="" name="Microsoft-Windows-TerminalServices-RDP-WinStationExtensions" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" processorArchitecture="amd64">
|
||||
<UserAuthentication>0</UserAuthentication>
|
||||
</component>
|
||||
<component name="Microsoft-Windows-Shell-Setup" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" processorArchitecture="AMD64">
|
||||
<ComputerName></ComputerName>
|
||||
</component>
|
||||
<component name="Networking-MPSSVC-Svc" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<FirewallGroups>
|
||||
<FirewallGroup wcm:action="add" wcm:keyValue="RemoteDesktop">
|
||||
<Active>true</Active>
|
||||
<Profile>all</Profile>
|
||||
<Group>@FirewallAPI.dll,-28752</Group>
|
||||
</FirewallGroup>
|
||||
</FirewallGroups>
|
||||
</component>
|
||||
<component name="Microsoft-Windows-IE-ESC" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<IEHardenAdmin>false</IEHardenAdmin>
|
||||
<IEHardenUser>false</IEHardenUser>
|
||||
</component>
|
||||
<component name="Microsoft-Windows-Deployment" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" processorArchitecture="AMD64">
|
||||
<RunSynchronous>
|
||||
<RunSynchronousCommand>
|
||||
<Order>1</Order>
|
||||
<Path>cmd /c net user administrator /active:yes</Path>
|
||||
<Description>RS1</Description>
|
||||
<WillReboot>Never</WillReboot>
|
||||
</RunSynchronousCommand>
|
||||
</RunSynchronous>
|
||||
</component>
|
||||
</settings>
|
||||
<settings pass="oobeSystem">
|
||||
<component name="Microsoft-Windows-Shell-Setup" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" processorArchitecture="AMD64">
|
||||
<UserAccounts>
|
||||
<AdministratorPassword>
|
||||
<Value>%adminpassword%</Value>
|
||||
<PlainText>true</PlainText>
|
||||
</AdministratorPassword>
|
||||
</UserAccounts>
|
||||
<OOBE>
|
||||
<SkipMachineOOBE>true</SkipMachineOOBE>
|
||||
</OOBE>
|
||||
</component>
|
||||
</settings>
|
||||
</unattend>
|
|
@ -8,11 +8,12 @@
|
|||
This function fetches the OpenID configuration metadata from the identity system and parses the Directory TenantID out of it.
|
||||
Azure Stack AD FS is configured to be a single tenanted identity system with a TenantID.
|
||||
.EXAMPLE
|
||||
Get-DirectoryTenantIdentifier -authority https://login.windows.net/microsoft.onmicrosoft.com
|
||||
Get-AzsDirectoryTenantIdentifier -authority https://login.windows.net/microsoft.onmicrosoft.com
|
||||
.EXAMPLE
|
||||
Get-DirectoryTenantIdentifier -authority https://adfs.local.azurestack.external/adfs
|
||||
Get-AzsDirectoryTenantIdentifier -authority https://adfs.local.azurestack.external/adfs
|
||||
#>
|
||||
function Get-DirectoryTenantIdentifier {
|
||||
|
||||
function Get-AzsDirectoryTenantidentifier {
|
||||
[CmdletBinding()]
|
||||
Param
|
||||
(
|
||||
|
@ -25,17 +26,20 @@ function Get-DirectoryTenantIdentifier {
|
|||
return $(Invoke-RestMethod $("{0}/.well-known/openid-configuration" -f $authority.TrimEnd('/'))).issuer.TrimEnd('/').Split('/')[-1]
|
||||
}
|
||||
|
||||
Export-ModuleMember -Function 'Get-AzsDirectoryTenantidentifier'
|
||||
|
||||
<#
|
||||
.Synopsis
|
||||
This function is used to create a Service Principal on teh AD Graph
|
||||
.DESCRIPTION
|
||||
The command creates a certificate in the cert store of the local user and uses that certificate to create a Service Principal in the Azure Stack Stamp Active Directory.
|
||||
.EXAMPLE
|
||||
$servicePrincipal = New-ADGraphServicePrincipal -DisplayName "mySPApp" -AdminCredential $(Get-Credential) -Verbose
|
||||
$servicePrincipal = New-AzsAdGraphServicePrincipal -DisplayName "mySPApp" -AdminCredential $(Get-Credential) -Verbose
|
||||
.EXAMPLE
|
||||
$servicePrincipal = New-ADGraphServicePrincipal -DisplayName "mySPApp" -AdminCredential $(Get-Credential) -DeleteAndCreateNew -Verbose
|
||||
$servicePrincipal = New-AzsAdGraphServicePrincipal -DisplayName "mySPApp" -AdminCredential $(Get-Credential) -DeleteAndCreateNew -Verbose
|
||||
#>
|
||||
function New-ADGraphServicePrincipal {
|
||||
|
||||
function New-AzsAdGraphServicePrincipal {
|
||||
[CmdletBinding()]
|
||||
Param
|
||||
(
|
||||
|
@ -46,9 +50,9 @@ function New-ADGraphServicePrincipal {
|
|||
$DisplayName,
|
||||
|
||||
# Adfs Machine name
|
||||
[Parameter(Mandatory = $true , Position = 1)]
|
||||
[Parameter(Mandatory = $true, Position = 1)]
|
||||
[string]
|
||||
$AdfsMachineName = "mas-adfs01.azurestack.local",
|
||||
$AdfsMachineName,
|
||||
|
||||
# Domain Administrator Credential to create Service Principal
|
||||
[Parameter(Mandatory = $true,
|
||||
|
@ -91,13 +95,13 @@ function New-ADGraphServicePrincipal {
|
|||
|
||||
Write-Verbose -Message "Creating new application group with name '$applicationGroupName'."
|
||||
$applicationParameters = @{
|
||||
Name = $applicationGroupName
|
||||
Description = $applicationGroupDescription
|
||||
ClientType = 'Confidential'
|
||||
ClientId = $shellSiteApplicationId
|
||||
ClientDisplayName = $shellSiteDisplayName
|
||||
Name = $applicationGroupName
|
||||
Description = $applicationGroupDescription
|
||||
ClientType = 'Confidential'
|
||||
ClientId = $shellSiteApplicationId
|
||||
ClientDisplayName = $shellSiteDisplayName
|
||||
ClientRedirectUris = $shellSiteRedirectUri
|
||||
ClientDescription = $shellSiteClientDescription
|
||||
ClientDescription = $shellSiteClientDescription
|
||||
ClientCertificates = $ClientCertificate
|
||||
}
|
||||
$defaultTimeOut = New-TimeSpan -Minutes 10
|
||||
|
@ -105,9 +109,9 @@ function New-ADGraphServicePrincipal {
|
|||
|
||||
Write-Verbose -Message "Shell Site ApplicationGroup: $($applicationGroup | ConvertTo-Json)"
|
||||
return [pscustomobject]@{
|
||||
ObjectId = $applicationGroup.Identifier
|
||||
ObjectId = $applicationGroup.Identifier
|
||||
ApplicationId = $applicationParameters.ClientId
|
||||
Thumbprint = $ClientCertificate.Thumbprint
|
||||
Thumbprint = $ClientCertificate.Thumbprint
|
||||
}
|
||||
}
|
||||
$domainAdminSession = New-PSSession -ComputerName $AdfsMachineName -Credential $AdminCredential -Authentication Credssp -Verbose
|
||||
|
@ -126,14 +130,14 @@ function Initialize-AzureRmEnvironment([string]$EnvironmentName, [string] $Resou
|
|||
$directoryTenantId = (New-Object uri(Invoke-RestMethod "$($endpoints.authentication.loginEndpoint.TrimEnd('/'))/$DirectoryTenantName/.well-known/openid-configuration").token_endpoint).AbsolutePath.Split('/')[1]
|
||||
|
||||
$azureEnvironmentParams = @{
|
||||
Name = $EnvironmentName
|
||||
ActiveDirectoryEndpoint = $endpoints.authentication.loginEndpoint.TrimEnd('/') + "/"
|
||||
Name = $EnvironmentName
|
||||
ActiveDirectoryEndpoint = $endpoints.authentication.loginEndpoint.TrimEnd('/') + "/"
|
||||
ActiveDirectoryServiceEndpointResourceId = $endpoints.authentication.audiences[0]
|
||||
AdTenant = $directoryTenantId
|
||||
ResourceManagerEndpoint = $ResourceManagerEndpoint
|
||||
GalleryEndpoint = $endpoints.galleryEndpoint
|
||||
GraphEndpoint = $endpoints.graphEndpoint
|
||||
GraphAudience = $endpoints.graphEndpoint
|
||||
AdTenant = $directoryTenantId
|
||||
ResourceManagerEndpoint = $ResourceManagerEndpoint
|
||||
GalleryEndpoint = $endpoints.galleryEndpoint
|
||||
GraphEndpoint = $endpoints.graphEndpoint
|
||||
GraphAudience = $endpoints.graphEndpoint
|
||||
}
|
||||
|
||||
Remove-AzureRmEnvironment -Name $EnvironmentName -Force -ErrorAction Ignore | Out-Null
|
||||
|
@ -157,30 +161,35 @@ function Resolve-AzureEnvironment([Microsoft.Azure.Commands.Profile.Models.PSAzu
|
|||
return $azureEnvironment
|
||||
}
|
||||
|
||||
function Initialize-AzureRmUserAccount([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureEnvironment, [string] $SubscriptionName, [string] $SubscriptionId) {
|
||||
# Prompts the user for interactive login flow
|
||||
$azureAccount = Add-AzureRmAccount -EnvironmentName $azureEnvironment.Name -TenantId $azureEnvironment.AdTenant
|
||||
function Initialize-AzureRmUserAccount([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureEnvironment, [string] $SubscriptionName, [string] $SubscriptionId, [pscredential] $AutomationCredential) {
|
||||
|
||||
if ($SubscriptionName) {
|
||||
$params = @{
|
||||
EnvironmentName = $azureEnvironment.Name
|
||||
TenantId = $azureEnvironment.AdTenant
|
||||
}
|
||||
|
||||
if ($AutomationCredential)
|
||||
{
|
||||
$params += @{ Credential = $AutomationCredential }
|
||||
}
|
||||
|
||||
# Prompts the user for interactive login flow if automation credential is not specified
|
||||
$azureAccount = Add-AzureRmAccount @params
|
||||
|
||||
if ($SubscriptionName)
|
||||
{
|
||||
Select-AzureRmSubscription -SubscriptionName $SubscriptionName | Out-Null
|
||||
}
|
||||
elseif ($SubscriptionId) {
|
||||
elseif ($SubscriptionId)
|
||||
{
|
||||
Select-AzureRmSubscription -SubscriptionId $SubscriptionId | Out-Null
|
||||
}
|
||||
|
||||
return $azureAccount
|
||||
}
|
||||
|
||||
function Get-IdentityApplicationData {
|
||||
# Import and read application data
|
||||
Write-Host "Loading identity application data..."
|
||||
$xmlData = [xml](Get-ChildItem -Path C:\EceStore -Recurse -Force -File | Sort Length | Select -Last 1 | Get-Content | Out-String)
|
||||
$xmlIdentityApplications = $xmlData.SelectNodes('//IdentityApplication')
|
||||
|
||||
return $xmlIdentityApplications
|
||||
}
|
||||
|
||||
function Resolve-GraphEnvironment([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureEnvironment) {
|
||||
function Resolve-GraphEnvironment([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureEnvironment)
|
||||
{
|
||||
$graphEnvironment = switch ($azureEnvironment.ActiveDirectoryAuthority) {
|
||||
'https://login.microsoftonline.com/' { 'AzureCloud' }
|
||||
'https://login.chinacloudapi.cn/' { 'AzureChinaCloud' }
|
||||
|
@ -193,9 +202,20 @@ function Resolve-GraphEnvironment([Microsoft.Azure.Commands.Profile.Models.PSAzu
|
|||
return $graphEnvironment
|
||||
}
|
||||
|
||||
function Get-AzureRmUserRefreshToken([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureEnvironment, [string]$directoryTenantId) {
|
||||
# Prompts the user for interactive login flow
|
||||
$azureAccount = Add-AzureRmAccount -EnvironmentName $azureEnvironment.Name -TenantId $directoryTenantId
|
||||
function Get-AzureRmUserRefreshToken([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureEnvironment, [string]$directoryTenantId, [pscredential]$AutomationCredential)
|
||||
{
|
||||
$params = @{
|
||||
EnvironmentName = $azureEnvironment.Name
|
||||
TenantId = $directoryTenantId
|
||||
}
|
||||
|
||||
if ($AutomationCredential)
|
||||
{
|
||||
$params += @{ Credential = $AutomationCredential }
|
||||
}
|
||||
|
||||
# Prompts the user for interactive login flow if automation credential is not specified
|
||||
$azureAccount = Add-AzureRmAccount @params
|
||||
|
||||
# Retrieve the refresh token
|
||||
$tokens = [Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache]::DefaultShared.ReadItems()
|
||||
|
@ -203,12 +223,15 @@ function Get-AzureRmUserRefreshToken([Microsoft.Azure.Commands.Profile.Models.PS
|
|||
Where Resource -EQ $azureEnvironment.ActiveDirectoryServiceEndpointResourceId |
|
||||
Where IsMultipleResourceRefreshToken -EQ $true |
|
||||
Where DisplayableId -EQ $azureAccount.Context.Account.Id |
|
||||
Select -ExpandProperty RefreshToken |
|
||||
Sort ExpiresOn |
|
||||
Select -Last 1 -ExpandProperty RefreshToken |
|
||||
ConvertTo-SecureString -AsPlainText -Force
|
||||
|
||||
return $refreshToken
|
||||
}
|
||||
|
||||
# Exposed Functions
|
||||
|
||||
<#
|
||||
.Synopsis
|
||||
Adds a Guest Directory Tenant to Azure Stack.
|
||||
|
@ -219,9 +242,10 @@ function Get-AzureRmUserRefreshToken([Microsoft.Azure.Commands.Profile.Models.PS
|
|||
$azureStackDirectoryTenant = "<homeDirectoryTenant>.onmicrosoft.com"
|
||||
$guestDirectoryTenantToBeOnboarded = "<guestDirectoryTenant>.onmicrosoft.com"
|
||||
|
||||
Register-GuestDirectoryTenantToAzureStack -AdminResourceManagerEndpoint $adminARMEndpoint -DirectoryTenantName $azureStackDirectoryTenant -GuestDirectoryTenantName $guestDirectoryTenantToBeOnboarded
|
||||
Register-AzsGuestDirectoryTenant -AdminResourceManagerEndpoint $adminARMEndpoint -DirectoryTenantName $azureStackDirectoryTenant -GuestDirectoryTenantName $guestDirectoryTenantToBeOnboarded
|
||||
#>
|
||||
function Register-GuestDirectoryTenantToAzureStack {
|
||||
|
||||
function Register-AzsGuestDirectoryTenant {
|
||||
[CmdletBinding()]
|
||||
param
|
||||
(
|
||||
|
@ -236,10 +260,15 @@ function Register-GuestDirectoryTenantToAzureStack {
|
|||
[ValidateNotNullOrEmpty()]
|
||||
[string] $DirectoryTenantName,
|
||||
|
||||
# The name of the guest Directory Tenant which is to be onboarded.
|
||||
# The names of the guest Directory Tenants which are to be onboarded.
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $GuestDirectoryTenantName,
|
||||
[string[]] $GuestDirectoryTenantName,
|
||||
|
||||
# The location of your Azure Stack deployment.
|
||||
[Parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $Location,
|
||||
|
||||
# The identifier of the Administrator Subscription. If not specified, the script will attempt to use the set default subscription.
|
||||
[ValidateNotNull()]
|
||||
|
@ -253,9 +282,10 @@ function Register-GuestDirectoryTenantToAzureStack {
|
|||
[ValidateNotNullOrEmpty()]
|
||||
[string] $ResourceGroupName = 'system',
|
||||
|
||||
# Optional: A credential used to authenticate with Azure Stack. Must support a non-interactive authentication flow. If not provided, the script will prompt for user credentials.
|
||||
[Parameter()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $Location = 'local'
|
||||
[ValidateNotNull()]
|
||||
[pscredential] $AutomationCredential = $null
|
||||
)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$VerbosePreference = 'Continue'
|
||||
|
@ -265,137 +295,29 @@ function Register-GuestDirectoryTenantToAzureStack {
|
|||
|
||||
# Initialize the Azure PowerShell module to communicate with Azure Stack. Will prompt user for credentials.
|
||||
$azureEnvironment = Initialize-AzureRmEnvironment -EnvironmentName 'AzureStackAdmin' -ResourceManagerEndpoint $AdminResourceManagerEndpoint -DirectoryTenantName $DirectoryTenantName
|
||||
$azureAccount = Initialize-AzureRmUserAccount -azureEnvironment $azureEnvironment -SubscriptionName $SubscriptionName -SubscriptionId $SubscriptionId
|
||||
$azureAccount = Initialize-AzureRmUserAccount -azureEnvironment $azureEnvironment -SubscriptionName $SubscriptionName -SubscriptionId $SubscriptionId -AutomationCredential $AutomationCredential
|
||||
|
||||
# resolve the guest directory tenant ID from the name
|
||||
$guestDirectoryTenantId = (New-Object uri(Invoke-RestMethod "$($azureEnvironment.ActiveDirectoryAuthority.TrimEnd('/'))/$GuestDirectoryTenantName/.well-known/openid-configuration").token_endpoint).AbsolutePath.Split('/')[1]
|
||||
|
||||
# Add (or update) the new directory tenant to the Azure Stack deployment
|
||||
$params = @{
|
||||
ApiVersion = '2015-11-01' # needed if using "latest" / later version of Azure Powershell
|
||||
ResourceType = "Microsoft.Subscriptions.Admin/directoryTenants"
|
||||
ResourceGroupName = $ResourceGroupName
|
||||
ResourceName = $GuestDirectoryTenantName
|
||||
Location = $Location
|
||||
Properties = @{ tenantId = $guestDirectoryTenantId }
|
||||
}
|
||||
$directoryTenant = New-AzureRmResource @params -Force -Verbose -ErrorAction Stop
|
||||
Write-Verbose -Message "Directory Tenant onboarded: $(ConvertTo-Json $directoryTenant)" -Verbose
|
||||
}
|
||||
|
||||
<#
|
||||
.Synopsis
|
||||
Publishes the list of applications to the Azure Stack ARM.
|
||||
.DESCRIPTION
|
||||
|
||||
.EXAMPLE
|
||||
$adminARMEndpoint = "https://adminmanagement.local.azurestack.external"
|
||||
$azureStackDirectoryTenant = "<homeDirectoryTenant>.onmicrosoft.com"
|
||||
$guestDirectoryTenantToBeOnboarded = "<guestDirectoryTenant>.onmicrosoft.com"
|
||||
|
||||
Publish-AzureStackApplicationsToARM -AdminResourceManagerEndpoint $adminARMEndpoint -DirectoryTenantName $azureStackDirectoryTenant
|
||||
#>
|
||||
function Publish-AzureStackApplicationsToARM {
|
||||
[CmdletBinding()]
|
||||
param
|
||||
(
|
||||
# The endpoint of the Azure Stack Resource Manager service.
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateNotNull()]
|
||||
[ValidateScript( {$_.Scheme -eq [System.Uri]::UriSchemeHttps})]
|
||||
[uri] $AdminResourceManagerEndpoint,
|
||||
|
||||
# The name of the home Directory Tenant in which the Azure Stack Administrator subscription resides.
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $DirectoryTenantName,
|
||||
|
||||
# The identifier of the Administrator Subscription. If not specified, the script will attempt to use the set default subscription.
|
||||
[Parameter()]
|
||||
[ValidateNotNull()]
|
||||
[string] $SubscriptionId = $null,
|
||||
|
||||
# The display name of the Administrator Subscription. If not specified, the script will attempt to use the set default subscription.
|
||||
[Parameter()]
|
||||
[ValidateNotNull()]
|
||||
[string] $SubscriptionName = $null,
|
||||
|
||||
[Parameter()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $ResourceGroupName = 'system',
|
||||
|
||||
[Parameter()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $Location = 'local',
|
||||
|
||||
[Parameter()]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[ValidateScript( {Test-Path -Path $_ -PathType Container -ErrorAction Stop})]
|
||||
[string] $InfrastructureSharePath = '\\SU1FileServer\SU1_Infrastructure_1'
|
||||
)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$VerbosePreference = 'Continue'
|
||||
|
||||
# Install-Module AzureRm -RequiredVersion '1.2.8'
|
||||
Import-Module 'AzureRm.Profile' -Force -Verbose:$false 4> $null
|
||||
Write-Warning "This script is intended to work only with the initial TP3 release of Azure Stack and will be deprecated."
|
||||
|
||||
# Initialize the Azure PowerShell module to communicate with Azure Stack. Will prompt user for credentials.
|
||||
$azureEnvironment = Initialize-AzureRmEnvironment -EnvironmentName 'AzureStackAdmin' -ResourceManagerEndpoint $AdminResourceManagerEndpoint -DirectoryTenantName $DirectoryTenantName
|
||||
$azureAccount = Initialize-AzureRmUserAccount -azureEnvironment $azureEnvironment -SubscriptionName $SubscriptionName -SubscriptionId $SubscriptionId
|
||||
|
||||
# Register each identity application for future onboarding.
|
||||
$xmlIdentityApplications = Get-IdentityApplicationData
|
||||
foreach ($xmlIdentityApplication in $xmlIdentityApplications) {
|
||||
$applicationData = Get-Content -Path ($xmlIdentityApplication.ConfigPath.Replace('{Infrastructure}', $InfrastructureSharePath)) | Out-String | ConvertFrom-Json
|
||||
|
||||
# Note - 'Admin' applications do not need to be registered for replication into a new directory tenant
|
||||
if ($xmlIdentityApplication.Name.StartsWith('Admin', [System.StringComparison]::OrdinalIgnoreCase)) {
|
||||
Write-Warning "Skipping registration of Admin application: $('{0}.{1}' -f $xmlIdentityApplication.Name, $xmlIdentityApplication.DisplayName)"
|
||||
continue
|
||||
}
|
||||
|
||||
# Advertise any necessary OAuth2PermissionGrants for the application
|
||||
$oauth2PermissionGrants = @()
|
||||
foreach ($applicationFriendlyName in $xmlIdentityApplication.OAuth2PermissionGrants.FirstPartyApplication.FriendlyName) {
|
||||
$oauth2PermissionGrants += [pscustomobject]@{
|
||||
Resource = $applicationData.ApplicationInfo.appId
|
||||
Client = $applicationData.GraphInfo.Applications."$applicationFriendlyName".Id
|
||||
ConsentType = 'AllPrincipals'
|
||||
Scope = 'user_impersonation'
|
||||
}
|
||||
}
|
||||
foreach ($directoryTenantName in $GuestDirectoryTenantName)
|
||||
{
|
||||
# Resolve the guest directory tenant ID from the name
|
||||
$directoryTenantId = (New-Object uri(Invoke-RestMethod "$($azureEnvironment.ActiveDirectoryAuthority.TrimEnd('/'))/$directoryTenantName/.well-known/openid-configuration").token_endpoint).AbsolutePath.Split('/')[1]
|
||||
|
||||
# Add (or update) the new directory tenant to the Azure Stack deployment
|
||||
$params = @{
|
||||
ApiVersion = '2015-11-01' # needed if using "latest" / later version of Azure Powershell
|
||||
ResourceType = "Microsoft.Subscriptions.Providers/applicationRegistrations"
|
||||
ApiVersion = '2015-11-01'
|
||||
ResourceType = "Microsoft.Subscriptions.Admin/directoryTenants"
|
||||
ResourceGroupName = $ResourceGroupName
|
||||
ResourceName = '{0}.{1}' -f $xmlIdentityApplication.Name, $xmlIdentityApplication.DisplayName
|
||||
Location = $Location
|
||||
Properties = @{
|
||||
"objectId" = $applicationData.ApplicationInfo.objectId
|
||||
"appId" = $applicationData.ApplicationInfo.appId
|
||||
"oauth2PermissionGrants" = $oauth2PermissionGrants
|
||||
"directoryRoles" = @()
|
||||
"tags" = @()
|
||||
}
|
||||
ResourceName = $directoryTenantName
|
||||
Location = $Location
|
||||
Properties = @{ tenantId = $directoryTenantId }
|
||||
}
|
||||
|
||||
# Advertise 'ReadDirectoryData' workaround for applications which require this permission of type 'Role'
|
||||
if ($xmlIdentityApplication.AADPermissions.ApplicationPermission.Name -icontains 'ReadDirectoryData') {
|
||||
$params.Properties.directoryRoles = @('Directory Readers')
|
||||
}
|
||||
|
||||
# Advertise any specified tags required for application integration scenarios
|
||||
if ($xmlIdentityApplication.tags) {
|
||||
$params.Properties.tags += $xmlIdentityApplication.tags
|
||||
}
|
||||
|
||||
$registeredApplication = New-AzureRmResource @params -Force -Verbose -ErrorAction Stop
|
||||
Write-Verbose -Message "Identity application registered: $(ConvertTo-Json $registeredApplication)" -Verbose
|
||||
$directoryTenant = New-AzureRmResource @params -Force -Verbose -ErrorAction Stop
|
||||
Write-Verbose -Message "Directory Tenant onboarded: $(ConvertTo-Json $directoryTenant)" -Verbose
|
||||
}
|
||||
}
|
||||
|
||||
Export-ModuleMember -Function 'Publish-AzsApplicationsToARM'
|
||||
|
||||
<#
|
||||
.Synopsis
|
||||
Consents to the given Azure Stack instance within the callers's Azure Directory Tenant.
|
||||
|
@ -405,10 +327,11 @@ Consents to the given Azure Stack instance within the callers's Azure Directory
|
|||
$tenantARMEndpoint = "https://management.local.azurestack.external"
|
||||
$myDirectoryTenantName = "<guestDirectoryTenant>.onmicrosoft.com"
|
||||
|
||||
Register-AzureStackWithMyDirectoryTenant -TenantResourceManagerEndpoint $tenantARMEndpoint `
|
||||
Register-AzsWithMyDirectoryTenant -TenantResourceManagerEndpoint $tenantARMEndpoint `
|
||||
-DirectoryTenantName $myDirectoryTenantName -Verbose -Debug
|
||||
#>
|
||||
function Register-AzureStackWithMyDirectoryTenant {
|
||||
|
||||
function Register-AzsWithMyDirectoryTenant {
|
||||
[CmdletBinding()]
|
||||
param
|
||||
(
|
||||
|
@ -421,7 +344,17 @@ function Register-AzureStackWithMyDirectoryTenant {
|
|||
# The name of the directory tenant being onboarded.
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $DirectoryTenantName
|
||||
[string] $DirectoryTenantName,
|
||||
|
||||
# Optional: The identifier (GUID) of the Resource Manager application. Pass this parameter to skip the need to complete the guest signup flow via the portal.
|
||||
[Parameter(Mandatory=$false)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $ResourceManagerApplicationId,
|
||||
|
||||
# Optional: A credential used to authenticate with Azure Stack. Must support a non-interactive authentication flow. If not provided, the script will prompt for user credentials.
|
||||
[Parameter()]
|
||||
[ValidateNotNull()]
|
||||
[pscredential] $AutomationCredential = $null
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
@ -429,50 +362,97 @@ function Register-AzureStackWithMyDirectoryTenant {
|
|||
|
||||
# Install-Module AzureRm -RequiredVersion '1.2.8'
|
||||
Import-Module 'AzureRm.Profile' -Force -Verbose:$false 4> $null
|
||||
Import-Module "$PSScriptRoot\GraphAPI\GraphAPI.psm1" -Force -Verbose:$false 4> $null
|
||||
Import-Module "$PSScriptRoot\GraphAPI\GraphAPI.psm1" -Force -Verbose:$false 4> $null
|
||||
|
||||
# Initialize the Azure PowerShell module to communicate with the Azure Resource Manager corresponding to their home Graph Service. Will prompt user for credentials.
|
||||
$azureStackEnvironment = Initialize-AzureRmEnvironment -EnvironmentName 'AzureStack' -ResourceManagerEndpoint $TenantResourceManagerEndpoint -DirectoryTenantName $DirectoryTenantName
|
||||
$azureEnvironment = Resolve-AzureEnvironment $azureStackEnvironment
|
||||
$refreshToken = Get-AzureRmUserRefreshToken $azureEnvironment $azureStackEnvironment.AdTenant
|
||||
$refreshToken = Get-AzureRmUserRefreshToken -azureEnvironment $azureEnvironment -directoryTenantId $azureStackEnvironment.AdTenant -AutomationCredential $AutomationCredential
|
||||
|
||||
# Initialize the Graph PowerShell module to communicate with the correct graph service
|
||||
$graphEnvironment = Resolve-GraphEnvironment $azureEnvironment
|
||||
$graphEnvironment = ResolveGraphEnvironment $azureEnvironment
|
||||
Initialize-GraphEnvironment -Environment $graphEnvironment -DirectoryTenantId $DirectoryTenantName -RefreshToken $refreshToken
|
||||
|
||||
# Initialize the service principal for the Azure Stack Resource Manager application (allows us to acquire a token to ARM). If not specified, the sign-up flow must be completed via the Azure Stack portal first.
|
||||
if ($ResourceManagerApplicationId)
|
||||
{
|
||||
$resourceManagerServicePrincipal = Initialize-GraphApplicationServicePrincipal -ApplicationId $ResourceManagerApplicationId
|
||||
}
|
||||
|
||||
# Authorize the Azure Powershell module to act as a client to call the Azure Stack Resource Manager in the onboarding directory tenant
|
||||
Initialize-GraphOAuth2PermissionGrant -ClientApplicationId (Get-GraphEnvironmentInfo).Applications.PowerShell.Id -ResourceApplicationIdentifierUri $azureStackEnvironment.ActiveDirectoryServiceEndpointResourceId
|
||||
Write-Host "Delaying for 15 seconds to allow the permission for Azure PowerShell to be initialized..."
|
||||
Start-Sleep -Seconds 15
|
||||
|
||||
# Authorize the Azure Powershell module to act as a client to call the Azure Stack Resource Manager in the onboarded tenant
|
||||
Initialize-GraphOAuth2PermissionGrant -ClientApplicationId (Get-GraphEnvironmentInfo).Applications.PowerShell.Id -ResourceApplicationIdentifierUri $azureStackEnvironment.ActiveDirectoryServiceEndpointResourceId
|
||||
|
||||
# Call Azure Stack Resource Manager to retrieve the list of registered applications which need to be initialized in the onboarding directory tenant
|
||||
$armAccessToken = (Get-GraphToken -Resource $azureStackEnvironment.ActiveDirectoryServiceEndpointResourceId -UseEnvironmentData).access_token
|
||||
$applicationRegistrationParams = @{
|
||||
Method = [Microsoft.PowerShell.Commands.WebRequestMethod]::Get
|
||||
Method = [Microsoft.PowerShell.Commands.WebRequestMethod]::Get
|
||||
Headers = @{ Authorization = "Bearer $armAccessToken" }
|
||||
Uri = "$($TenantResourceManagerEndpoint.ToString().TrimEnd('/'))/applicationRegistrations?api-version=2014-04-01-preview"
|
||||
Uri = "$($TenantResourceManagerEndpoint.ToString().TrimEnd('/'))/applicationRegistrations?api-version=2014-04-01-preview"
|
||||
}
|
||||
$applicationRegistrations = Invoke-RestMethod @applicationRegistrationParams | Select -ExpandProperty value
|
||||
$applicationRegistrations = Invoke-RestMethod @applicationRegistrationParams | Select-Object -ExpandProperty value
|
||||
|
||||
# Initialize each registered application in the onboarding directory tenant
|
||||
foreach ($applicationRegistration in $applicationRegistrations) {
|
||||
# Initialize the service principal for the registered application, updating any tags as necessary
|
||||
# Identify which permissions have already been granted to each registered application and which additional permissions need consent
|
||||
$permissions = @()
|
||||
foreach ($applicationRegistration in $applicationRegistrations)
|
||||
{
|
||||
# Initialize the service principal for the registered application
|
||||
$applicationServicePrincipal = Initialize-GraphApplicationServicePrincipal -ApplicationId $applicationRegistration.appId
|
||||
if ($applicationRegistration.tags) {
|
||||
|
||||
# Initialize the necessary tags for the registered application
|
||||
if ($applicationRegistration.tags)
|
||||
{
|
||||
Update-GraphApplicationServicePrincipalTags -ApplicationId $applicationRegistration.appId -Tags $applicationRegistration.tags
|
||||
}
|
||||
|
||||
# Initialize the necessary oauth2PermissionGrants for the registered application
|
||||
foreach ($oauth2PermissionGrant in $applicationRegistration.oauth2PermissionGrants) {
|
||||
$oauth2PermissionGrantParams = @{
|
||||
ClientApplicationId = $oauth2PermissionGrant.client
|
||||
ResourceApplicationId = $oauth2PermissionGrant.resource
|
||||
Scope = $oauth2PermissionGrant.scope
|
||||
# Lookup the permission consent status for the application permissions (either to or from) that the registered application requires
|
||||
foreach($appRoleAssignment in $applicationRegistration.appRoleAssignments)
|
||||
{
|
||||
$params = @{
|
||||
ClientApplicationId = $appRoleAssignment.client
|
||||
ResourceApplicationId = $appRoleAssignment.resource
|
||||
PermissionType = 'Application'
|
||||
PermissionId = $appRoleAssignment.roleId
|
||||
}
|
||||
Initialize-GraphOAuth2PermissionGrant @oauth2PermissionGrantParams
|
||||
$permissions += New-GraphPermissionDescription @params -LookupConsentStatus
|
||||
}
|
||||
|
||||
# Initialize the necessary directory role membership(s) for the registered application
|
||||
foreach ($directoryRole in $applicationRegistration.directoryRoles) {
|
||||
Initialize-GraphDirectoryRoleMembership -ApplicationId $applicationRegistration.appId -RoleDisplayName $directoryRole
|
||||
# Lookup the permission consent status for the delegated permissions (either to or from) that the registered application requires
|
||||
foreach($oauth2PermissionGrant in $applicationRegistration.oauth2PermissionGrants)
|
||||
{
|
||||
$resourceApplicationServicePrincipal = Initialize-GraphApplicationServicePrincipal -ApplicationId $oauth2PermissionGrant.resource
|
||||
foreach ($scope in $oauth2PermissionGrant.scope.Split(' '))
|
||||
{
|
||||
$params = @{
|
||||
ClientApplicationId = $oauth2PermissionGrant.client
|
||||
ResourceApplicationServicePrincipal = $resourceApplicationServicePrincipal
|
||||
PermissionType = 'Delegated'
|
||||
PermissionId = ($resourceApplicationServicePrincipal.oauth2Permissions | Where value -EQ $scope).id
|
||||
}
|
||||
$permissions += New-GraphPermissionDescription @params -LookupConsentStatus
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Show the user a display of the required permissions
|
||||
$permissions | Show-GraphApplicationPermissionDescriptions
|
||||
|
||||
if ($permissions | Where isConsented -EQ $false | Select -First 1)
|
||||
{
|
||||
# Grant the required permissions to the corresponding applications
|
||||
$permissions | Where isConsented -EQ $false | Grant-GraphApplicationPermission
|
||||
}
|
||||
|
||||
Write-Host "`r`nAll permissions required for registered Azure Stack applications or scenarios have been granted!" -ForegroundColor Green
|
||||
}
|
||||
|
||||
Export-ModuleMember -Function @(
|
||||
"Register-AzureStackWithMyDirectoryTenant",
|
||||
"Register-GuestDirectoryTenantToAzureStack",
|
||||
"Get-DirectoryTenantIdentifier",
|
||||
"New-AzsADGraphServicePrincipal"
|
||||
)
|
|
@ -1,7 +1,7 @@
|
|||
# Azure Stack Identity
|
||||
|
||||
```powershell
|
||||
Install-Module -Name 'AzureRm.Bootstrapper' -Scope CurrentUser
|
||||
// Place your settings in this file to overwrite the default settings
|
||||
{
|
||||
"workbench.colorTheme": "Abyss"
|
||||
}nstall-Module -Name 'AzureRm.Bootstrapper' -Scope CurrentUser
|
||||
Install-AzureRmProfile -profile '2017-03-09-profile' -Force -Scope CurrentUser
|
||||
Install-Module -Name AzureStack -RequiredVersion 1.2.9 -Scope CurrentUser
|
||||
```
|
||||
|
@ -18,7 +18,7 @@ Import-Module ..\Identity\AzureStack.Identity.psm1
|
|||
This function is used to get the Directory Tenant Guid. This method works for both AAD and AD FS.
|
||||
|
||||
```powershell
|
||||
$directoryTenantId = Get-DirectoryTenantIdentifier -Authority "<DirectoryTenantUrl>"
|
||||
$directoryTenantId = Get-AzsDirectoryTenantIdentifier -Authority "<DirectoryTenantUrl>"
|
||||
```
|
||||
|
||||
An example of an authority for AAD is `https://login.windows.net/microsoft.onmicrosoft.com`
|
||||
|
@ -29,7 +29,7 @@ and for AD FS is `https://adfs.local.azurestack.external/adfs`.
|
|||
You can create a Service Principal by executing the following command after importing the Identity module
|
||||
|
||||
```powershell
|
||||
$servicePrincipal = New-ADGraphServicePrincipal -DisplayName "<YourServicePrincipalName>" -AdminCredential $(Get-Credential) -Verbose
|
||||
$servicePrincipal = New-AzsAdGraphServicePrincipal -DisplayName "<YourServicePrincipalName>" -AdminCredential $(Get-Credential) -Verbose
|
||||
```
|
||||
|
||||
After the Service Principal is created, you should open your Azure Stack Portal to provide the appropriate level of RBAC to it. You can do this from the Access Control (IAM) tab of any resource. After the RBAC is given, you can login using the service principal as follows:
|
||||
|
@ -48,22 +48,6 @@ There are two personas involved in implementing this scenario.
|
|||
|
||||
### Azure Stack Administrator
|
||||
|
||||
#### Pre-Requisite: Populate Azure Resource Manager with AzureStack Applications
|
||||
|
||||
- This step is a temporary workaround and needed only for the TP3 (March) release of Azure Stack
|
||||
- Execute this cmdlet as the **Azure Stack Service Administrator**, from the Console VM or the DVM replacing ```$azureStackDirectoryTenant``` with the directory tenant that Azure Stack is registered to and ```$guestDirectoryTenant``` with the directory that needs to be onboarded to Azure Stack.
|
||||
|
||||
__NOTE:__ This cmd needs to be run **only once** throughout the entire life cycle of that Azure Stack installation. You do **not** have to run this step every time you need to add a new directory.
|
||||
|
||||
```powershell
|
||||
$adminARMEndpoint = "https://adminmanagement.<region>.<domain>"
|
||||
$azureStackDirectoryTenant = "<homeDirectoryTenant>.onmicrosoft.com"
|
||||
$guestDirectoryTenantToBeOnboarded = "<guestDirectoryTenant>.onmicrosoft.com"
|
||||
|
||||
Publish-AzureStackApplicationsToARM -AdminResourceManagerEndpoint $adminARMEndpoint `
|
||||
-DirectoryTenantName $azureStackDirectoryTenant
|
||||
```
|
||||
|
||||
#### Step 1: Onboard the Guest Directory Tenant to Azure Stack
|
||||
|
||||
This step will let Azure Resource manager know that it can accept users and service principals from the guest directory tenant.
|
||||
|
@ -72,9 +56,11 @@ This step will let Azure Resource manager know that it can accept users and serv
|
|||
$adminARMEndpoint = "https://adminmanagement.<region>.<domain>"
|
||||
$azureStackDirectoryTenant = "<homeDirectoryTenant>.onmicrosoft.com" # this is the primary tenant Azure Stack is registered to
|
||||
$guestDirectoryTenantToBeOnboarded = "<guestDirectoryTenant>.onmicrosoft.com" # this is the new tenant that needs to be onboarded to Azure Stack
|
||||
|
||||
$location = "local"
|
||||
Register-GuestDirectoryTenantToAzureStack -AdminResourceManagerEndpoint $adminARMEndpoint `
|
||||
-DirectoryTenantName $azureStackDirectoryTenant -GuestDirectoryTenantName $guestDirectoryTenantToBeOnboarded
|
||||
-DirectoryTenantName $azureStackDirectoryTenant `
|
||||
-GuestDirectoryTenantName $guestDirectoryTenantToBeOnboarded `
|
||||
-Location $location
|
||||
```
|
||||
|
||||
With this step, the work of the Azure Stack administrator is done.
|
||||
|
@ -85,7 +71,7 @@ The following steps need to be completed by the **Directory Tenant Administrator
|
|||
|
||||
#### Step 2: Providing UI-based consent to Azure Stack Portal and ARM
|
||||
|
||||
- This is an important step. Open up a web browser, and go to `https://portal.<region>.<domain>/guest/signup/<guestDirectoryName>`. Note that this is the directory tenant that needs to be onboarded to Azure Stack.
|
||||
- This is an important step. Open up a web browser, and go to `https://portal.<region>.<domain>/guest/signup/<guestDirectoryName>`. Note that this is the directory tenant that needs to be onboarded to Azure Stack.
|
||||
- This will take you to an AAD sign in page where you need to enter your credentials and click on 'Accept' on the consent screen.
|
||||
|
||||
#### Step 3: Registering Azure Stack applications with the Guest Directory
|
||||
|
@ -97,5 +83,5 @@ $tenantARMEndpoint = "https://management.<region>.<domain>"
|
|||
$guestDirectoryTenantName = "<guestDirectoryTenant>.onmicrosoft.com" # this is the new tenant that needs to be onboarded to Azure Stack
|
||||
|
||||
Register-AzureStackWithMyDirectoryTenant -TenantResourceManagerEndpoint $tenantARMEndpoint `
|
||||
-DirectoryTenantName $guestDirectoryTenantName -Verbose -Debug
|
||||
-DirectoryTenantName $guestDirectoryTenantName
|
||||
```
|
||||
|
|
После Ширина: | Высота: | Размер: 1.8 MiB |
|
@ -3,12 +3,7 @@
|
|||
Instructions below are relative to the .\Infrastructure folder of the [AzureStack-Tools repo](..).
|
||||
This also requires the Azure Stack Connect Module to be imported before running any of the commands. The Module can also be found in the [AzureStack-Tools repo](..).
|
||||
|
||||
Whats new for TP3:
|
||||
|
||||
- New Cmdlet Name Prefix
|
||||
- API Resource Name changes
|
||||
- New cmdlets
|
||||
- Use of Azure Stack Connect Module
|
||||
![Using infrastructure cmdlets against Azure Stack](/Infrastructure/InfraAlertsVideo.gif)
|
||||
|
||||
## Import the Module
|
||||
|
||||
|
@ -17,32 +12,29 @@ Import-Module .\AzureStack.Infra.psm1
|
|||
```
|
||||
|
||||
## Add PowerShell environment
|
||||
```powershell
|
||||
Import-Module .\AzureStack.Connect.psm1
|
||||
```
|
||||
|
||||
You will need to reference your Azure Stack Administrator environment. To create an administrator environment use the below. The ARM endpoint below is the administrator default for a one-node environment.
|
||||
You will need to login to your Azure Stack Administrator environment. To create an administrator environment use the below. The ARM endpoint below is the administrator default for a one-node environment.
|
||||
|
||||
```powershell
|
||||
Add-AzureStackAzureRmEnvironment -Name "AzureStackAdmin" -ArmEndpoint "https://adminmanagement.local.azurestack.external"
|
||||
```
|
||||
|
||||
Connecting to your environment requires that you obtain the value of your Directory Tenant ID. For **Azure Active Directory** environments provide your directory tenant name:
|
||||
|
||||
```powershell
|
||||
$TenantID = Get-DirectoryTenantID -AADTenantName "<mydirectorytenant>.onmicrosoft.com" -EnvironmentName AzureStackAdmin
|
||||
```
|
||||
|
||||
For **ADFS** environments use the following:
|
||||
|
||||
```powershell
|
||||
$TenantID = Get-DirectoryTenantID -ADFS -EnvironmentName AzureStackAdmin
|
||||
Add-AzureRMEnvironment -Name "AzureStackAdmin" -ArmEndpoint "https://adminmanagement.local.azurestack.external"
|
||||
```
|
||||
|
||||
Then login:
|
||||
|
||||
```powershell
|
||||
Login-AzureRmAccount -EnvironmentName "AzureStackAdmin" -TenantId $TenantID
|
||||
Login-AzureRmAccount -EnvironmentName "AzureStackAdmin"
|
||||
```
|
||||
----
|
||||
If you are **not** using your home directory tenant, you will need to supply the tenant ID to your login command. You may find it easiest to obtain using the Connect tool. For **Azure Active Directory** environments provide your directory tenant name:
|
||||
|
||||
```powershell
|
||||
$TenantID = Get-AzsDirectoryTenantId -AADTenantName "<mydirectorytenant>.onmicrosoft.com" -EnvironmentName AzureStackAdmin
|
||||
```
|
||||
|
||||
For **ADFS** environments use the following:
|
||||
|
||||
```powershell
|
||||
$TenantID = Get-AzsDirectoryTenantId -ADFS -EnvironmentName AzureStackAdmin
|
||||
```
|
||||
|
||||
## Individual Command Usage
|
||||
|
@ -54,406 +46,356 @@ Explains each individual command and shows how to use it
|
|||
List active and closed Infrastructure Alerts
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Get-AzSAlert -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsAlert
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to retrieve Alerts. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Retrieves Active & Closed Alerts
|
||||
|
||||
|
||||
### Close Infrastructure Alerts
|
||||
|
||||
Close any active Infrastructure Alert. Run Get-AzureStackAlert to get the AlertID, required to close a specific Alert.
|
||||
Close any active Infrastructure Alert. Run Get-AzsAlert to get the AlertID, required to close a specific Alert.
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Close-AzSAlert -AzureStackCredentials $credential -TenantID $TenantID -AlertID "ID" -EnvironmentName "AzureStackAdmin"
|
||||
Close-AzsAlert -AlertID "ID"
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to close active Alert. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Close active Alert
|
||||
|
||||
|
||||
### Get Region Update Summary
|
||||
|
||||
Review the Update Summary for a specified region.
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Get-AzSUpdateSummary -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsUpdateSummary
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to retrieve Region Update Summary. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Retrieves Region Update Summary
|
||||
|
||||
|
||||
### Get Azure Stack Update
|
||||
|
||||
Retrieves list of Azure Stack Updates
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Get-AzSUpdate -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsUpdate
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to retrieve Azure Stack Updates. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- List Azure Stack Updates
|
||||
|
||||
|
||||
### Apply Azure Stack Update
|
||||
|
||||
Applies a specific Azure Stack Update that is downloaded and applicable. Run Get-AzureStackUpdate to retrieve Update Version first
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Install-AzSUpdate -AzureStackCredentials $credential -TenantID $TenantID -vupdate "Update Version" -EnvironmentName "AzureStackAdmin"
|
||||
Install-AzsUpdate -Update "Update Version"
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to apply a specific Update. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Applies specified Update
|
||||
|
||||
|
||||
### Get Azure Stack Update Run
|
||||
|
||||
Should be used to validate a specific Update Run or look at previous update runs
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Get-AzSUpdateRun -AzureStackCredentials $credential -TenantID $TenantID -vupdate "Update Version" -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsUpdateRun -Update "Update Version"
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to retrieve Update Run information. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Lists Update Run information for a specific Azure Stack update
|
||||
|
||||
|
||||
### List Infrastructure Roles
|
||||
|
||||
Does list all Infrastructure Roles
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Get-AzSInfraRole -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsInfrastructureRole
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to retrieve Infrastructure Roles. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Lists Infrastructure Roles
|
||||
|
||||
|
||||
### List Infrastructure Role Instance
|
||||
|
||||
Does list all Infrastructure Role Instances (Note: Does not return Directory Management VM in One Node deployment)
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Get-AzSInfraRoleInstance -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsInfrastructureRoleInstance
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to retrieve Infrastructure Role Instances. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Lists Infrastructure Role Instances
|
||||
|
||||
|
||||
### List Scale Unit
|
||||
|
||||
Does list all Scale Units in a specified Region
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Get-AzSScaleUnit -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsScaleUnit
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to retrieve Scale Units. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Lists Scale Units
|
||||
|
||||
|
||||
### List Scale Unit Nodes
|
||||
|
||||
Does list all Scale Units Nodes
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Get-AzSScaleUnitNode -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsScaleUnitNode
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to retrieve all Scale Unit Nodes. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Lists Scale Unit Nodes
|
||||
|
||||
|
||||
### List Logical Networks
|
||||
|
||||
Does list all logical Networks by ID
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Get-AzSLogicalNetwork -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsLogicalNetwork
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to retrieve logical Networks. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Lists logical Networks
|
||||
|
||||
|
||||
### List Storage Capacity
|
||||
|
||||
Does return the total capacity of the storage subsystem
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Get-AzSStorageCapacity -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsStorageCapacity
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to retrieve total storage capacity. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Lists total storage capacity for the storage subsystem
|
||||
|
||||
|
||||
### List Storage Shares
|
||||
|
||||
Does list all file shares in the storage subsystem
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Get-AzSStorageShare -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
|
||||
Get-AzsStorageShare
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to retrieve file shares. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Retrieves all file shares
|
||||
|
||||
|
||||
### List IP Pools
|
||||
|
||||
Does list all IP Pools
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Get-AzSIPPool -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsIpPool
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to retrieve IP Pools. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Retrieves all IP Pools
|
||||
|
||||
|
||||
### List MAC Address Pools
|
||||
|
||||
Does list all MAC Address Pool
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Get-AzSMacPool -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsMacPool
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to retrieve all MAC Address Pools. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Retrieves all MAC Address Pools
|
||||
|
||||
|
||||
### List Gateway Pools
|
||||
|
||||
Does list all Gateway Pools
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Get-AzSGatewayPool -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsGatewayPool
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to retrieve the Gateway Pools. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Retrieves all Gateway Pools
|
||||
|
||||
|
||||
### List SLB MUX
|
||||
|
||||
Does list all SLB MUX Instances
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Get-AzSSLBMUX -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzSLBMux
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to retrieve all SLB MUX instances. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Retrieves all SLB MUX instances
|
||||
|
||||
|
||||
### List Gateway Instances
|
||||
|
||||
Does list all Gateway Instances
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Get-AzSGateway -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsGateway
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to retrieve all Gateway instances. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Retrieves all Gateway instances
|
||||
|
||||
|
||||
### Start Infra Role Instance
|
||||
|
||||
Does start an Infra Role Instance
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Start-AzSInfraRoleInstance -AzureStackCredentials $credential -TenantID $TenantID -Name "InfraRoleInstanceName" -EnvironmentName "AzureStackAdmin"
|
||||
Start-AzsInfrastructureRoleInstance -Name "InfraRoleInstanceName"
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to start an infra role instance. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Starts an Infra Role instance
|
||||
|
||||
|
||||
### Stop Infra Role Instance
|
||||
|
||||
Does stop an Infra Role Instance
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Stop-AzSInfraRoleInstance -AzureStackCredentials $credential -TenantID $TenantID -Name "InfraRoleInstanceName" -EnvironmentName "AzureStackAdmin"
|
||||
Stop-AzsInfrastructureRoleInstance -Name "InfraRoleInstanceName"
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to stop an infra role instance. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Stops an Infra Role instance
|
||||
|
||||
|
||||
### Restart Infra Role Instance
|
||||
|
||||
Does restart an Infra Role Instance
|
||||
Does Restart an Infra Role Instance
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Restart-AzSInfraRoleInstance -AzureStackCredentials $credential -TenantID $TenantID -Name "InfraRoleInstanceName" -EnvironmentName "AzureStackAdmin"
|
||||
Restart-AzsInfrastructureRoleInstance -Name "InfraRoleInstanceName"
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to restart an infra role instance. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Restart an Infra Role instance
|
||||
|
||||
|
||||
### Add IP Pool
|
||||
|
||||
Does add an IP Pool
|
||||
|
||||
```powershell
|
||||
$credential = Get-Credential
|
||||
Add-AzSIPPool -AzureStackCredentials $credential -TenantID $TenantID -Name "PoolName" -StartIPAddress "192.168.55.1" -EndIPAddress "192.168.55.254" -AddressPrefix "192.168.0./24" -EnvironmentName "AzureStackAdmin"
|
||||
Add-AzsIpPool -Name "PoolName" -StartIPAddress "192.168.55.1" -EndIPAddress "192.168.55.254" -AddressPrefix "192.168.0./24"
|
||||
```
|
||||
|
||||
Note: The cmdlet requires credentials to add an IP Pool. Provide the administrator Azure Active Directory credentials, such as *<Admin Account>*@*<mydirectory>*.onmicrosoft.com or the ADFS credentials, to the prompt.
|
||||
|
||||
The command does the following:
|
||||
- Authenticates to the Azure Stack environment
|
||||
- Adds an IP Pool
|
||||
|
||||
### Enable Maintenance Mode
|
||||
|
||||
Does put a ScaleUnitNode in Maintenance Mode
|
||||
|
||||
```powershell
|
||||
Disable-AzsScaleUnitNode -Name NodeName
|
||||
```
|
||||
|
||||
The command does the following:
|
||||
- Enables Maintenance Mode for a specified ScaleUnitNode
|
||||
|
||||
### Disable Maintenance Mode
|
||||
|
||||
Does resume a ScaleUnitNode from Maintenance Mode
|
||||
|
||||
```powershell
|
||||
Enable-AzsScaleUnitNode -Name NodeName
|
||||
```
|
||||
|
||||
The command does the following:
|
||||
- Resume from Maintenance Mode for a specified ScaleUnitNode
|
||||
|
||||
### Show Region Capacity
|
||||
|
||||
Does show capacity for specified Region
|
||||
|
||||
```powershell
|
||||
Get-AzsLocationCapacity
|
||||
```
|
||||
|
||||
The command does the following:
|
||||
- Retrieves Region Capacity information
|
||||
|
||||
## Scenario Command Usage
|
||||
|
||||
Demonstrates using multiple commands together for an end to end scenario.
|
||||
|
||||
### Recover an Infrastructure Role Instance that has an Alert assigned.
|
||||
### Recover an Infrastructure Role Instance that has an Alert assigned
|
||||
|
||||
```powershell
|
||||
#Retrieve all Alerts and apply a filter to only show active Alerts
|
||||
$Active=Get-AzSAlert -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"|where {$_.state -eq "active"}
|
||||
$Active=Get-AzsAlert | Where {$_.State -eq "active"}
|
||||
$Active
|
||||
|
||||
#Stop Infra Role Instance
|
||||
Stop-AzSInfraRoleInstance -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin" -Name $Active.resourceName
|
||||
Stop-AzsInfrastructureRoleInstance -Name $Active.ResourceName
|
||||
|
||||
#Start Infra Role Instance
|
||||
Start-AzSInfraRoleInstance -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin" -Name $Active.resourceName
|
||||
Start-AzsInfrastructureRoleInstance -Name $Active.resourceName
|
||||
|
||||
#Validate if error is resolved (Can take up to 3min)
|
||||
Get-AzSAlert -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"|where {$_.state -eq "active"}
|
||||
Get-AzsAlert | Where {$_.State -eq "active"}
|
||||
```
|
||||
|
||||
|
||||
### Increase Public IP Pool Capacity
|
||||
|
||||
```powershell
|
||||
#Retrieve all Alerts and apply a filter to only show active Alerts
|
||||
$Active=Get-AzSAlert -AzureStackCredentials $cred -TenantID $TenantID -EnvironmentName "AzureStackAdmin"|where {$_.state -eq "active"}
|
||||
$Active=Get-AzsAlert | Where {$_.State -eq "active"}
|
||||
$Active
|
||||
|
||||
#Review IP Pool Allocation
|
||||
Get-AzSIPPool -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsIpPool
|
||||
|
||||
#Add New Public IP Pool
|
||||
Add-AzSIPPool -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin" -Name "NewPublicIPPool" -StartIPAddress "192.168.80.0" -EndIPAddress "192.168.80.255" -AddressPrefix "192.168.80.0/24"
|
||||
Add-AzsIpPool -Name "NewPublicIPPool" -StartIPAddress "192.168.80.0" -EndIPAddress "192.168.80.255" -AddressPrefix "192.168.80.0/24"
|
||||
|
||||
#Validate new IP Pool
|
||||
Get-AzSIPPool -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsIpPool
|
||||
```
|
||||
|
||||
### Apply Update to Azure Stack
|
||||
|
||||
```powershell
|
||||
#Review Current Region Update Summary
|
||||
Get-AzSUpdateSummary -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsUpdateSummary
|
||||
|
||||
#Check for available and applicable updates
|
||||
Get-AzSUpdate -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsUpdate
|
||||
|
||||
#Apply Update
|
||||
Install-AzSUpdate -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin" -vupdate "2.0.0.0"
|
||||
Install-AzsUpdate -Update "2.0.0.0"
|
||||
|
||||
#Check Update Run
|
||||
Get-AzSUpdateRun -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin" -vupdate "2.0.0.0"
|
||||
Get-AzsUpdateRun -Update "2.0.0.0"
|
||||
|
||||
#Review Region Update Summary after successful run
|
||||
Get-AzSUpdateSummary -AzureStackCredentials $credential -TenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Get-AzsUpdateSummary
|
||||
```
|
||||
|
||||
### Perform FRU procedure
|
||||
|
||||
```powershell
|
||||
#Review current ScaleUnitNode State
|
||||
$node=Get-AzsScaleUnitNode
|
||||
$node | fl
|
||||
|
||||
|
||||
#Enable Maintenance Mode for that node which drains all active resources
|
||||
Disable-AzsScaleUnitNode -Name $node.name
|
||||
|
||||
#Power Off Server using build in KVN or physical power button
|
||||
#BMC IP Address is returned by previous command $node.properties | fl
|
||||
#Apply FRU Procedure
|
||||
#Power On Server using build in KVN or physical power button
|
||||
|
||||
#Resume ScaleUnitNode from Maintenance Mode
|
||||
Enable-AzsScaleUnitNode -Name $node.name
|
||||
|
||||
#Validate ScaleUnitNode Status
|
||||
$node=Get-AzsScaleUnitNode
|
||||
$node | fl
|
||||
```
|
||||
|
||||
### Set Azure Stack's Latitude and Longitude
|
||||
|
@ -468,7 +410,6 @@ $latitude = '12.972442'
|
|||
$longitude = '77.580643'
|
||||
$regionName = 'local'
|
||||
|
||||
$TenantID = Get-DirectoryTenantID -AADTenantName $directoryName -EnvironmentName AzureStackAdmin
|
||||
Set-AzSLocationInformation -TenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredentials $credential -Region $regionName -Latitude $latitude -Longitude $longitude
|
||||
Set-AzsLocationInformation -Region $regionName -Latitude $latitude -Longitude $longitude
|
||||
|
||||
```
|
||||
|
|
|
@ -11,8 +11,8 @@ Describe $script:ModuleName {
|
|||
Should Not Be $null
|
||||
}
|
||||
|
||||
It 'Get-AzSAlert should be exported' {
|
||||
Get-Command -Name Get-AzSAlert -ErrorAction SilentlyContinue |
|
||||
It 'Get-AzsAlert should be exported' {
|
||||
Get-Command -Name Get-AzsAlert -ErrorAction SilentlyContinue |
|
||||
Should Not Be $null
|
||||
}
|
||||
}
|
||||
|
@ -23,67 +23,56 @@ InModuleScope $script:ModuleName {
|
|||
$HostComputer = $global:HostComputer
|
||||
$ArmEndpoint = $global:ArmEndpoint
|
||||
$natServer = $global:natServer
|
||||
$AdminUser= $global:AdminUser
|
||||
$AdminUser = $global:AdminUser
|
||||
$AadServiceAdmin = $global:AadServiceAdmin
|
||||
|
||||
$AdminPassword = $global:AdminPassword
|
||||
$AadServiceAdminPassword = $global:AadServiceAdminPassword
|
||||
$stackLoginCreds = $global:AzureStackLoginCredentials
|
||||
|
||||
$VPNConnectionName = $global:VPNConnectionName
|
||||
|
||||
$AadTenant = $global:AadTenantID
|
||||
|
||||
$EnvironmentName = $global:EnvironmentName
|
||||
|
||||
|
||||
Describe 'Infra - Functional Tests' {
|
||||
It 'Get-AzSAlert should not throw' {
|
||||
{ Get-AzSAlert -TenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredentials $stackLoginCreds } |
|
||||
It 'Get-AzsAlert should not throw' {
|
||||
{ Get-AzsAlert } |
|
||||
Should Not Throw
|
||||
}
|
||||
It 'Get-AzSScaleUnit should not throw' {
|
||||
{ Get-AzSAlert -TenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredentials $stackLoginCreds } |
|
||||
It 'Get-AzsScaleUnit should not throw' {
|
||||
{ Get-AzsAlert } |
|
||||
Should Not Throw
|
||||
}
|
||||
It 'Get-AzSScaleUnitNode should not throw' {
|
||||
{ Get-AzSScaleUnitNode -TenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredentials $stackLoginCreds } |
|
||||
It 'Get-AzsScaleUnitNode should not throw' {
|
||||
{ Get-AzsScaleUnitNode } |
|
||||
Should Not Throw
|
||||
}
|
||||
It 'Get-AzSStorageCapacity should not throw' {
|
||||
{ Get-AzSStorageCapacity -TenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredentials $stackLoginCreds } |
|
||||
It 'Get-AzsStorageCapacity should not throw' {
|
||||
{ Get-AzsStorageCapacity } |
|
||||
Should Not Throw
|
||||
}
|
||||
It 'Get-AzSInfraRole should not throw' {
|
||||
{ Get-AzSInfraRole -TenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredentials $stackLoginCreds } |
|
||||
It 'Get-AzsInfraRole should not throw' {
|
||||
{ Get-AzsInfraRole } |
|
||||
Should Not Throw
|
||||
}
|
||||
It 'Get-AzSInfraRoleInstance should not throw' {
|
||||
{ Get-AzSInfraRoleInstance -TenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredentials $stackLoginCreds } |
|
||||
It 'Get-AzsInfraRoleInstance should not throw' {
|
||||
{ Get-AzsInfraRoleInstance } |
|
||||
Should Not Throw
|
||||
}
|
||||
It 'Get-AzSStorageShare should not throw' {
|
||||
{ Get-AzSStorageShare -TenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredentials $stackLoginCreds } |
|
||||
It 'Get-AzsStorageShare should not throw' {
|
||||
{ Get-AzsStorageShare } |
|
||||
Should Not Throw
|
||||
}
|
||||
It 'Get-AzSlogicalnetwork should not throw' {
|
||||
{ Get-AzSlogicalnetwork -TenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredentials $stackLoginCreds } |
|
||||
It 'Get-Azslogicalnetwork should not throw' {
|
||||
{ Get-Azslogicalnetwork } |
|
||||
Should Not Throw
|
||||
}
|
||||
|
||||
It 'Get-AzSUpdateSummary should not throw' {
|
||||
{ Get-AzSUpdateSummary -TenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredentials $stackLoginCreds } |
|
||||
It 'Get-AzsUpdateSummary should not throw' {
|
||||
{ Get-AzsUpdateSummary } |
|
||||
Should Not Throw
|
||||
}
|
||||
It 'Get-AzSUpdate should not throw' {
|
||||
{ Get-AzSUpdate -TenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredentials $stackLoginCreds } |
|
||||
It 'Get-AzsUpdate should not throw' {
|
||||
{ Get-AzsUpdate } |
|
||||
Should Not Throw
|
||||
}
|
||||
It 'Set-AzSLocationInformation should not throw' {
|
||||
{ Set-AzSLocationInformation -TenantID $AadTenant -EnvironmentName $EnvironmentName -AzureStackCredentials $stackLoginCreds -Region 'local' -Latitude '12.972442' -Longitude '77.580643'} |
|
||||
Should Not Throw
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
После Ширина: | Высота: | Размер: 601 B |
После Ширина: | Высота: | Размер: 1.5 KiB |
После Ширина: | Высота: | Размер: 260 B |
После Ширина: | Высота: | Размер: 220 KiB |
После Ширина: | Высота: | Размер: 662 B |
После Ширина: | Высота: | Размер: 1.0 KiB |
После Ширина: | Высота: | Размер: 5.7 KiB |
После Ширина: | Высота: | Размер: 1.1 KiB |
|
@ -0,0 +1,16 @@
|
|||
# Azure Stack Marketplace Toolkit parameter file
|
||||
|
||||
$ApplicationName = "Windows Server"
|
||||
$Publisher = "Contoso"
|
||||
$Summary = "Windows Server virtual machine"
|
||||
$Description = "This marketplace item deploys a Windows Server virtual machine, a Virtual Network (with DNS), a Public IP address, a Network Security Group, and a Network Interface."
|
||||
$Category = "Solutions"
|
||||
$Icon40x40 = "C:\AzureStack_Marketplace\40.png"
|
||||
$Icon90x90 = "C:\AzureStack_Marketplace\90.png"
|
||||
$Icon115x115 = "C:\AzureStack_Marketplace\115.png"
|
||||
$Icon255x115 = "C:\AzureStack_Marketplace\255.png"
|
||||
$Screenshot533X324 = "C:\AzureStack_Marketplace\533.png"
|
||||
$ArmTemplate = ""
|
||||
$ExecutablePath = ""
|
||||
$UserName = "admin@mydomain.onmicrosoft.com"
|
||||
$Endpoint = "adminmanagement.local.azurestack.external"
|
|
@ -0,0 +1,72 @@
|
|||
# The Marketplace Toolkit for Microsoft Azure Stack
|
||||
|
||||
The Marketplace Toolkit for Microsoft Azure Stack provides service administrators and application developers with a UI to create and upload marketplace items to the Microsoft Azure Stack marketplace.
|
||||
|
||||
## Features
|
||||
|
||||
The toolkit allows you to
|
||||
- Create and publish a solution for the marketplace. This accepts any main ARM template and allows you to define the tenant deployment experience, by creating steps, re-assigning and re-ordering parameters.
|
||||
- Create and publish an extension for the marketplace. This creates a marketplace item for a VM Extension template that will surface on the extension tab of a deployed virtual machine.
|
||||
- Publish an existing package. If you have an existing marketplace item package (.azpkg file), the publish wizard enables an easy wizard to publish the package to the marketplace.
|
||||
|
||||
## Requirements
|
||||
|
||||
To use the Marketplace Toolkit for Microsoft Azure Stack script you require:
|
||||
|
||||
- This script
|
||||
- The gallerypackager executable (http://www.aka.ms/azurestackmarketplaceitem)
|
||||
- Access as Azure Stack administrator to the Azure Stack environment. This is only required if you want to publish the generated package to the marketplace. For this you will also need to install the current PowerShell modules to support Azure Stack on the machine that runs this script (https://docs.microsoft.com/en-us/azure/azure-stack/azure-stack-powershell-install).
|
||||
|
||||
## Download the Marketplace Toolkit
|
||||
To download the Azure Stack Marketplace Toolkit from this repository, run the following PowerShell script:
|
||||
|
||||
```PowerShell
|
||||
# Variables
|
||||
$Uri = 'https://raw.githubusercontent.com/Azure/AzureStack-Tools/master/Marketplace/'
|
||||
$LocalPath = 'c:\AzureStack_Marketplace'
|
||||
|
||||
# Create folder
|
||||
New-Item $LocalPath -Type directory
|
||||
|
||||
# Files
|
||||
$files = @{
|
||||
'40.png',
|
||||
'90.png',
|
||||
'115.png',
|
||||
'255.png',
|
||||
'533.png',
|
||||
'MarketplaceToolkit.ps1',
|
||||
'MarketplaceToolkit_parameters.ps1'
|
||||
}
|
||||
|
||||
# Download files
|
||||
$files | foreach { Invoke-WebRequest ($uri + $_) -OutFile ($LocalPath + '\' + $_) }
|
||||
```
|
||||
|
||||
## Create a marketplace item
|
||||
|
||||
Start the Marketplace Toolkit in a PowerShell session.
|
||||
|
||||
``` PowerShell
|
||||
cd c:\AzureStack_Marketplace
|
||||
.\MarketplaceToolkit.ps1
|
||||
```
|
||||
From the dashboard you can select a solution, an extension or publish an existing .azpkg file. Select solution.
|
||||
|
||||
- Step one of the wizard will gather the text details for the marketplace item and the icons that will show up in the marketplace. Sample icons can be found in c:\AzureStack_Marketplace. Clicking preview UI Experience gives an idea of what the marketplace item will look like in Azure Stack. Optionally you can select a parameter file to populate the fields. This is useful when you want to reuse values for multiple marketplace items. c:\AzureStack_Marketplace contains an example parameter file called MarketplaceToolkit_parameters.ps1.
|
||||
- Step two of the wizard specifies the ARM template for the marketplace item and the path of the gallerypackager executable. Browse for the ARM template. The deployment wizard tree view lists the parameters from the selected ARM. All parameters are listed on the basics step of the deployment wizard. You can add a new step by typing in the name of the step and click add. The new step is added to the tree view. If you select a parameter in the tree view the Details blade allows you to move the parameter up, down or move it to a different step. These changes are reflected in the tree view. You can only remove a step if there are no parameters assigned to it. The basics step cannot be removed. When the customization is finalized you can create the .azpkg file by selecting create (ensure you have specified the path to the gallerypackager.exe). The .azpkg file is generated and stored in the mydocuments folder. You can now close the wizard if you do not have access to an Azure Stack environment as Service Administrator or your Azure Stack environment is using ADFS for authentication.
|
||||
- Step three of the wizard provides an job to publish the marketplace item just created, to the marketplace. Specify the Azure AD credentials for your Azure Stack environment. The Admin API endpoint needs to be configured as FQDN (e.g. adminmanagement.local.azurestack.external). Both the AzureAD username and the Admin API endpoint can be configured in the parameter file. When you click publish, a background job is started that will publish the .azpkg file to the Azure Stack Marketplace.
|
||||
|
||||
The VM extension on the dashboard is used to create a marketplace item for a VM Extension. This marketplace item will be visible in the Add extension tab on an existing VM in Azure Stack. The process to create an extension item is similar to a creating a solution, with the following exceptions:
|
||||
|
||||
- The category for an extension is not specified.
|
||||
- The ARM template for an extension has two required parameters. vmName and Location. The UI will prevent you from selecting an ARM template if these two parameters are not present.
|
||||
- You cannot specify additional deployment wizard steps. A VM extension consists of a single blade.
|
||||
|
||||
## Limitations
|
||||
|
||||
- The current version of the script only supports Azure AD for directly publishing an package to the marketplace. We are working on adding support for ADFS. When you are using ADFS you can still create the marketplace item package with the tool, but publishing the package to the marketplace is a manual process in PowerShell.
|
||||
|
||||
## Improvements
|
||||
|
||||
The Marketplace Toolkit for Microsoft Azure Stack is based on PowerShell and the Windows Presentation Foundation. It is published in this public repository so you can make improvements to it by submitting a pull request.
|
|
@ -8,8 +8,8 @@
|
|||
.SYNOPSIS
|
||||
Produces Azure Resource Manager Policy document to apply to restrict Azure subscriptions to Azure Stack compatible functionality
|
||||
#>
|
||||
function Get-AzureStackRmPolicy
|
||||
{
|
||||
|
||||
function Get-AzsPolicy {
|
||||
$defaults = [System.IO.Path]::GetDirectoryName($PSCommandPath)
|
||||
|
||||
$providerMetadata = ConvertFrom-Json (Get-Content -Path ($defaults + "\AzureStack.Provider.Metadata.json") -Raw)
|
||||
|
@ -18,10 +18,8 @@ function Get-AzureStackRmPolicy
|
|||
|
||||
$allowResources = @()
|
||||
|
||||
foreach ($p in $providerMetadata.value)
|
||||
{
|
||||
foreach ($r in $p.resourceTypes)
|
||||
{
|
||||
foreach ($p in $providerMetadata.value) {
|
||||
foreach ($r in $p.resourceTypes) {
|
||||
$allowResources += @{ field = "type"; equals = $p.namespace + "/" + $r.ResourceType}
|
||||
$allowResources += @{ field = "type"; like = $p.namespace + "/" + $r.ResourceType + "/*" }
|
||||
}
|
||||
|
@ -31,7 +29,7 @@ function Get-AzureStackRmPolicy
|
|||
$storageSkuField = "Microsoft.Storage/storageAccounts/sku.name"
|
||||
|
||||
$policy = @{
|
||||
if = @{
|
||||
if = @{
|
||||
not = @{
|
||||
allOf = @(
|
||||
@{
|
||||
|
@ -43,13 +41,13 @@ function Get-AzureStackRmPolicy
|
|||
@{
|
||||
allOf = @(
|
||||
@{
|
||||
field = $vmSkuField;
|
||||
field = $vmSkuField;
|
||||
exists = "true"
|
||||
},
|
||||
@{
|
||||
not = @{
|
||||
field = $vmSkuField;
|
||||
in = $vmSkus
|
||||
in = $vmSkus
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -57,13 +55,13 @@ function Get-AzureStackRmPolicy
|
|||
@{
|
||||
allOf = @(
|
||||
@{
|
||||
field = $storageSkuField;
|
||||
field = $storageSkuField;
|
||||
exists = "true"
|
||||
},
|
||||
@{
|
||||
not = @{
|
||||
field = $storageSkuField;
|
||||
in = $storageSkus
|
||||
in = $storageSkus
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -82,4 +80,4 @@ function Get-AzureStackRmPolicy
|
|||
ConvertTo-Json $policy -Depth 100
|
||||
}
|
||||
|
||||
Export-ModuleMember Get-AzureStackRmPolicy
|
||||
Export-ModuleMember Get-AzsPolicy
|
||||
|
|
|
@ -11,7 +11,7 @@ Login-AzureRmAccount
|
|||
$s = Select-AzureRmSubscription -SubscriptionName "<sub name>"
|
||||
$subId = $s.Subscription.SubscriptionId
|
||||
|
||||
$policy = New-AzureRmPolicyDefinition -Name AzureStack -Policy (Get-AzureStackRmPolicy)
|
||||
$policy = New-AzureRmPolicyDefinition -Name AzureStack -Policy (Get-AzsPolicy)
|
||||
|
||||
New-AzureRmPolicyAssignment -Name AzureStack -PolicyDefinition $policy -Scope /subscriptions/$subId
|
||||
```
|
||||
|
@ -25,7 +25,9 @@ New-AzureRmPolicyAssignment -Name AzureStack -PolicyDefinition $policy -Scope /s
|
|||
```
|
||||
|
||||
To remove the Azure Stack policy, run this command with the same scope used when the policy was applied:
|
||||
|
||||
```powershell
|
||||
|
||||
Remove-AzureRmPolicyAssignment -Name AzureStack -Scope /subscriptions/$subId/resourceGroups/$rgName
|
||||
Remove-AzureRmPolicyAssignment -Name AzureStack -Scope /subscriptions/$subId
|
||||
```
|
||||
|
|
28
README.md
|
@ -1,13 +1,8 @@
|
|||
# Azure Stack Technical Preview Version
|
||||
|
||||
These tools are meant for use with **Azure Stack Technical Preview 3 Refresh**. Azure Stack Technical Preview 3 (March build) users can still use the tools in the [TP3.N](https://github.com/Azure/AzureStack-Tools/tree/TP3.N).
|
||||
These tools are meant for use with **Azure Stack Development Kit**. Azure Stack Technical Preview 3 Refresh users can still use the tools in the [TP3-Refresh](https://github.com/Azure/AzureStack-Tools/tree/TP3-Refresh).
|
||||
|
||||
A few notes for this release:
|
||||
- Default ARM endpoints have changed in this release.
|
||||
- Tools have been updated to include an EnvironmentName parameter.
|
||||
- Make sure to use the the Net35 parameter when uploading a Server 2016 image for use with deploying the PaaS services
|
||||
|
||||
# Tools for using Azure and Azure Stack
|
||||
## Tools for using Azure and Azure Stack
|
||||
|
||||
To use these tools, obtain Azure Stack compatible Azure PowerShell module. Unless you've installed from other sources, one way to do it is to obtain from public package repositories as follows. Note that both of these could still be used to operate against Azure as well as Azure Stack, but may lack some of the latest Azure features.
|
||||
|
||||
|
@ -16,12 +11,12 @@ For PowerShell, install the following:
|
|||
```powershell
|
||||
Install-Module -Name 'AzureRm.Bootstrapper' -Scope CurrentUser
|
||||
Install-AzureRmProfile -profile '2017-03-09-profile' -Force -Scope CurrentUser
|
||||
Install-Module -Name AzureStack -RequiredVersion 1.2.9 -Scope CurrentUser
|
||||
Install-Module -Name AzureStack -RequiredVersion 1.2.10 -Scope CurrentUser
|
||||
```
|
||||
|
||||
Obtain the tools by cloning the git repository.
|
||||
|
||||
```
|
||||
```commandline
|
||||
git clone https://github.com/Azure/AzureStack-Tools.git --recursive
|
||||
cd AzureStack-Tools
|
||||
```
|
||||
|
@ -33,44 +28,50 @@ invoke-webrequest https://github.com/Azure/AzureStack-Tools/archive/master.zip -
|
|||
expand-archive master.zip -DestinationPath . -Force
|
||||
cd AzureStack-Tools-master
|
||||
```
|
||||
|
||||
Instructions below are relative to the root of the repo.
|
||||
|
||||
## [Azure Resource Manager policy for Azure Stack](Policy)
|
||||
|
||||
Constrains Azure subscription to the capabilities available in the Azure Stack.
|
||||
|
||||
- Apply Azure Stack policy to Azure subscriptions and resource groups
|
||||
|
||||
## [Deployment of Azure Stack](Deployment)
|
||||
|
||||
Helps prepare for Azure Stack deployment.
|
||||
- Prepare to Deploy (boot from VHD)
|
||||
- Prepare to Redeploy (boot back to original/base OS)
|
||||
|
||||
- Prepare to Deploy (boot from VHD)
|
||||
- Prepare to Redeploy (boot back to original/base OS)
|
||||
|
||||
## [Connecting to Azure Stack](Connect)
|
||||
|
||||
Connect to an Azure Stack instance from your personal computer/laptop.
|
||||
|
||||
- Connect via VPN to an Azure Stack installation
|
||||
- Configure Azure Stack PowerShell environment
|
||||
- Prepare new subscriptions for use in PowerShell and CLI
|
||||
|
||||
## [Setting up Identity for Azure Stack](Identity)
|
||||
|
||||
Create and manage identity related objects and configurations for Azure Stack
|
||||
|
||||
- Create Service Principals in a disconnected topology
|
||||
|
||||
## [Azure Stack Service Administration](ServiceAdmin)
|
||||
|
||||
Manage plans and subscriptions in Azure Stack.
|
||||
|
||||
- Add default (unlimited) plans and quotas so that tenants can create new subscriptions
|
||||
|
||||
## [Azure Stack Compute Administration](ComputeAdmin)
|
||||
|
||||
Manage compute (VM) service in Azure Stack.
|
||||
|
||||
- Add VM Image to the Azure Stack Marketplace
|
||||
|
||||
## [Azure Stack Infrastructure Administration](Infrastructure)
|
||||
|
||||
Manage Azure Stack Infrastructure
|
||||
|
||||
- Get Infrastructure Roles
|
||||
- Get Infrastructure Role Instances
|
||||
- Start Infrastructure Role Instance
|
||||
|
@ -97,6 +98,7 @@ Manage Azure Stack Infrastructure
|
|||
## [AzureRM Template Validator](TemplateValidator)
|
||||
|
||||
Validate Azure ARM Template Capabilities
|
||||
|
||||
- resources - Types, Location, Apiversion
|
||||
- Compute Capabilities - extensions, images, sizes
|
||||
- Storage Capabilities - skus
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
# Registration
|
||||
|
||||
This script must be run from the Host machine. As a prerequisite, make sure that you have an Azure subscription and that you have installed Azure PowerShell:
|
||||
|
||||
```powershell
|
||||
Install-Module -Name AzureRM
|
||||
Install-Module -Name AzureRM
|
||||
```
|
||||
|
||||
This script helps you to run through the steps of registering your Azure Stack with your Azure subscription. Additional details can be found in the [documentation](https://docs.microsoft.com/en-us/azure/azure-stack/azure-stack-register).
|
||||
This script helps you to run through the steps of registering your Azure Stack with your Azure subscription. Additional details can be found in the [documentation](https://docs.microsoft.com/en-us/azure/azure-stack/azure-stack-register).
|
||||
|
||||
To run the script:
|
||||
|
||||
|
@ -12,4 +14,4 @@ To run the script:
|
|||
RegisterWithAzure.ps1 -azureDirectory YourDirectory -azureSubscriptionId YourGUID -azureSubscriptionOwner YourAccountName
|
||||
```
|
||||
|
||||
You will be prompted for your Azure credentials one more time as well as prompted to click "Enter" twice as the script runs.
|
||||
You will be prompted for your Azure credentials one more time as well as prompted to click "Enter" twice as the script runs.
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# See LICENSE.txt in the project root for license information.
|
||||
# See LICENSE.txt in the project root for license information.
|
||||
|
||||
<#
|
||||
|
||||
.SYNOPSIS
|
||||
|
||||
This script can be used to register Azure Stack POC with Azure. To run this script, you must have a public Azure subscription of any type.
|
||||
There must also be an account that is an owner or contributor of the subscription. This account cannot be an MSA (i.e. cannot be live.com or hotmail.com) or 2FA account.
|
||||
<#
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
RegisterToAzure runs local scripts to connect your Azure Stack to Azure. After connecting with Azure, you can test marketplace syndication.
|
||||
.SYNOPSIS
|
||||
|
||||
This script can be used to register Azure Stack POC with Azure. To run this script, you must have a public Azure subscription of any type.
|
||||
There must also be an account that is an owner or contributor of the subscription.
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
RegisterToAzure runs local scripts to connect your Azure Stack to Azure. After connecting with Azure, you can test marketplace syndication.
|
||||
|
||||
The script will follow four steps:
|
||||
Configure bridge identity: configures Azure Stack so that it can call to Azure via your Azure subscription
|
||||
|
@ -18,176 +18,192 @@ Get registration request: get Azure Stack environment information to create a re
|
|||
Register with Azure: uses Azure powershell to create an "Azure Stack Registration" resource on your Azure subscription
|
||||
Activate Azure Stack: final step in connecting Azure Stack to be able to call out to Azure
|
||||
|
||||
.PARAMETER azureSubscriptionId
|
||||
|
||||
.PARAMETER azureSubscriptionId
|
||||
|
||||
|
||||
Azure subscription ID that you want to register your Azure Stack with. This parameter is mandatory.
|
||||
|
||||
.PARAMETER azureDirectory
|
||||
|
||||
.PARAMETER azureDirectoryTenantName
|
||||
|
||||
Name of your AAD Tenant which your Azure subscription is a part of. This parameter is mandatory.
|
||||
|
||||
.PARAMETER azureSubscriptionOwner
|
||||
|
||||
.PARAMETER azureAccountId
|
||||
|
||||
Username for an owner/contributor of the azure subscription. This user must not be an MSA or 2FA account. This parameter is mandatory.
|
||||
|
||||
.PARAMETER azureSubscriptionPassword
|
||||
.PARAMETER azureCredential
|
||||
|
||||
Password for the Azure subscription. You will be prompted to type in this password. This parameter is mandatory.
|
||||
Powershell object that contains credential information such as user name and password. If not supplied script will request login via gui
|
||||
|
||||
.PARAMETER marketplaceSyndication
|
||||
.PARAMETER azureEnvironment
|
||||
|
||||
Flag (ON/OFF) whether to enable downloading items from the Azure marketplace on this environment. Defaults to "ON".
|
||||
Environment name for use in retrieving tenant details and running several of the activation scripts. Defaults to "AzureCloud".
|
||||
|
||||
.PARAMETER reportUsage
|
||||
|
||||
Flag (ON/OFF) whether to enable pushing usage data to Azure on this environment. Defaults to "ON".
|
||||
.PARAMETER azureResourceManagerEndpoint
|
||||
|
||||
URI used for ActivateBridge.ps1 that refers to the endpoint for Azure Resource Manager. Defaults to "https://management.azure.com"
|
||||
|
||||
.EXAMPLE
|
||||
|
||||
This script must be run from the Host machine of the POC.
|
||||
.\RegisterWithAzure.ps1 -azureSubscriptionId "5e0ae55d-0b7a-47a3-afbc-8b372650abd3" -azureDirectory "contoso.onmicrosoft.com" -azureSubscriptionOwner "serviceadmin@contoso.onmicrosoft.com"
|
||||
This script must be run from the Host machine of the POC.
|
||||
.\RegisterWithAzure.ps1 -azureSubscriptionId "5e0ae55d-0b7a-47a3-afbc-8b372650abd3" -azureDirectoryTenantName "contoso.onmicrosoft.com" -azureAccountId "serviceadmin@contoso.onmicrosoft.com"
|
||||
|
||||
|
||||
.NOTES
|
||||
Ensure that you have an Azure subscription
|
||||
|
||||
.NOTES
|
||||
Ensure that you have an Azure subscription and it is registered for Microsoft.AzureStack namespace in Azure.
|
||||
Namespace can be registered with the following command:
|
||||
Register-AzureRmResourceProvider -ProviderNamespace 'microsoft.azurestack'
|
||||
#>
|
||||
|
||||
|
||||
[CmdletBinding()]
|
||||
Param (
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$azureDirectory,
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[PSCredential] $azureCredential,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[String]$azureSubscriptionId,
|
||||
[String] $azureAccountId,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[String]$azureSubscriptionOwner,
|
||||
[String] $azureSubscriptionId,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[securestring]$azureSubscriptionPassword,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[ValidateSet('On', 'Off')]
|
||||
[string] $marketplaceSyndication = 'On',
|
||||
[String] $azureDirectoryTenantName,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[ValidateSet('On', 'Off')]
|
||||
[string] $reportUsage = 'On'
|
||||
[Parameter(Mandatory = $false)]
|
||||
[String] $azureEnvironment = "AzureCloud",
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[String] $azureResourceManagerEndpoint = "https://management.azure.com",
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[bool] $enableSyndication = $true,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[Switch] $reportUsage = $false
|
||||
)
|
||||
|
||||
#requires -Module AzureRM.Profile
|
||||
#requires -Module AzureRM.Resources
|
||||
#requires -RunAsAdministrator
|
||||
|
||||
Import-Module C:\CloudDeployment\ECEngine\EnterpriseCloudEngine.psm1 -Force
|
||||
cd C:\CloudDeployment\Setup\Activation\Bridge
|
||||
$ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop
|
||||
$VerbosePreference = [System.Management.Automation.ActionPreference]::Continue
|
||||
|
||||
Read-Host "This script will turn marketplace syndication $marketplaceSyndication and usage reporting $reportUsage. You can change this by running the script using different flags. Press Enter to continue."
|
||||
Import-Module C:\CloudDeployment\ECEngine\EnterpriseCloudEngine.psd1 -Force
|
||||
Set-Location C:\CloudDeployment\Setup\Activation\Bridge
|
||||
|
||||
# Determine version of TP3 and set values accordingly
|
||||
$versionInfo = [xml] (Get-Content -Path C:\CloudDeployment\Configuration\Version\version.xml)
|
||||
if($versionInfo.Version -ge "1.0.170308.2")
|
||||
{
|
||||
Write-Verbose -Message "Using TP3.N release" -Verbose
|
||||
$bridgeAppConfigFile = "\\SU1FileServer\SU1_Infrastructure_1\ASResourceProvider\Config\AzureBridge.IdentityApplication.Configuration.json"
|
||||
}
|
||||
elseif($versionInfo.Version -eq "1.0.170225.2")
|
||||
{
|
||||
Write-Verbose -Message "Using TP3.O release" -Verbose
|
||||
$bridgeAppConfigFile = "\\SU1FileServer\SU1_Infrastructure_1\ASResourceProvider\Config\ConnectionAzureArm.IdentityApplication.Configuration.json"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Error -Message "Unsupported TP3 release" -Verbose
|
||||
}
|
||||
#
|
||||
# Pre-req: Version check
|
||||
#
|
||||
|
||||
$versionInfo = [xml] (Get-Content -Path C:\CloudDeployment\Configuration\Version\version.xml)
|
||||
$minVersion = "1.0.170501.1"
|
||||
if ($versionInfo.Version -lt $minVersion) {
|
||||
Write-Error -Message "Script only applicable for Azure Stack builds $minVersion or later"
|
||||
}
|
||||
else {
|
||||
Write-Verbose -Message "Running registration on build $($versionInfo.Version)" -Verbose
|
||||
}
|
||||
|
||||
#
|
||||
# Obtain refresh token for Azure identity
|
||||
#
|
||||
|
||||
Import-Module C:\CloudDeployment\Setup\Common\AzureADConfiguration.psm1 -ErrorAction Stop
|
||||
$AzureDirectoryTenantId = Get-TenantIdFromName -azureEnvironment $azureEnvironment -tenantName $azureDirectoryTenantName
|
||||
|
||||
if (-not $azureCredential) {
|
||||
Write-Verbose "Prompt user to enter Azure Credentials to get refresh token"
|
||||
$tenantDetails = Get-AzureADTenantDetails -AzureEnvironment $azureEnvironment -AADDirectoryTenantName $azureDirectoryTenantName
|
||||
}
|
||||
else {
|
||||
Write-Verbose "Using provided Azure Credentials to get refresh token"
|
||||
$tenantDetails = Get-AzureADTenantDetails -AzureEnvironment $azureEnvironment -AADDirectoryTenantName $azureDirectoryTenantName -AADAdminCredential $azureCredential
|
||||
}
|
||||
|
||||
$refreshToken = (ConvertTo-SecureString -string $tenantDetails["RefreshToken"] -AsPlainText -Force)
|
||||
|
||||
#
|
||||
# Step 1: Configure Bridge identity
|
||||
#
|
||||
|
||||
$azureCreds = New-Object System.Management.Automation.PSCredential($azureSubscriptionOwner, $azureSubscriptionPassword)
|
||||
.\Configure-BridgeIdentity.ps1 -AzureCredential $azureCreds -AzureDirectoryTenantId $azureDirectory -AzureEnvironment AzureCloud -Verbose
|
||||
Write-Host "STEP 1: Configure local identity completed"
|
||||
Write-Verbose "Calling Configure-BridgeIdentity.ps1"
|
||||
.\Configure-BridgeIdentity.ps1 -RefreshToken $refreshToken -AzureAccountId $azureAccountId -AzureDirectoryTenantName $azureDirectoryTenantName -AzureEnvironment $azureEnvironment -Verbose
|
||||
Write-Verbose "Configure Bridge identity completed"
|
||||
|
||||
#
|
||||
# Step 2: Create new registration request
|
||||
#
|
||||
|
||||
$bridgeAppConfigFile = "\\SU1FileServer\SU1_Infrastructure_1\ASResourceProvider\Config\AzureBridge.IdentityApplication.Configuration.json"
|
||||
$registrationOutputFile = "c:\temp\registration.json"
|
||||
|
||||
Write-Verbose "Calling New-RegistrationRequest.ps1"
|
||||
.\New-RegistrationRequest.ps1 -BridgeAppConfigFile $bridgeAppConfigFile -RegistrationRequestOutputFile $registrationOutputFile -Verbose
|
||||
Read-Host "STEP 2: Registration request completed. Re-enter your Azure subscription credentials in the next step. Note: Step 3 can be run from a different machine that is connected to Azure. Press Enter to continue and run step 3 from this machine."
|
||||
Write-Verbose "New registration request completed"
|
||||
|
||||
#
|
||||
# Step 3: Register Azure Stack with Azure
|
||||
#
|
||||
|
||||
New-Item -ItemType Directory -Force -Path "C:\temp"
|
||||
$registrationRequestFile = "c:\temp\registration.json"
|
||||
$registrationOutputFile = "c:\temp\registrationOutput.json"
|
||||
|
||||
Login-AzureRmAccount -EnvironmentName AzureCloud
|
||||
Select-AzureRmSubscription -SubscriptionId $azureSubscriptionId
|
||||
$timestamp = [DateTime]::Now.ToString("yyyyMMdd-HHmmss")
|
||||
$logPath = (New-Item -Path "$env:SystemDrive\CloudDeployment\Logs\" -ItemType Directory -Force).FullName
|
||||
$logFile = Join-Path -Path $logPath -ChildPath "Register-AzureStack.${timestamp}.txt"
|
||||
try { Start-Transcript -Path $logFile -Force | Out-String | Write-Verbose -Verbose } catch { Write-Warning -Message $_.Exception.Message }
|
||||
|
||||
# Ensure subscription is registered to Microsoft.AzureStack namespace in Azure
|
||||
Register-AzureRmResourceProvider -ProviderNamespace 'microsoft.azurestack'
|
||||
$result = $null
|
||||
$attempts = 0
|
||||
$maxAttempts = 20
|
||||
$delayInSecondsBetweenAttempts = 10
|
||||
do
|
||||
{
|
||||
$attempts++
|
||||
Write-Verbose "[CHECK] Checking for resource provider registration... (attempt $attempts of $maxAttempts)"
|
||||
$result = $(Get-AzureRmResourceProvider -ProviderNamespace 'microsoft.azurestack')[0].RegistrationState -EQ 'Registered'
|
||||
$result
|
||||
if ((-not $result) -and ($attempts -lt $maxAttempts))
|
||||
{
|
||||
Write-Verbose "[DELAY] Attempt $attempts failed to see provider registration, delaying for $delayInSecondsBetweenAttempts seconds before retry"
|
||||
Start-Sleep -Seconds $delayInSecondsBetweenAttempts
|
||||
}
|
||||
}
|
||||
while ((-not $result) -and ($attempts -lt $maxAttempts))
|
||||
Write-Verbose "Calling Register-AzureStack.ps1"
|
||||
.\Register-AzureStack.ps1 -BillingModel PayAsYouUse -EnableSyndication -ReportUsage -SubscriptionId $azureSubscriptionId -AzureAdTenantId $AzureDirectoryTenantId `
|
||||
-RefreshToken $refreshToken -AzureAccountId $azureAccountId -AzureEnvironmentName $azureEnvironment -RegistrationRequestFile $registrationRequestFile `
|
||||
-RegistrationOutputFile $registrationOutputFile -Location "westcentralus" -Verbose
|
||||
Write-Verbose "Register Azure Stack with Azure completed"
|
||||
|
||||
if (-not $result)
|
||||
{
|
||||
throw New-Object System.InvalidOperationException("Azure Bridge Resource Provider was registered but did not become routable within the alloted time")
|
||||
try { Stop-Transcript -Verbose } catch { Write-Warning "$_" }
|
||||
|
||||
#
|
||||
# workaround to enable syndication and usage
|
||||
#
|
||||
|
||||
$activationDataFile = "c:\temp\regOutput2.json"
|
||||
$reg = Get-Content $registrationOutputFile | ConvertFrom-Json
|
||||
|
||||
$newProps = @{
|
||||
ObjectId = $reg.properties.ObjectId
|
||||
ProvisioningState = $reg.properties.provisioningState
|
||||
enablesyndication = $enableSyndication
|
||||
reportusage = $reportUsage
|
||||
}
|
||||
|
||||
.\Register-AzureStack.ps1 -BillingModel Consumption -Syndication $marketplaceSyndication -ReportUsage $reportUsage -SubscriptionId $azureSubscriptionId -AzureAdTenantId $azureDirectory `
|
||||
-AzureCredential $azureCreds -AzureEnvironmentName AzureCloud -RegistrationRequestFile $registrationRequestFile -RegistrationOutputFile $registrationOutputFile -Location "westcentralus" -Verbose
|
||||
Read-Host "STEP 3: Register Azure Stack with Azure completed. Press Enter to continue."
|
||||
$reg.properties = $newProps
|
||||
$reg | ConvertTo-Json -Depth 4 | Out-File -FilePath $activationDataFile
|
||||
|
||||
Write-Verbose "Activation file is at : $activationDataFile"
|
||||
|
||||
#
|
||||
# Step 4: Activate Azure Stack
|
||||
#
|
||||
$regResponse = Get-Content -path $activationDataFile
|
||||
$bytes = [System.Text.Encoding]::UTF8.GetBytes($regResponse)
|
||||
$activationCode = [Convert]::ToBase64String($bytes)
|
||||
|
||||
# temporary step to adjust registration output to expected format
|
||||
$reg = Get-Content $registrationOutputFile | ConvertFrom-Json
|
||||
$newProps = @{
|
||||
ObjectId = $reg.properties.ObjectId
|
||||
ProvisioningState = $reg.properties.provisioningState
|
||||
syndication = $marketplaceSyndication
|
||||
usagebridge = $reportUsage
|
||||
try {
|
||||
.\Activate-Bridge.ps1 -activationCode $activationCode -AzureResourceManagerEndpoint $azureResourceManagerEndpoint -Verbose
|
||||
}
|
||||
$reg.properties = $newProps
|
||||
$reg | ConvertTo-Json -Depth 4 | Out-File -FilePath $registrationOutputFile
|
||||
catch {
|
||||
$exceptionMessage = $_.Exception.Message
|
||||
|
||||
$regResponse = Get-Content -path $registrationOutputFile
|
||||
$AzureResourceManagerEndpoint = "https://management.azure.com"
|
||||
|
||||
if($versionInfo.Version -ge "1.0.170308.2")
|
||||
{
|
||||
$bytes = [System.Text.Encoding]::UTF8.GetBytes($regResponse)
|
||||
$activationCode = [Convert]::ToBase64String($bytes)
|
||||
.\Activate-Bridge.ps1 -activationCode $activationCode -AzureResourceManagerEndpoint $AzureResourceManagerEndpoint -Verbose
|
||||
if($exceptionMessage.Contains("Application is currently being upgraded"))
|
||||
{
|
||||
Write-Warning "Activate-Bridge: Known issue with redundant service fabric upgrade call"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Error -Message "Activate-Bridge: Error : $($_.Exception)"
|
||||
}
|
||||
}
|
||||
elseif($versionInfo.Version -eq "1.0.170225.2")
|
||||
{
|
||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($regResponse)
|
||||
$activationCode = [Convert]::ToBase64String($bytes)
|
||||
.\Activate-Bridge.ps1 -activationCode $activationCode -Verbose
|
||||
}
|
||||
|
||||
Write-Host "STEP 4: Activate Azure Stack completed"
|
||||
Write-Host "Registration complete. Close and re-open the Marketplace Management blade in the admin portal."
|
||||
Write-Verbose "Azure Stack activation completed"
|
||||
|
|
|
@ -2,239 +2,159 @@
|
|||
# See LICENSE.txt in the project root for license information.
|
||||
|
||||
#requires -Version 4.0
|
||||
#requires -Modules AzureStack.Connect
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Creates "default" tenant offer with unlimited quotas across Compute, Network, Storage and KeyVault services.
|
||||
#>
|
||||
function New-AzSTenantOfferAndQuotas
|
||||
{
|
||||
param (
|
||||
[parameter(HelpMessage="Name of the offer to be made advailable to tenants")]
|
||||
[string] $Name ="default",
|
||||
[parameter(HelpMessage="Azure Stack region in which to define plans and quotas")]
|
||||
[string]$Location = "local",
|
||||
[Parameter(HelpMessage="If this parameter is not specified all quotas are assigned. Provide a sub selection of quotas in this parameter if you do not want all quotas assigned.")]
|
||||
[ValidateSet('Compute','Network','Storage','KeyVault','Subscriptions',IgnoreCase =$true)]
|
||||
[array]$ServiceQuotas,
|
||||
[parameter(Mandatory=$true,HelpMessage="The name of the AzureStack environment")]
|
||||
[string] $EnvironmentName,
|
||||
[parameter(Mandatory=$true,HelpMessage="Azure Stack service administrator credential")]
|
||||
[pscredential] $azureStackCredentials,
|
||||
[parameter(mandatory=$true, HelpMessage="TenantID of Identity Tenant")]
|
||||
[string] $tenantID
|
||||
)
|
||||
|
||||
$azureStackEnvironment = Get-AzureRmEnvironment -Name $EnvironmentName -ErrorAction SilentlyContinue
|
||||
if($azureStackEnvironment -ne $null) {
|
||||
$ARMEndpoint = $azureStackEnvironment.ResourceManagerUrl
|
||||
}
|
||||
else {
|
||||
Write-Error "The Azure Stack Admin environment with the name $EnvironmentName does not exist. Create one with Add-AzureStackAzureRmEnvironment." -ErrorAction Stop
|
||||
}
|
||||
|
||||
Write-Verbose "Obtaining token from AAD..." -Verbose
|
||||
$subscription, $headers = (Get-AzureStackAdminSubTokenHeader -TenantId $tenantId -AzureStackCredentials $azureStackCredentials -EnvironmentName $EnvironmentName)
|
||||
|
||||
Write-Verbose "Creating quotas..." -Verbose
|
||||
$Quotas = @()
|
||||
if ((!($ServiceQuotas)) -or ($ServiceQuotas -match 'Compute')){ $Quotas += New-ComputeQuota -AdminUri $armEndPoint -SubscriptionId $subscription -AzureStackTokenHeader $headers -ArmLocation $Location }
|
||||
if ((!($ServiceQuotas)) -or ($ServiceQuotas -match 'Network')){ $Quotas += New-NetworkQuota -AdminUri $armEndPoint -SubscriptionId $subscription -AzureStackTokenHeader $headers -ArmLocation $Location }
|
||||
if ((!($ServiceQuotas)) -or ($ServiceQuotas -match 'Storage')){ $Quotas += New-StorageQuota -AdminUri $armEndPoint -SubscriptionId $subscription -AzureStackTokenHeader $headers -ArmLocation $Location }
|
||||
if ((!($ServiceQuotas)) -or ($ServiceQuotas -match 'KeyVault')){ $Quotas += Get-KeyVaultQuota -AdminUri $armEndPoint -SubscriptionId $subscription -AzureStackTokenHeader $headers -ArmLocation $Location }
|
||||
if ((!($ServiceQuotas)) -or ($ServiceQuotas -match 'Subscriptions')){ $Quotas += Get-SubscriptionsQuota -AdminUri $armEndpoint -SubscriptionId $subscription -AzureStackTokenHeader $headers -ArmLocation $Location }
|
||||
|
||||
Write-Verbose "Creating resource group for plans and offers..." -Verbose
|
||||
if (Get-AzureRmResourceGroup -Name $Name -ErrorAction SilentlyContinue)
|
||||
{
|
||||
Remove-AzureRmResourceGroup -Name $Name -Force -ErrorAction Stop
|
||||
}
|
||||
New-AzureRmResourceGroup -Name $Name -Location $Location -ErrorAction Stop
|
||||
|
||||
Write-Verbose "Creating plan..." -Verbose
|
||||
$plan = New-AzureRMPlan -Name $Name -DisplayName $Name -ArmLocation $Location -ResourceGroup $Name -QuotaIds $Quotas
|
||||
|
||||
Write-Verbose "Creating public offer..." -Verbose
|
||||
$offer = New-AzureRMOffer -Name $Name -DisplayName $Name -State Public -BasePlanIds @($plan.Id) -ArmLocation $Location -ResourceGroup $Name
|
||||
|
||||
return $offer
|
||||
}
|
||||
|
||||
Export-ModuleMember New-AzSTenantOfferAndQuotas
|
||||
|
||||
function Get-SubscriptionsQuota
|
||||
{
|
||||
function Add-AzsStorageQuota {
|
||||
param(
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $AdminUri,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $SubscriptionId,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[hashtable] $AzureStackTokenHeader,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $ArmLocation
|
||||
)
|
||||
|
||||
$getSubscriptionsQuota = @{
|
||||
Uri = "{0}/subscriptions/{1}/providers/Microsoft.Subscriptions.Admin/locations/{2}/quotas?api-version=2015-11-01" -f $AdminUri, $SubscriptionId, $ArmLocation
|
||||
Method = "GET"
|
||||
Headers = $AzureStackTokenHeader
|
||||
ContentType = "application/json"
|
||||
}
|
||||
$subscriptionsQuota = Invoke-RestMethod @getSubscriptionsQuota
|
||||
$subscriptionsQuota.value.Id
|
||||
}
|
||||
|
||||
function New-StorageQuota
|
||||
{
|
||||
param(
|
||||
[string] $Name ="default",
|
||||
[string] $Name = "default",
|
||||
[int] $CapacityInGb = 1000,
|
||||
[int] $NumberOfStorageAccounts = 2000,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $AdminUri,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $SubscriptionId,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[hashtable] $AzureStackTokenHeader,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $ArmLocation
|
||||
)
|
||||
[string] $Location = $null
|
||||
)
|
||||
|
||||
$Location = Get-AzsHomeLocation -Location $Location
|
||||
|
||||
$ApiVersion = "2015-12-01-preview"
|
||||
|
||||
$uri = "{0}/subscriptions/{1}/providers/Microsoft.Storage.Admin/locations/{2}/quotas/{3}?api-version={4}" -f $AdminUri, $SubscriptionId, $ArmLocation, $Name, $ApiVersion
|
||||
$RequestBody = @"
|
||||
{
|
||||
"name":"$Name",
|
||||
"location":"$ArmLocation",
|
||||
"properties": {
|
||||
"capacityInGb": $CapacityInGb,
|
||||
"numberOfStorageAccounts": $NumberOfStorageAccounts
|
||||
$params = @{
|
||||
ResourceName = "{0}/{1}" -f $Location, $Name
|
||||
ResourceType = "Microsoft.Storage.Admin/locations/quotas"
|
||||
ApiVersion = "2015-12-01-preview"
|
||||
Properties = @{
|
||||
capacityInGb = $CapacityInGb
|
||||
numberOfStorageAccounts = $NumberOfStorageAccounts
|
||||
}
|
||||
}
|
||||
"@
|
||||
$storageQuota = Invoke-RestMethod -Method Put -Uri $uri -Body $RequestBody -ContentType 'application/json' -Headers $AzureStackTokenHeader
|
||||
$storageQuota.Id
|
||||
|
||||
New-AzsServiceQuota @params
|
||||
}
|
||||
|
||||
function New-ComputeQuota
|
||||
{
|
||||
function Add-AzsComputeQuota {
|
||||
param(
|
||||
[string] $Name ="default",
|
||||
[string] $Name = "default",
|
||||
[int] $VmCount = 1000,
|
||||
[int] $MemoryLimitMB = 1048576,
|
||||
[int] $CoresLimit = 1000,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $AdminUri,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $SubscriptionId,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[hashtable] $AzureStackTokenHeader,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $ArmLocation
|
||||
)
|
||||
[string] $Location = $null
|
||||
)
|
||||
|
||||
$ApiVersion = "2015-12-01-preview"
|
||||
|
||||
$uri = "{0}/subscriptions/{1}/providers/Microsoft.Compute.Admin/locations/{2}/quotas/{3}?api-version={4}" -f $AdminUri, $SubscriptionId, $ArmLocation, $Name, $ApiVersion
|
||||
$RequestBody = @"
|
||||
{
|
||||
"name":"$Name",
|
||||
"type":"Microsoft.Compute.Admin/quotas",
|
||||
"location":"$ArmLocation",
|
||||
"properties":{
|
||||
"virtualMachineCount":$VmCount,
|
||||
"memoryLimitMB":$MemoryLimitMB,
|
||||
"coresLimit":$CoresLimit
|
||||
$Location = Get-AzsHomeLocation -Location $Location
|
||||
|
||||
$params = @{
|
||||
ResourceName = "{0}/{1}" -f $Location, $Name
|
||||
ResourceType = "Microsoft.Compute.Admin/locations/quotas"
|
||||
ApiVersion = "2015-12-01-preview"
|
||||
Properties = @{
|
||||
virtualMachineCount = $VmCount
|
||||
memoryLimitMB = $MemoryLimitMB
|
||||
coresLimit = $CoresLimit
|
||||
}
|
||||
}
|
||||
"@
|
||||
$computeQuota = Invoke-RestMethod -Method Put -Uri $uri -Body $RequestBody -ContentType 'application/json' -Headers $AzureStackTokenHeader
|
||||
$computeQuota.Id
|
||||
|
||||
New-AzsServiceQuota @params
|
||||
}
|
||||
|
||||
function New-NetworkQuota
|
||||
{
|
||||
|
||||
function Add-AzsNetworkQuota {
|
||||
param(
|
||||
[string] $Name ="default",
|
||||
[int] $PublicIpsPerSubscription = 500,
|
||||
[int] $VNetsPerSubscription = 500,
|
||||
[int] $GatewaysPerSubscription = 10,
|
||||
[int] $ConnectionsPerSubscription = 20,
|
||||
[int] $LoadBalancersPerSubscription = 500,
|
||||
[int] $NicsPerSubscription = 1000,
|
||||
[int] $SecurityGroupsPerSubscription = 500,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $AdminUri,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $SubscriptionId,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[hashtable] $AzureStackTokenHeader,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $ArmLocation
|
||||
[string] $Name = "default",
|
||||
[int] $PublicIpsPerSubscription = 500,
|
||||
[int] $VNetsPerSubscription = 500,
|
||||
[int] $GatewaysPerSubscription = 10,
|
||||
[int] $ConnectionsPerSubscription = 20,
|
||||
[int] $LoadBalancersPerSubscription = 500,
|
||||
[int] $NicsPerSubscription = 1000,
|
||||
[int] $SecurityGroupsPerSubscription = 500,
|
||||
[string] $Location = $null
|
||||
)
|
||||
|
||||
$ApiVersion = "2015-06-15"
|
||||
|
||||
$uri = "{0}/subscriptions/{1}/providers/Microsoft.Network.Admin/locations/{2}/quotas/{3}?api-version={4}" -f $AdminUri, $SubscriptionId, $ArmLocation, $Name, $ApiVersion
|
||||
$id = "/subscriptions/{0}/providers/Microsoft.Network.Admin/locations/{1}/quotas/{2}" -f $SubscriptionId, $ArmLocation, $quotaName
|
||||
$RequestBody = @"
|
||||
{
|
||||
"id":"$id",
|
||||
"name":"$Name",
|
||||
"type":"Microsoft.Network.Admin/quotas",
|
||||
"location":"$ArmLocation",
|
||||
"properties":{
|
||||
"maxPublicIpsPerSubscription":$PublicIpsPerSubscription,
|
||||
"maxVnetsPerSubscription":$VNetsPerSubscription,
|
||||
"maxVirtualNetworkGatewaysPerSubscription":$GatewaysPerSubscription,
|
||||
"maxVirtualNetworkGatewayConnectionsPerSubscription":$ConnectionsPerSubscription,
|
||||
"maxLoadBalancersPerSubscription":$LoadBalancersPerSubscription,
|
||||
"maxNicsPerSubscription":$NicsPerSubscription,
|
||||
"maxSecurityGroupsPerSubscription":$SecurityGroupsPerSubscription,
|
||||
$Location = Get-AzsHomeLocation -Location $Location
|
||||
|
||||
$params = @{
|
||||
ResourceName = "{0}/{1}" -f $Location, $Name
|
||||
ResourceType = "Microsoft.Network.Admin/locations/quotas"
|
||||
ApiVersion = "2015-06-15"
|
||||
Properties = @{
|
||||
maxPublicIpsPerSubscription = $PublicIpsPerSubscription
|
||||
maxVnetsPerSubscription = $VNetsPerSubscription
|
||||
maxVirtualNetworkGatewaysPerSubscription = $GatewaysPerSubscription
|
||||
maxVirtualNetworkGatewayConnectionsPerSubscription = $ConnectionsPerSubscription
|
||||
maxLoadBalancersPerSubscription = $LoadBalancersPerSubscription
|
||||
maxNicsPerSubscription = $NicsPerSubscription
|
||||
maxSecurityGroupsPerSubscription = $SecurityGroupsPerSubscription
|
||||
}
|
||||
}
|
||||
"@
|
||||
$networkQuota = Invoke-RestMethod -Method Put -Uri $uri -Body $RequestBody -ContentType 'application/json' -Headers $AzureStackTokenHeader
|
||||
$networkQuota.Id
|
||||
|
||||
New-AzsServiceQuota @params
|
||||
}
|
||||
|
||||
function Get-KeyVaultQuota
|
||||
{
|
||||
|
||||
function Get-AzsSubscriptionsQuota {
|
||||
param(
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $AdminUri,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $SubscriptionId,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[hashtable] $AzureStackTokenHeader,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string] $ArmLocation
|
||||
)
|
||||
[string] $Location
|
||||
)
|
||||
|
||||
$uri = "{0}/subscriptions/{1}/providers/Microsoft.Keyvault.Admin/locations/{2}/quotas?api-version=2014-04-01-preview" -f $AdminUri, $SubscriptionId, $ArmLocation
|
||||
$kvQuota = Invoke-RestMethod -Method Get -Uri $uri -Headers $AzureStackTokenHeader -ContentType 'application/json'
|
||||
$kvQuota.Value.Id
|
||||
$Location = Get-AzsHomeLocation -Location $Location
|
||||
|
||||
$params = @{
|
||||
ResourceName = $Location
|
||||
ResourceType = "Microsoft.Subscriptions.Admin/locations/quotas"
|
||||
ApiVersion = "2015-11-01"
|
||||
}
|
||||
|
||||
Get-AzsServiceQuota @params
|
||||
}
|
||||
|
||||
function Get-AzsKeyVaultQuota {
|
||||
param(
|
||||
[string] $Location
|
||||
)
|
||||
|
||||
$Location = Get-AzsHomeLocation -Location $Location
|
||||
|
||||
$params = @{
|
||||
ResourceName = $Location
|
||||
ResourceType = "Microsoft.Keyvault.Admin/locations/quotas"
|
||||
ApiVersion = "2014-04-01-preview"
|
||||
}
|
||||
|
||||
Get-AzsServiceQuota @params
|
||||
}
|
||||
|
||||
function Get-AzsHomeLocation {
|
||||
param(
|
||||
[string] $Location
|
||||
)
|
||||
|
||||
if ($Location) {
|
||||
return $Location
|
||||
}
|
||||
|
||||
$locationResource = Get-AzsLocation
|
||||
return $locationResource.Name
|
||||
}
|
||||
|
||||
|
||||
function New-AzsServiceQuota {
|
||||
param(
|
||||
[string] $ResourceName,
|
||||
[string] $ResourceType,
|
||||
[string] $ApiVersion,
|
||||
[PSObject] $Properties
|
||||
)
|
||||
|
||||
$serviceQuota = New-AzureRmResource -ResourceName $ResourceName -ResourceType $ResourceType -ApiVersion $ApiVersion -Properties $Properties -Force
|
||||
$serviceQuota.ResourceId
|
||||
}
|
||||
|
||||
function Get-AzsServiceQuota {
|
||||
param(
|
||||
[string] $ResourceName,
|
||||
[string] $ResourceType,
|
||||
[string] $ApiVersion
|
||||
)
|
||||
|
||||
$serviceQuota = Get-AzureRmResource -ResourceName $ResourceName -ApiVersion $ApiVersion -ResourceType $ResourceType
|
||||
$serviceQuota.ResourceId
|
||||
}
|
||||
|
|
|
@ -9,35 +9,25 @@ Install-Module -Name 'AzureRm.Bootstrapper' -Scope CurrentUser
|
|||
Install-AzureRmProfile -profile '2017-03-09-profile' -Force -Scope CurrentUser
|
||||
Install-Module -Name AzureStack -RequiredVersion 1.2.9 -Scope CurrentUser
|
||||
```
|
||||
|
||||
Then make sure the following modules are imported:
|
||||
|
||||
```powershell
|
||||
Import-Module ..\Connect\AzureStack.Connect.psm1
|
||||
Import-Module .\AzureStack.ServiceAdmin.psm1
|
||||
```
|
||||
|
||||
You will need to reference your Azure Stack Administrator environment. To create an administrator environment use the below. The ARM endpoint below is the administrator default for a one-node environment.
|
||||
|
||||
```powershell
|
||||
Add-AzureStackAzureRmEnvironment -Name "AzureStackAdmin" -ArmEndpoint "https://adminmanagement.local.azurestack.external"
|
||||
Add-AzsEnvironment -Name "AzureStackAdmin" -ArmEndpoint "https://adminmanagement.local.azurestack.external"
|
||||
```
|
||||
|
||||
Creating quotas/offers/plans requires that you obtain the value of your Directory Tenant ID. For **Azure Active Directory** environments provide your directory tenant name:
|
||||
|
||||
```powershell
|
||||
$TenantID = Get-DirectoryTenantID -AADTenantName "<mydirectorytenant>.onmicrosoft.com" -EnvironmentName AzureStackAdmin
|
||||
```
|
||||
|
||||
For **ADFS** environments use the following:
|
||||
|
||||
```powershell
|
||||
$TenantID = Get-DirectoryTenantID -ADFS -EnvironmentName AzureStackAdmin
|
||||
```
|
||||
|
||||
## Create default plan and quota for tenants
|
||||
|
||||
```powershell
|
||||
New-AzSTenantOfferAndQuotas -tenantID $TenantID -EnvironmentName "AzureStackAdmin"
|
||||
Add-AzsTenantOfferAndQuota
|
||||
```
|
||||
|
||||
Tenants can now see the "default" offer available to them and can subscribe to it. The offer includes unlimited compute, network, storage and key vault usage.
|
||||
|
||||
Tenants can now see the "default" offer available to them and can subscribe to it. The offer includes unlimited compute, network, storage and key vault usage.
|
||||
|
|
|
@ -10,38 +10,12 @@ Describe $script:ModuleName {
|
|||
Get-Module -Name $script:ModuleName |
|
||||
Should Not Be $null
|
||||
}
|
||||
|
||||
It 'New-AzSTenantOfferAndQuotas should be exported' {
|
||||
Get-Command -Name New-AzSTenantOfferAndQuotas -ErrorAction SilentlyContinue |
|
||||
Should Not Be $null
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
InModuleScope $script:ModuleName {
|
||||
|
||||
$HostComputer = $global:HostComputer
|
||||
$ArmEndpoint = $global:ArmEndpoint
|
||||
$natServer = $global:natServer
|
||||
$AdminUser= $global:AdminUser
|
||||
$AadServiceAdmin = $global:AadServiceAdmin
|
||||
|
||||
$AdminPassword = $global:AdminPassword
|
||||
$AadServiceAdminPassword = $global:AadServiceAdminPassword
|
||||
$stackLoginCreds = $global:AzureStackLoginCredentials
|
||||
|
||||
$VPNConnectionName = $global:VPNConnectionName
|
||||
|
||||
$AadTenant = $global:AadTenantID
|
||||
|
||||
$EnvironmentName = $global:EnvironmentName
|
||||
|
||||
Describe 'ServiceAdmin - Functional Tests' {
|
||||
It 'New-AzSTenantOfferAndQuotas should create Quotas, Plan and Offer' {
|
||||
{ New-AzSTenantOfferAndQuotas -tenantID $AadTenant -AzureStackCredentials $stackLoginCreds -EnvironmentName $EnvironmentName } |
|
||||
Should Not Throw
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,37 @@
|
|||
# Validate Azure ARM Template Capabilities
|
||||
|
||||
Instructions below are relative to the .\TemplateValidator folder of the [AzureStack-Tools repo](..).
|
||||
To Validate Compute Capabilities such as Images, Extensions & Sizes available in the CloudCapabilities.json add -IncludeComputeCapabilities
|
||||
To Validate Storage Capabilities such as Skus available in the CloudCapabilities.json add -IncludeStorageCapabilities
|
||||
|
||||
```powershell
|
||||
Import-Module ".\AzureRM.TemplateValidator.psm1"
|
||||
```
|
||||
# Prerequisites
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Create CloudCapabilities.json by using Get-AzureRMCloudCapabilities tool [AzureStack-Tools repo/CloudCapabilities](../CloudCapabilities). or use the provided sample AzureStackCapabilities_TP3.json in this folder
|
||||
For Azure/AzureStack quickstart templates, git clone from below links
|
||||
https://github.com/Azure/AzureStack-QuickStart-Templates/
|
||||
https://github.com/Azure/Azure-QuickStart-Templates/
|
||||
# Usage
|
||||
`https://github.com/Azure/AzureStack-QuickStart-Templates/`
|
||||
`https://github.com/Azure/Azure-QuickStart-Templates/`
|
||||
|
||||
## Usage
|
||||
|
||||
```powershell
|
||||
$TemplatePath = "<Provide Template(s) Path>"
|
||||
$CapabilitiesPath = ".\AzureStackCapabilities_TP3.json"
|
||||
Test-AzureRMTemplate -TemplatePath $TemplatePath -CapabilitiesPath $CapabilitiesPath -Verbose #-IncludeComputeCapabilities -IncludeStorageCapabilities
|
||||
```
|
||||
#Reporting Usage
|
||||
Passed - Validation passed. The template has all the Capabilities to deploy on the validated Cloud
|
||||
|
||||
## Reporting Usage
|
||||
|
||||
Passed - Validation passed. The template has all the Capabilities to deploy on the validated Cloud
|
||||
NotSupported - The template Capabilities is currently not supported on the validated cloud
|
||||
Exception - Exception in processing and validating the template
|
||||
Recommend - The template has all the Capabilities to deploy on the validated Cloud but has recommendations for best practices
|
||||
Warning - Changes are required either in Template or the validated cloud to deploy succesfully
|
||||
|
||||
# TroubleShooting
|
||||
## TroubleShooting
|
||||
|
||||
For "NotSupported" - Refer the region specific capability JSON for the supported capabilities.
|
||||
For Warnings(in Console Output) such as "No StorageSkus found in region specific Capabilities JSON file.", Please run Get-AzureRMCloudCapabilities with -IncludeComputeCapabilities and -IncludeStorageCapabilities
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
param (
|
||||
[parameter(mandatory=$true, HelpMessage="Azure Stack One Node host address or name such as '1.2.3.4'")]
|
||||
[parameter(mandatory = $true, HelpMessage = "Azure Stack One Node host address or name such as '1.2.3.4'")]
|
||||
[string] $HostComputer,
|
||||
[Parameter(mandatory=$true, HelpMessage="The Admin ARM endpoint of the Azure Stack Environment")]
|
||||
[Parameter(mandatory = $true, HelpMessage = "The Admin ARM endpoint of the Azure Stack Environment")]
|
||||
[string] $ArmEndpoint,
|
||||
[parameter(HelpMessage="NAT computer name in this Azure Stack Instance")]
|
||||
[string] $natServer = "MAS-BGPNAT01",
|
||||
[parameter(HelpMessage="Administrator user name of this Azure Stack Instance")]
|
||||
[parameter(HelpMessage = "NAT computer name in this Azure Stack Instance")]
|
||||
[string] $natServer = "Azs-BGPNAT01",
|
||||
[parameter(HelpMessage = "Administrator user name of this Azure Stack Instance")]
|
||||
[string] $AdminUser = "administrator",
|
||||
[parameter(HelpMessage="Administrator Azure Stack Environment Name")]
|
||||
[parameter(HelpMessage = "Administrator Azure Stack Environment Name")]
|
||||
[string] $EnvironmentName = "AzureStackAdmin",
|
||||
[parameter(mandatory=$true, HelpMessage="Administrator password used to deploy this Azure Stack instance")]
|
||||
[parameter(mandatory = $true, HelpMessage = "Administrator password used to deploy this Azure Stack instance")]
|
||||
[securestring] $AdminPassword,
|
||||
[parameter(mandatory=$true, HelpMessage="The AAD service admin user name of this Azure Stack Instance")]
|
||||
[parameter(mandatory = $true, HelpMessage = "The AAD service admin user name of this Azure Stack Instance")]
|
||||
[string] $AzureStackServiceAdmin,
|
||||
[parameter(mandatory=$true, HelpMessage="AAD Service Admin password used to deploy this Azure Stack instance")]
|
||||
[parameter(mandatory = $true, HelpMessage = "AAD Service Admin password used to deploy this Azure Stack instance")]
|
||||
[securestring] $AzureStackServiceAdminPassword
|
||||
)
|
||||
|
||||
|
@ -27,7 +27,7 @@ $global:AzureStackServiceAdmin = $AzureStackServiceAdmin
|
|||
$global:AzureStackServiceAdminPassword = $AzureStackServiceAdminPassword
|
||||
$global:EnvironmentName = $EnvironmentName
|
||||
|
||||
$ServiceAdminCreds = New-Object System.Management.Automation.PSCredential "$global:AzureStackServiceAdmin", ($global:AzureStackServiceAdminPassword)
|
||||
$ServiceAdminCreds = New-Object System.Management.Automation.PSCredential "$global:AzureStackServiceAdmin", ($global:AzureStackServiceAdminPassword)
|
||||
$global:AzureStackLoginCredentials = $ServiceAdminCreds
|
||||
|
||||
$global:VPNConnectionName = "AzureStackTestVPN"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# PreReqs
|
||||
|
||||
As a prerequisite, make sure that you installed the correct PowerShell modules and versions:
|
||||
|
||||
```powershell
|
||||
|
@ -5,7 +7,6 @@ Install-Module -Name 'AzureRm.Bootstrapper' -Scope CurrentUser
|
|||
Install-AzureRmProfile -profile '2017-03-09-profile' -Force -Scope CurrentUser
|
||||
Install-Module -Name AzureStack -RequiredVersion 1.2.9 -Scope CurrentUser
|
||||
```
|
||||
```
|
||||
|
||||
Use this script to extract usage data from the AzureStack Usage API's and export it to a CSV file
|
||||
For more information on Billing and Usage see [here](https://docs.microsoft.com/en-us/azure/azure-stack/azure-stack-billing-and-chargeback)
|
||||
```
|
||||
|
|
|
@ -1,26 +1,22 @@
|
|||
<#
|
||||
<#
|
||||
.Synopsis
|
||||
Exports usage meters from Azure Stack to a csv file
|
||||
.DESCRIPTION
|
||||
Long description
|
||||
.EXAMPLE
|
||||
Export-AzureStackUsageDetails -StartTime 2/15/2017 -EndTime 2/16/2017 -AzureStackDomain azurestack.local -AADDomain mydir.onmicrosoft.com -Granularity Hourly
|
||||
Export-AzsUsage -StartTime 2/15/2017 -EndTime 2/16/2017 -Granularity Hourly
|
||||
#>
|
||||
function Export-AzureStackUsage {
|
||||
|
||||
function Export-AzsUsage {
|
||||
Param
|
||||
(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[datetime]
|
||||
$StartTime,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[datetime]
|
||||
$EndTime ,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[String]
|
||||
$AzureStackDomain ,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[String]
|
||||
$AADDomain ,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[ValidateSet("Hourly", "Daily")]
|
||||
[String]
|
||||
|
@ -29,15 +25,9 @@ function Export-AzureStackUsage {
|
|||
[String]
|
||||
$CsvFile = "UsageSummary.csv",
|
||||
[Parameter (Mandatory = $false)]
|
||||
[PSCredential]
|
||||
$Credential,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[Switch]
|
||||
$TenantUsage,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[String]
|
||||
$Subscription,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[Switch]
|
||||
$Force
|
||||
)
|
||||
|
@ -66,115 +56,80 @@ function Export-AzureStackUsage {
|
|||
}
|
||||
|
||||
#Output Files
|
||||
if (Test-Path -Path $CsvFile -ErrorAction SilentlyContinue) {
|
||||
if ($Force) {
|
||||
if (Test-Path -Path $CsvFile -ErrorAction SilentlyContinue)
|
||||
{
|
||||
if ($Force)
|
||||
{
|
||||
Remove-Item -Path $CsvFile -Force
|
||||
}
|
||||
else {
|
||||
Write-Host "$CsvFile alreday exists use -Force to overwrite"
|
||||
Write-Error "'$CsvFile' already exists use -Force to overwrite"
|
||||
return
|
||||
}
|
||||
}
|
||||
New-Item -Path $CsvFile -ItemType File | Out-Null
|
||||
|
||||
#get auth metadata and acquire token for REST call
|
||||
$api = 'adminmanagement'
|
||||
if ($TenantUsage) {
|
||||
$api = 'management'
|
||||
}
|
||||
$uri = 'https://{0}.{1}/metadata/endpoints?api-version=1.0' -f $api, $AzureStackDomain
|
||||
$endpoints = (Invoke-RestMethod -Uri $uri -Method Get)
|
||||
$activeDirectoryServiceEndpointResourceId = $endpoints.authentication.audiences[0]
|
||||
$loginEndpoint = $endpoints.authentication.loginEndpoint
|
||||
$authority = $loginEndpoint + $AADDomain + '/'
|
||||
$powershellClientId = '0a7bdc5c-7b57-40be-9939-d4c5fc7cd417'
|
||||
|
||||
#region Auth
|
||||
if ($Credential) {
|
||||
$adminToken = Get-AzureStackToken `
|
||||
-Authority $authority `
|
||||
-Resource $activeDirectoryServiceEndpointResourceId `
|
||||
-AadTenantId $AADDomain `
|
||||
-ClientId $powershellClientId `
|
||||
-Credential $Credential
|
||||
}
|
||||
else {
|
||||
$adminToken = Get-AzureStackToken `
|
||||
-Authority $authority `
|
||||
-Resource $activeDirectoryServiceEndpointResourceId `
|
||||
-AadTenantId $AADDomain `
|
||||
-ClientId $powershellClientId
|
||||
}
|
||||
|
||||
if (!$adminToken) {
|
||||
Return
|
||||
}
|
||||
#endregion
|
||||
|
||||
#Setup REST call variables
|
||||
$headers = @{ Authorization = (('Bearer {0}' -f $adminToken)) }
|
||||
$armEndpoint = 'https://{0}.{1}' -f $api, $AzureStackDomain
|
||||
|
||||
if (!$Subscription) {
|
||||
#Get default subscription ID
|
||||
$uri = $armEndpoint + '/subscriptions?api-version=2015-01-01'
|
||||
$result = Invoke-RestMethod -Method GET -Uri $uri -Headers $headers
|
||||
$Subscription = $result.value[0].subscriptionId
|
||||
}
|
||||
|
||||
$usageResourceType = "Microsoft.Commerce/locations/subscriberUsageAggregates"
|
||||
|
||||
#build usage uri
|
||||
if (!$TenantUsage) {
|
||||
$uri = $armEndpoint + '/subscriptions/{0}/providers/Microsoft.Commerce/subscriberUsageAggregates?api-version=2015-06-01-preview&reportedstartTime={1:s}Z&reportedEndTime={2:s}Z&showDetails=true&aggregationGranularity={3}' -f $Subscription, $StartTime, $EndTime, $Granularity
|
||||
if ($TenantUsage)
|
||||
{
|
||||
$usageResourceType = "Microsoft.Commerce/locations/UsageAggregates"
|
||||
}
|
||||
else {
|
||||
$uri = $armEndpoint + '/subscriptions/{0}/providers/Microsoft.Commerce/UsageAggregates?api-version=2015-06-01-preview&reportedstartTime={1:s}Z&reportedEndTime={2:s}Z&showDetails=true&aggregationGranularity={3}' -f $Subscription, $StartTime, $EndTime, $Granularity
|
||||
}
|
||||
|
||||
Do {
|
||||
$result = Invoke-RestMethod -Method GET -Uri $uri -Headers $headers -ErrorVariable RestError -Verbose
|
||||
if ($RestError) {
|
||||
return
|
||||
}
|
||||
$usageSummary = @()
|
||||
$uri = $result.NextLink
|
||||
$count = $result.value.Count
|
||||
$Total += $count
|
||||
$result.value | ForEach-Object {
|
||||
$record = New-Object -TypeName System.Object
|
||||
$resourceInfo = ($_.Properties.InstanceData |ConvertFrom-Json).'Microsoft.Resources'
|
||||
$resourceText = $resourceInfo.resourceUri.Replace('\', '/')
|
||||
$subscription = $resourceText.Split('/')[2]
|
||||
$resourceType = $resourceText.Split('/')[7]
|
||||
$resourceName = $resourceText.Split('/')[8]
|
||||
#$record | Add-Member -Name Name -MemberType NoteProperty -Value $_.Name
|
||||
#$record | Add-Member -Name Type -MemberType NoteProperty -Value $_.Type
|
||||
$record | Add-Member -Name MeterId -MemberType NoteProperty -Value $_.Properties.MeterId
|
||||
if ($meters.ContainsKey($_.Properties.MeterId)) {
|
||||
$record | Add-Member -Name MeterName -MemberType NoteProperty -Value $meters[$_.Properties.MeterId]
|
||||
}
|
||||
$record | Add-Member -Name Quantity -MemberType NoteProperty -Value $_.Properties.Quantity
|
||||
$record | Add-Member -Name UsageStartTime -MemberType NoteProperty -Value $_.Properties.UsageStartTime
|
||||
$record | Add-Member -Name UsageEndTime -MemberType NoteProperty -Value $_.Properties.UsageEndTime
|
||||
$record | Add-Member -Name additionalInfo -MemberType NoteProperty -Value $resourceInfo.additionalInfo
|
||||
$record | Add-Member -Name location -MemberType NoteProperty -Value $resourceInfo.location
|
||||
$record | Add-Member -Name tags -MemberType NoteProperty -Value $resourceInfo.tags
|
||||
$record | Add-Member -Name subscription -MemberType NoteProperty -Value $subscription
|
||||
$record | Add-Member -Name resourceType -MemberType NoteProperty -Value $resourceType
|
||||
$record | Add-Member -Name resourceName -MemberType NoteProperty -Value $resourceName
|
||||
$record | Add-Member -Name resourceUri -MemberType NoteProperty -Value $resourceText
|
||||
$usageSummary += $record
|
||||
}
|
||||
$usageSummary | Export-Csv -Path $CsvFile -Append -NoTypeInformation
|
||||
if ($PSBoundParameters.ContainsKey(‘Debug’)) {
|
||||
$result.value | Export-Csv -Path "$CsvFile.raw" -Append -NoTypeInformation
|
||||
}
|
||||
|
||||
$params = @{
|
||||
ResourceName = '../'
|
||||
ResourceType = $usageResourceType
|
||||
ApiVersion = "2015-06-01-preview"
|
||||
ODataQuery = "reportedStartTime={0:s}&reportedEndTime={1:s}&showDetails=true&aggregationGranularity={2}" -f $StartTime, $EndTime, $Granularity
|
||||
}
|
||||
While ($count -ne 0)
|
||||
|
||||
$result = Get-AzureRmResource @params -ErrorVariable RestError -Verbose
|
||||
|
||||
if ($RestError)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
$usageSummary = @()
|
||||
$count = $result.Count
|
||||
$Total += $count
|
||||
$result | ForEach-Object
|
||||
{
|
||||
$record = New-Object -TypeName System.Object
|
||||
$resourceInfo = ($_.Properties.InstanceData | ConvertFrom-Json).'Microsoft.Resources'
|
||||
$resourceText = $resourceInfo.resourceUri.Replace('\', '/')
|
||||
$subscription = $resourceText.Split('/')[2]
|
||||
$resourceType = $resourceText.Split('/')[7]
|
||||
$resourceName = $resourceText.Split('/')[8]
|
||||
#$record | Add-Member -Name Name -MemberType NoteProperty -Value $_.Name
|
||||
#$record | Add-Member -Name Type -MemberType NoteProperty -Value $_.Type
|
||||
$record | Add-Member -Name MeterId -MemberType NoteProperty -Value $_.Properties.MeterId
|
||||
if ($meters.ContainsKey($_.Properties.MeterId)) {
|
||||
$record | Add-Member -Name MeterName -MemberType NoteProperty -Value $meters[$_.Properties.MeterId]
|
||||
}
|
||||
$record | Add-Member -Name Quantity -MemberType NoteProperty -Value $_.Properties.Quantity
|
||||
$record | Add-Member -Name UsageStartTime -MemberType NoteProperty -Value $_.Properties.UsageStartTime
|
||||
$record | Add-Member -Name UsageEndTime -MemberType NoteProperty -Value $_.Properties.UsageEndTime
|
||||
$record | Add-Member -Name additionalInfo -MemberType NoteProperty -Value $resourceInfo.additionalInfo
|
||||
$record | Add-Member -Name location -MemberType NoteProperty -Value $resourceInfo.location
|
||||
$record | Add-Member -Name tags -MemberType NoteProperty -Value $resourceInfo.tags
|
||||
$record | Add-Member -Name subscription -MemberType NoteProperty -Value $subscription
|
||||
$record | Add-Member -Name resourceType -MemberType NoteProperty -Value $resourceType
|
||||
$record | Add-Member -Name resourceName -MemberType NoteProperty -Value $resourceName
|
||||
$record | Add-Member -Name resourceUri -MemberType NoteProperty -Value $resourceText
|
||||
$usageSummary += $record
|
||||
}
|
||||
|
||||
$usageSummary | Export-Csv -Path $CsvFile -Append -NoTypeInformation
|
||||
if ($PSBoundParameters.ContainsKey('Debug'))
|
||||
{
|
||||
$result | Export-Csv -Path "$CsvFile.raw" -Append -NoTypeInformation
|
||||
}
|
||||
|
||||
Write-Host "Complete - $Total Usage records written to $CsvFile"
|
||||
}
|
||||
|
||||
#Main
|
||||
|
||||
$aadCred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList '<user@domain>', (ConvertTo-SecureString -String 'XXX' -AsPlainText -Force)
|
||||
Export-AzureStackUsage -StartTime 3/1/2017 -EndTime 3/13/2017 -AzureStackDomain 'local.azurestack.external' -AADDomain '<domain>' -Credential $aadCred -Granularity Hourly -Debug -Force
|
||||
Export-AzsUsage -StartTime 6/10/2017 -EndTime 6/11/2017 -Granularity Hourly -Force
|
||||
|
|