try catch doesn’t work with Exchange cmdlets in a remote session

I have something that connects to an on-prem Exchange server remotely and creates a mailbox etc. Like so:

Naturally I put it in a try catch block to catch any errors:

Yes, I did take care to add the -ErrorAction Stop so the cmdlet should stop in case of any errors and try catch will catch it. You’d think this will work, and I am pretty positive I tested it too (but I am not a 100% sure)… but last week I realized that it wasn’t working. I had a few instances where this cmdlet failed but my script didn’t realize and it said everything was swell.

I tested this out manually, and sure enough it doesn’t work. I then found this very helpful blog post from 2015 where the author ran into the same issue and he has a useful workaround: Invoke-Command. So you’d do the following:

Turns out Invoke-Command can be set to fail if the underlying cmdlet fails, and we can capture that in the try catch block.

But that brings a new problem. The variables $Identity and $EmailAddress are not passed on to the remote session. To work around that you have to use remote variables. You could do something like $Using:Identity and $Using:EmailAddress which makes Invoke-Command take the local variables and pass them on… and turns out it can even work with splatting (I didn’t know I could use $Using with splatting – so cool!):

Lastly you can also use -ArgumentList with Invoke-Command and each of the arguments you give are passed on the $args[0] and so on.

As part of troubleshooting Invoke-Command I learnt that since April 2021 Exchange remote PowerShell runs in a No Language mode. This means I can’t for instance do something like Write-Host within the Invoke-Command scriptblock. If you try that you get the following error:

The syntax is not supported by this runspace. This can occur if the runspace is in no-language mode.

From this page:

NoLanguage mode can only be used through the API. NoLanguage mode means no script text of any form is permitted. This precludes the use of the AddScript() method which sends fragments of PowerShell script to be parsed and executed. You can only use AddCommand() and AddParameter() which don’t go through the parser.

Beginning in PowerShell 7.2, the New-Object cmdlet is disabled in NoLanguage mode when system lockdown is configured.

Blimey!