FIX: Azure Automation PS 7 not recognizing environment variables

Do I run the script (runbook) locally or in Azure Automation?

I develop scripts or runbooks on my local machine and then run them against Microsoft Graph or Azure (REST API) and when the script is complete I upload them in Azure Automation as a runbook.

I need logic in my script to see if it’s running locally or in Azure Automation so I can import the right modules, call the right variables, and more.

When you run a runbook in PowerShell 5.1 in Azure Automation, object $PSPrivateMetadata is available. This for example contains the JobId.

For PowerShell 7 there is (I don’t think so?) such object. At least I haven’t found it yet.
I use environment variables for this.

There is a whole list of variables in the environment variables ran in Azure Automation. The Azure Automation sandbox Id and the distribution channel where the runbook runs, and more.

[Environment]::GetEnvironmentVariables()

Name                           Value
----                           -----
USERNAME                       Client
AUTOMATION_ASSET_ENDPOINT      http://127.0.0.1:20043/
AUTOMATION_ASSET_KEY           SZ142JlZ3K1osD/jiB6seh54YGp3/Y/wnNJxifC8gmA=
COMPUTERNAME                   CLIENT
AZUREPS_HOST_ENVIRONMENT       AzureAutomation/
MSI_SECRET                     QazgMdBlQ1l6bO31fEV0eO8dhwSoC6MIdlkG0YmEBFo=
MSI_ENDPOINT                   http://127.0.0.1:20043/oauth2/token
IDENTITY_ENDPOINT              http://127.0.0.1:20043/oauth2/token
AUTOMATION_ASSET_ACCOUNTID     01752a2d-1d81-156a-9471-1432ab3aebf0
IDENTITY_HEADER                QazgMdBlQ1l6bO34fEV0eO8dhwSoC6MIdlkG0YmEBFo=
POWERSHELL_DISTRIBUTION_CHANN… AzureAutomation
SkipAzInstallationChecks       true
AUTOMATION_ASSET_SANDBOX_ID    25c1b720-cae1-40a1-9dde-c6bc77504e11

The logic behind a script running locally or in Azure Automation

I assumed, and this also brings me to the problem for which I am writing the blog, that various environment variables are always available.
For that reason I assumed that when $env:AUTOMATION_ASSET_SANDBOX_ID has a value, the script is running in Azure sandbox.

I checked that with this ‘simple trick’:

if (([string]::IsNullOrEmpty($env:AUTOMATION_ASSET_SANDBOX_ID))) {
    Write-Output 'Running Locally'
} 
else {
    Write-Output 'Running in Azure Automation sandbox'
}

And yet every so often a runbook job had a failed state that before and after that simply had a completed job state again.

The runbook jobs that failed, which failed on a suspended state with the last verbose logging being the following:

VERBOSE: Populating RepositorySourceLocation property for module Az.

Thats weird? That’s a verbose message for when a module is imported and for the module Az it’s often Connect-AzAccount that is called after.

So, I checked a few things and made the discovery that the environment variables not always have a value. Which means the runbook running in Azure Automation thinks it’s running locally and since Connect-AzAccount does not use basic authentication anymore, it will simply open the default browser with the modern authentication login method for Azure & PowerShell.

The runbook would have failed with the error message that you cannot open a interactive action on a sandbox environment.


So, how can we be 100% sure the runbook is running locally or in Azure Automation? Environment variables!

I have come up with a workaround for this how you can distinguish locally and Azure Automation.

We do not run runbooks on hybrid workers and sandboxes, so all scripts that need to run, run in the sandbox environment.

So, I can continue to use the variable $env:AUTOMATION_ASSET_SANDBOX_ID, but so look carefully at which variable best suits your scenario.

So the situation is as follows:

We check if the variable $env:AUTOMATION_ASSET_SANDBOX_ID has a value, if so, then the runbook runs in Azure Automation or we check the variable, but it does not return a value, so you still don’t know if the runbook runs in Azure Automation.

The following should be sufficient for this:

if ([string]::IsNullOrEmpty($env:AUTOMATION_ASSET_SANDBOX_ID)) {
    Write-Output 'UNKNOWN?'
}
else {
    $RunningLocally = $false
}

So, we now need a 2nd check. Azure Automation has a number of cmdlets that are for internal use only. 1 of these is Start-AutomationRunbook.

This isn’t a cmdlet I have on my local machine, so we could use it nicely.

We can use Get-Command to see if this cmdlet is available, and if not, throw it to a catch block.

This would look like this:

if ([string]::IsNullOrEmpty($env:AUTOMATION_ASSET_SANDBOX_ID)) {
    try {
        $null = Get-Command 'Start-AutomationRunbook' -ErrorAction Stop
        $RunningLocally = $false
    }
    catch {
        $RunningLocally = $true
    }
}
else {
    $RunningLocally = $false
}

Now you can be sure that the correct values are taken per environment.


The end result I use

I have written it out in full for you below.
Includes PowerShell 5.

#region Test if the runbook really is not running in Azure Automation
# This is a workaround for Azure Automation 7, the JobId is not always available in the PSPrivateMetadata or the env:AUTOMATION_ASSET_SANDBOX_ID
if (([string]::IsNullOrEmpty($PSPrivateMetadata.JobId.Guid)) -and ([string]::IsNullOrEmpty($env:AUTOMATION_ASSET_SANDBOX_ID))) {
    try {
        $null = Get-Command 'Start-AutomationRunbook' -ErrorAction Stop
        $RunningLocally = $false
    }
    catch {
        $RunningLocally = $true
    }
}
else {
    $RunningLocally = $false
}
#endregion Test if the runbook really is not running in Azure Automation
#region Azure Automation
if ($RunningLocally -eq $false) {
    Connect-AzAccount -Identity
}
#endregion Azure Automation
#region Local
else {
    Connect-AzAccount
}
#endregion Local

Can it be more readable, manageable, optimized? I’m sure, but this is my way.

Published by

Bas Wijdenes

My name is Bas Wijdenes and I work as a PowerShell DevOps Engineer. In my spare time I write about interesting stuff that I encounter during my work.

Leave a Reply

Your email address will not be published. Required fields are marked *