Error
Thanks Kirk Munro: Become a PowerShell Debugging Ninja
# PowerShell saves all Errors in $Error Variable, clear the Errors in the beginning
$global:Error.Clear()
$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
$Error[0].StackTrace
$Error[0].Exception.StackTrace
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 {
Throw
}
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)
$logentry
$rawStatusMessage = $logentry.Properties
$status = $rawStatusMessage.Content.statusMessage | ConvertFrom-Json
$status.error.details
$status.error.details.details
Debug Azure Resource Manager Deployment
function Test-ArmTemplate {
<#
.SYNOPSIS
Test the resource group deployment by getting a detailed error message using the debug output stream
.DESCRIPTION
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
.EXAMPLE
Test-ArmTemplate -TemplateFile $TemplateFile -templateParameterObject $templateParameterObject
#>
param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullorEmpty()]
[object]
$TemplateFile,
[Parameter(Mandatory = $true)]
[ValidateNotNullorEmpty()]
[HashTable]
$templateParameterObject,
[string]
$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 |
ConvertFrom-Json).properties
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
}
$return
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
$pester
# Display only Failed Tests
$pester.TestResult | ? { $_.Result -eq 'Failed' }
# Pest Test Error Display
$_.Exception | Format-List * -Force | Out-String | Write-Host
ScriptAnalyzer
Script Analyzer helps you to write good PowerShell code.
Invoke-ScriptAnalyzer -Path $Path -IncludeDefaultRules