Powershell splatting: pass ErrorAction = Ignore in hash table

819 views Asked by At

Here's a script to list directories / files passed on the command line -- recursively or not:

param( [switch] $r )
@gci_args = @{
  Recurse = $r
  ErrorAction = Ignore
}
$args | gci @gci_args 

Now this does not work because Ignore is interpreted as a literal. What's the canonical way to pass an ErrorAction?

I see that both "Ignore" and (in PS7) { Ignore } work as values, but neither seems to make a difference for my use case (bad file name created under Linux, which stops PS5 regardless of the ErrorAction, but does not bother PS7 at all). So I'm not even sure the parameter has any effect.

2

There are 2 answers

6
filimonic On BEST ANSWER

I think the best way is to use native type.

$ErrorActionPreference.GetType().FullName # System.Management.Automation.ActionPreference

So, use

$gci_args = @{   
  Recurse = $r
  ErrorAction = [System.Management.Automation.ActionPreference]::Ignore
}
0
mklement0 On

because Ignore is interpreted as a literal

No, Ignore is interpreted as a command to execute, because it is parsed in argument mode (command invocation, like a shell) rather than in expression mode (like a traditional programming language) - see this answer for more information.

While using a [System.Management.Automation.ActionPreference] enumeration value explicitly, as in filimonic's helpful answer, is definitely an option, you can take advantage of the fact that PowerShell automatically converts back and forth between enum values and their symbolic string representations.

Therefore, you can use string 'Ignore' as a more convenient alternative to [System.Management.Automation.ActionPreference]::Ignore:[1]

$gci_args = @{
  # ... 
  ErrorAction = 'Ignore'
}

Note that it is the quoting ('...') that signals to PowerShell that expression-mode parsing should be used, i.e. that the token is a string literal rather than a command.

Also note that -ErrorAction only operates on non-terminating errors (which are the typical kind, however) - see this answer for more information.


As for discovery of the permissible -ErrorAction values:

  • The conceptual about_CommonParameters help topic covers all common parameters, of which -ErrorAction is one.

  • Many common parameters have corresponding preference variables (which accept the same values), covered in about_Preference_Variables, which allow you to preset common parameters.

  • Interactively, you can use tab-completion to see the permissible values (as unquoted symbolic names, which you simply need to wrap in quotes); e.g.:

    # Pressing the Tab key repeatedly where indicated 
    # cycles through the acceptable arguments.
    Get-ChildItem -ErrorAction <tab> 
    

[1] Note that using a string does not mean giving up type safety, if the context unambiguously calls for a specific enum type, such as in this case. Validation only happens at runtime either way, given that PowerShell is an interpreted language.
However, it is possible for a PowerShell-aware editor - such as Visual Studio Code with the PowerShell extension - to flag incorrect values at design time. As of version 2020.6.0, however, that does not yet appear to be the case. Fortunately, however, tab-completion and IntelliSense work as expected, so the problem may not arise.
That said, as zett42 points out, in the context of defining a hashtable entry for latter splatting the expected type is not (yet) known, so explicit use of [System.Management.Automation.ActionPreference] does have advantages: (a) IntelliSense in the editor can guide you, and (b) - assuming that Set-StrictMode -Version 2 or higher is in effect - an invalid value will we reported earlier at runtime, namely at the point of assignment, which makes troubleshooting easier. As of PowerShell 7.1, a caveat regarding Set-StrictMode -Version 2 or higher is that you will not be able to use the intrinsic (PowerShell-supplied) .Count property on objects that don't have it type-natively, due to the bug described in GitHub issue #2798.