PowerShell error record has empty/incorrect 'InvocationInfo'

Viewed 258

I am running a PowerShell script in Azure DevOps, and in the event of a command failing I need to log a warning so that observers can see that the script did not run as expected.

As part of the warning, I wish to output the path to the script and the line number / offset where an exception occurred.

To do this, am using the $_ variable within the catch or a try/catch block.

$command = "New-AzCosmosDBAccountKey -Name {0} -ResourceGroupName {1} -KeyKind {2}" -f $Name, $ResourceGroupName, $keyKind
Write-Verbose ("##[command] {0}" -f $command)
try {
    Invoke-Expression $command
}
catch
{
    Write-Host ("##[warning] {0}" -f $_.Exception.Message -replace "`r`n", ". ")
    Write-Host ("##vso[task.logissue type=warning;sourcepath={0};linenumber={1};columnnumber={2};]{3}" -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.InvocationInfo.OffsetInLine, $_.Exception.Message -replace "`r`n", ". ")
}

However, for some reason within $_.InvocationInfo, the ScriptName is blank and both ScriptLineNumber and OffsetInLine are set to 1.

If I output $_.ScriptStackTrace I see that there are three messages, and presumably $_ relies on the last message in the stack trace.

at <ScriptBlock>, <No file>: line 1
at <ScriptBlock>, C:\pathTo\My-Script.ps1: line 40
at <ScriptBlock>, <No file>: line 1

What I don't understand is where these messages on the stack trace are coming from, and why they don't contain the script name, line number, etc.

1 Answers

After comments on OP stating that my issue was being caused be the use of Invoke-Expression, and suggesting that I don't use that cmdlet, I investigated other possible solutions and I came across the brave new world (for me!) of splatting.

Sadly there is no Format-Splat function, so I had to write a little one, but as it'll be used several times in the script I'm not too bothered. Hoepfully this is something MS will add in the future.

Happily, using the snippets below means that warnings are now being written properly for Azure DevOps -

##vso[task.logissue type=warning;sourcepath=C:\pathTo\My-Script.ps1;linenumber=60;columnnumber=17;]Something went wrong.

using namespace System.Collections.Specialized

function Format-Splat
{
    param([Parameter(Mandatory=$true)][OrderedDictionary]$Hashtable)

    $output = @()
    foreach ($key in $Hashtable.Keys)
    {
        $output += "-{0} {1}" -f $key, $Hashtable[$key]
    }    
    Write-Output ($output -join " ")
}

$parameters = [Ordered]@{ Name = $Name; ResourceGroupName = $ResourceGroupName; keyKind = $keyKind }
Write-Verbose ("##[command]New-AzCosmosDBAccountKey {0}" -f (Format-Splat $parameters))
try {
    $null = New-AzCosmosDBAccountKey @parameters
}
catch
{
    Write-Output ("##vso[task.logissue type=warning;sourcepath={0};linenumber={1};columnnumber={2};]{3}" -f $_.InvocationInfo.ScriptName, $_.InvocationInfo.ScriptLineNumber, $_.InvocationInfo.OffsetInLine, $_.Exception.Message -replace "`r`n", ". ")
}
Related