The following variables exist in PowerShell 5.1+, both of which seem to offer the full path to the 'invoking' script (i.e. the script that called this one, e.g. from a module, a function, or an external script):
$MyInvocation.ScriptName
$MyInvocation.PSCommandPath
I can find official documentation referencing both as options:
Which one should I use? My current theories & observations:
Any other weird edge-cases or hidden 'gotchas' with either of these that I should be aware of? Or should I be aware of any situations where one should be preferred over the other?
tl;dr
For symmetry with the automatic variable of the same name, $PSCommandPath
(which reflects the running script's full file path), it is better to use $MyInvocation.PSCommandPath
(which reflects the path of the calling script, if any).
$MyInvocation.ScriptName
, will continue to work, but I suggest avoiding it for its obscure name; on the plus side, however, it isn't plagued by the $null
quirk you've discovered (see next).Unfortunately, $MyInvocation.PSCommandPath
latter has a quirk/bug in that when there is no calling script, it reports $null
rather than the ''
(the empty string) - see GitHub issue #23828.
$null
and ''
; e.g.:
$noParentScript = -not $MyInvocation.PSCommandPath
- that is, you can rely on PowerShell's to-Boolean coercion, which coerces both $null
and ''
to $false
$noParentScript = $MyInvocation.PSCommandPath -like ''
- in the context of wildcard matching with -like
, $null
is coerced to ''
The automatic $PSCommandPath
and $PSScriptRoot
variables were introduced in PowerShell v3 (released in 2012), to reflect the running script's full file path and full directory path, respectively.
Aside from being simpler than what you needed to do in v1 and v2 - $MyInvocation.MyCommand.Path
and Split-Path -Parent $MyInvocation.MyCommand.Path
- these variables work consistently,
namely also in (script) modules.
For symmetry with the newly introduced automatic variables in v3, $MyInvocation
was given new properties with the same name, i.e. $MyInvocation.PSCommandPath
and $MyInvocation.PSScriptRoot
, which report the analogous information about the running script's caller, i.e. the invoking script.
As such, these properties may not have values in a script invoked directly from an interactive session or via Invoke-Expression
.
Just like $PSCommandPath
now (mostly) duplicates the older $MyInvocation.MyCommand.Path
,
so does $MyInvocation.PSCommandPath
(mostly) with respect to the older - and unfortunately named - $MyInvocation.ScriptName
In v3+ (v2 is fortunately rarely encountered anymore these days), it is therefore better to use the following:
$PSCommandPath
and $PSScriptRoot
$MyInvocation.PSCommandPath
and $MyInvocation.PSScriptRoot
As you've discovered, there's a quirk in that the $MyInvocation.PSCommandPath
reports $null
rather than ''
(the empty string)
if there is no calling script, unlike $MyInvocation.PSScriptRoot
(and unlike $MyInvocation.PSCommandPath
's older equivalent,
$MyInvocation.ScriptName
).
This should be considered a bug - a simple oversight in the implementation that makes for an awkward asymmetry.
I've reported it in GitHub issue #23828, though I'm not holding my breath that it will be fixed, especially since
there may be existing code that test for $null
explicitly.