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

  1. create ADF
  2. Get Principal ID of ADF
  3. 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!