Catching Non-Terminating Errors in PowerShell
Hello!
I’m sure I’ve learnt this before somewhere, but now I’m writing it down to make sure I don’t forget: PowerShell will not catch non-terminating errors. This means you cannot use try/catch when attempting some retry logic. This caught me out today in some Azure RM PowerShell scripts I’ve been working on: I create an ADF, and because I’m going to add a shared self-hosted Integration Runtime to it I need to assign the ADF contributor permissions. Sadly, whilst the object is created fast enough as a resource in Azure, the principal is not added to AAD until up to a minute after the creation of the ADF. So if my step are as follows
- create ADF
- Get Principal ID of ADF
- Add Contributor permissions using principal ID of ADF
Step 3 is where I get the failure. Now I could do something rudimentary like add a start-sleep -Seconds 60
to the script like below, but that seems a little basic. Especially as it could take longer for the principal to be created.
$SharedIR = Get-AzureRmDataFactoryV2IntegrationRuntime -ResourceGroupName $DefaultResourceGroupName -DataFactoryName $defaultFactoryName -Name $integrationRuntimeName
Write-Host "Adding role assignment..."
Start-Sleep -Seconds 60
New-AzureRMRoleAssignment -ObjectId $factory.Identity.PrincipalId -RoleDefinitionId 'b24988ac-6180-42a0-ab88-20f7382dd24c' -Scope $SharedIR.Id
What would be neater it to set up a retry to catch the error if the principal id does not exist, and this is what I lost some time to today: if the principal ID does not exist, because the error thrown by the cmdlet is not terminating, it will not throw an exception. So if I want it to throw an exception, and therefore make it catchable, I need to update the errorAction
to Stop on that specific cmdlet.
$SharedIR = Get-AzureRmDataFactoryV2IntegrationRuntime -ResourceGroupName $DefaultResourceGroupName -DataFactoryName $defaultFactoryName -Name $integrationRuntimeName
Write-Host "Adding role assignment..."
$retryCount = 10
while ($retryCount -gt 0) {
try {
New-AzureRMRoleAssignment -ObjectId $factory.Identity.PrincipalId -RoleDefinitionId 'b24988ac-6180-42a0-ab88-20f7382dd24c' -Scope $SharedIR.Id -ErrorAction Stop
$retryCount = 0
}
catch {
Write-Host "Principal does not exist. Maybe it has not been created. Sleeping for 10 seconds and trying again..."
Start-Sleep -Seconds 10
$retryCount --
}
}
And if it does take longer than a minute: fine. And if it is shorter: also fine!