Thanks Kirk Munro: Become a PowerShell Debugging Ninja

# PowerShell saves all Errors in $Error Variable, clear the Errors in the beginning

$global:ErrorView = "NormalView"

Prioritize Errors

$Error |
Group-Object |
Sort-Object -Property Count -Descending |
Format-Table -Property Count, Name -AutoSize

List All Error Members

$Error[0] | fl * -Force
$Error[0].Exception | fl * -Force

Stack Trace of Error


Output Error User

# Save Callers Preference
$callerErrorActionPreference = $ErrorActionPreference
# ...
Catch {
 # Will have a nice error message
  Write-Error -ErrorRecord $_ -ErrorAction $callerErrorActionPreference

Output Error Dev

catch {
 # Log thedetails in error message
   $_.Exception | Format-List -Force| Out-String | Write-Verbose

# Or throw up, will get details into shell if not handled
Catch {

ARM Deployment

Trouble shooting ARM templates can be tedious. With these few scripts your ARM development will be much smoother and debugging way easier.

$ResourceGroupName = 'deploymentGroupName'

$correlationId = ((Get-AzLog -ResourceGroupName $ResourceGroupName)[0]).CorrelationId
$logentry = (Get-AzLog -CorrelationId $correlationId -DetailedOutput)


$rawStatusMessage = $logentry.Properties

$status = $rawStatusMessage.Content.statusMessage | ConvertFrom-Json



Debug Azure Resource Manager Deployment

function Test-ArmTemplate {
    Test the resource group deployment by getting a detailed error message using the debug output stream

    Test the resource group deployment by getting a detailed error message using the debug output stream
    This should return a more detailed error message for the template then the regular command

    .PARAMETER TemplateFile
    The path to the arm template

    .PARAMETER templateParameterObject
    The path to the arm template parameter file

    Test-ArmTemplate -TemplateFile $TemplateFile -templateParameterObject $templateParameterObject
      [Parameter(Mandatory = $true)]

      [Parameter(Mandatory = $true)]

      $Name = 'testdeployment'

  $debugpreference = "Continue"

  $Deployment = @{
    ResourceGroupName = $Name
    TemplateFile = $TemplateFile.FullName
    TemplateParameterObject = $TemplateParameterObject
    ErrorAction = Stop
  $rawResponse = Test-AzResourceGroupDeployment @Deployment 5>&1

  $debugpreference = "SilentlyContinue"

  $deploymentOutput = ($rawResponse.Item(32) -split 'Body:' |
    Select-Object -Skip 1 |

  return $deploymentOutput

Azure Resource Manager Outputs

When dealing with Azure Resource Manager Templates New-AzResourceGroupDeployment -... returns a json. To get only the outputs a little script is needed to extract the values.

$return = [PSCusomtOBject]@{}
Foreach($output in $Outputs.GetEnumerator()) {
  $return | Add-Member -MemberType NoteProperty -Name $output.Name -Value $output.Value.Value

Log complex Objects

If you want to log a complex object while sticking limiting the output to the Verbose stream. You can use Format-List * -Force to expand the whole object. Pipe it to Out-String to create one big string stream and pipe this into Write-Verbose. Now youy have the whole output in your verbose output.

# Function is not needed, but makes the idea clear.
function _log($Object) {
    $Object | format-list * -force | Out-String | Write-Verbose

Save Session State

How to save time intensive output state and reuse for debugging (ARM template outputs debugging) If you want to troubleshoot a time intensive output and save the state you can leverage export-clixml.

After that you can use the state.xml to retrieve the objects and all of their properties.

# Deploy actual arm template or time intensive task then generates an object to reuse
$Deploy = New-AzResourceGroupDeployment ....

# save the state by serializing the object to xml
$Deploy | Export-Clixml $Home\state.xml

# load time intensive object from serialized state
$session = Import-Clixml $home\state.xml

That will allow you to troubleshoot the output without rerunning the whole script until this point. In debug mode you are able to export the output of a script at runtime at a specific place and time, too.

Pester Test

Leveraging Pester is a good practice. There are some tricks to work with Pester a bit smarter.

Store the output into a variable using -PassThru. No you can query the output and search e.g. for only Failed tests.

Also, if you are within a Pester test the output, especially from exceptions, is suppressed. Using a work around you can still get the exception message.

# Invoke with Output Object
$pester = Invoke-Pester -PassThru

# Get Summary of Pester

# Display only Failed Tests
$pester.TestResult | ? { $_.Result -eq 'Failed' }

# Pest Test Error Display
$_.Exception | Format-List * -Force | Out-String | Write-Host


Script Analyzer helps you to write good PowerShell code.

 Invoke-ScriptAnalyzer -Path $Path -IncludeDefaultRules