Last active
March 12, 2019 01:22
-
-
Save gdbarron/40a05af81a12f936aaf6f68ade57f329 to your computer and use it in GitHub Desktop.
Perform validation prior to moving Azure resources between resource groups or subscriptions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
Test if moving Azure resources will be successful | |
.DESCRIPTION | |
Test if moving Azure resources will be successful. Returns a boolean, but will also display an error if encountered. | |
.PARAMETER SourceSubscriptionId | |
Subscription ID where the resources are to move from | |
.PARAMETER SourceResourceGroup | |
Resource group name where the resources are to move from | |
.PARAMETER SourceResourceIds | |
Resource IDs to be moved. The resource id can typically be found on the Properties page in the portal | |
.PARAMETER TargetSubscriptionId | |
Subscription ID where the resources are to move to. If moving within the same subscription, this does not need to be provided. | |
.PARAMETER TargetResourceGroup | |
Resource group name where the resources are to move to | |
.EXAMPLE | |
.Test-AzureResourceMove.ps1 -SourceSubscriptionId '5a9601f8-83d2-4d2f-a655-24518e89e766' -SourceResourceGroup 'my_source_rg' -TargetResourceGroup 'my_target_rg' -SourceResourceIds '/subscriptions/5a9601f8-83d2-4d2f-a655-24518e89e766/resourceGroups/my_source_rg/providers/Microsoft.Compute/virtualMachines/myVM' | |
Test resource moves within the same subscription | |
.INPUTS | |
None | |
.OUTPUTS | |
Boolean | |
.NOTES | |
Author: Greg Brownstein | |
.LINK | |
https://gallery.technet.microsoft.com/scriptcenter/Easily-obtain-AccessToken-3ba6e593 | |
#> | |
param( | |
[Parameter(Mandatory)] | |
[string] $SourceSubscriptionId, | |
[Parameter(Mandatory)] | |
[string] $SourceResourceGroup, | |
[Parameter(Mandatory)] | |
[string[]] $SourceResourceIds, | |
[Parameter()] | |
[string] $TargetSubscriptionId, | |
[Parameter(Mandatory)] | |
[string] $TargetResourceGroup | |
) | |
function Get-AzureRmCachedAccessToken() { | |
$ErrorActionPreference = 'Stop' | |
if (-not (Get-Module AzureRm.Profile)) { | |
Import-Module AzureRm.Profile | |
} | |
$azureRmProfileModuleVersion = (Get-Module AzureRm.Profile).Version | |
# refactoring performed in AzureRm.Profile v3.0 or later | |
if ($azureRmProfileModuleVersion.Major -ge 3) { | |
$azureRmProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile | |
if (-not $azureRmProfile.Accounts.Count) { | |
Write-Error "Ensure you have logged in before calling this function." | |
} | |
} | |
else { | |
# AzureRm.Profile < v3.0 | |
$azureRmProfile = [Microsoft.WindowsAzure.Commands.Common.AzureRmProfileProvider]::Instance.Profile | |
if (-not $azureRmProfile.Context.Account.Count) { | |
Write-Error "Ensure you have logged in before calling this function." | |
} | |
} | |
$currentAzureContext = Get-AzureRmContext | |
$profileClient = New-Object Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient($azureRmProfile) | |
Write-Debug ("Getting access token for tenant" + $currentAzureContext.Subscription.TenantId) | |
$token = $profileClient.AcquireAccessToken($currentAzureContext.Subscription.TenantId) | |
$token.AccessToken | |
} | |
function Get-AzureRmBearerToken() { | |
$ErrorActionPreference = 'Stop' | |
('Bearer {0}' -f (Get-AzureRmCachedAccessToken)) | |
} | |
function Get-AzCachedAccessToken() { | |
$ErrorActionPreference = 'Stop' | |
if (-not (Get-Module Az.Profile)) { | |
Import-Module Az.Profile | |
} | |
$azureRmProfileModuleVersion = (Get-Module Az.Profile).Version | |
$azureRmProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile | |
if (-not $azureRmProfile.Accounts.Count) { | |
Write-Error "Ensure you have logged in before calling this function." | |
} | |
$currentAzureContext = Get-AzContext | |
$profileClient = New-Object Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient($azureRmProfile) | |
Write-Debug ("Getting access token for tenant" + $currentAzureContext.Tenant.TenantId) | |
$token = $profileClient.AcquireAccessToken($currentAzureContext.Tenant.TenantId) | |
$token.AccessToken | |
} | |
function Get-AzBearerToken() { | |
$ErrorActionPreference = 'Stop' | |
('Bearer {0}' -f (Get-AzCachedAccessToken)) | |
} | |
Write-Warning "Be patient, this will take some time..." | |
if ( -not $PSBoundParameters.ContainsKey('TargetSubscriptionId') ) { | |
$TargetSubscriptionId = $SourceSubscriptionId | |
} | |
Write-Verbose "Getting token" | |
$authHeader = Get-AzureRmBearerToken | |
$body = @{ | |
'resources' = $SourceResourceIds | |
'targetResourceGroup' = "/subscriptions/$TargetSubscriptionId/resourceGroups/$TargetResourceGroup" | |
} | |
$params = @{ | |
Method = 'Post' | |
Uri = "https://management.azure.com/subscriptions/$SourceSubscriptionId/resourceGroups/$SourceResourceGroup/validateMoveResources?api-version=2018-02-01" | |
Headers = @{'Authorization' = $authHeader} | |
ContentType = 'application/json' | |
Body = ($body | ConvertTo-Json) | |
} | |
$initialRequest = Invoke-WebRequest @params | |
$retryInSecs = $initialRequest.headers.'Retry-After' | |
$retryLocation = $initialRequest.headers.location | |
$performRetry = $false | |
$testPassed = $false | |
if ( $retryInSecs -and $retryLocation ) { | |
$performRetry = $true | |
Write-Verbose "Successfully created validation request, waiting for response from Azure" | |
} | |
$params = @{ | |
Method = 'Get' | |
Uri = $initialRequest.headers.location | |
Headers = @{'Authorization' = $authHeader} | |
} | |
while ($performRetry) { | |
Write-Verbose "Sleeping $retryInSecs seconds" | |
Start-Sleep -Seconds $retryInSecs | |
try { | |
$response = Invoke-WebRequest @params | |
switch ($response.StatusCode) { | |
202 { | |
# operation still in progress | |
$retryInSecs = $response.headers.'Retry-After' | |
} | |
204 { | |
# success | |
$testPassed = $true | |
$performRetry = $false | |
} | |
Default { | |
# something we didn't expect | |
$performRetry = $false | |
Write-Error ($response | Out-String) | |
$testPassed = $false | |
} | |
} | |
} | |
catch { | |
$errDetails = $_.ErrorDetails.message | ConvertFrom-Json | |
Write-Error ('Validation failed with code {0} and message {1}' -f $errDetails.error.code, $errDetails.error.message) | |
$performRetry = $false | |
$testPassed = $false | |
} | |
} | |
$testPassed |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment