0

I have a PowerShell script containing the following logging function:

function LogError([string] $message, $exception = $null) {…}

In a try-catch block, when an exception occurs, I call that logging function like this:

catch { LogError("…", $_.Exception) }

In the LogError function, the second argument is always $null. Why?

I couldn't find any documentation that would explain why I cannot use $_.Exception in a function call or that I am supposed to use instead.

AxD
  • 2,714
  • 3
  • 31
  • 53
  • This is a common mistake. In PowerShell you do not call functions the way you would in other languages `Function(Args)` The parens are precedence and grouping operators so when you pass your args like this you are passing a single array with 2 elements instead of 2 discrete arguments. – Steven Jun 22 '22 at 14:28
  • PowerShell Gotcha [2. parentheses and commas are not used with arguments](https://stackoverflow.com/a/69644807/1701026) – iRon Jun 22 '22 at 14:34

1 Answers1

3

Powershell function arguments are not passed using the parenthesis / comma formatting.

That is bad

LogError("…", $_.Exception)

Powershell take that as a single array argument. This is actually the same as LogError -Message ("...",$_.Exception)

That is ok

LogError '…' $_.Exception

That is best

 LogError -message '...' -exception $_.Exception

Complete working example

function LogError([string] $message, $exception = $null) {
  Write-Host $message
   $exception | Out-String | Write-Host -ForegroundColor red 
  }

try {
  throw 'Noooo !!!!'
}
catch {
  LogError -message 'oops' -exception $_.Exception
}

Sage Pourpre
  • 9,932
  • 3
  • 27
  • 39
  • 1
    I'd advise not to use `$_` in a catch block. `$_` is used all over PowerShell so there can be conflicts. For example if you use a try catch within a `ForEach-Object` which `$_` are you exposing. If you just caught an error it should be the last error, you can use `$Error[0].Exception` instead... – Steven Jun 22 '22 at 14:24
  • @Steven: Great suggestion! I'm actually editing an existing PowerShell script. Don't want to alter it too much. I got distracted by the existing code, not recognizing it was wrong. – AxD Jun 22 '22 at 14:25
  • 1
    @Steven f you use a try catch within a ForEach-Object, the `$_` should always be set to the error within the catch block because it is the closest element to it. At that time, that automatic variable will always contain the error. That's a problem only when you have multiple layer of `$_` and you need to access an outer layer (then it is not accessible via `$_` at that time). I prefer `$_` for brevity but both are indeed equivalent. – Sage Pourpre Jun 22 '22 at 14:39
  • 1
    @SagePourpre It's only a practical suggestion. While you're correct you lose the ability to reference the current pipeline element in a `ForEach-Object` scenario. I don't know if the disadvantages stop there. I suppose it could also be an issue in a function process block, although best practice there is to use the parameter variable instead of `$_`. – Steven Jun 22 '22 at 17:17