Powershell: Unix: A script without .ps1 extension passed to the powershell binary lacks invocation information ($PSCommandPath, $MyInvocation), such as when invoked via a shebang line.

Created on 11 Jul 2017  路  20Comments  路  Source: PowerShell/PowerShell

Steps to reproduce

Create file ./t - note the absence of extension .ps1 - with the content below and make it executable (chmod +x ./t).

#!/usr/bin/env powershell

'$PSCommandPath: ' + $PSCommandPath
'$MyInvocation.MyCommand.Path: ' + $MyInvocation.MyCommand.Path
'$MyInvocation: ' + ($MyInvocation | Out-String)

Both the following invocation methods, from bash, yield the behavior described below:

./t  # invocation via shebang line
powershell ./t   # implied -File

Expected behavior

$PSCommandPath and $MyInvocation.MyCommand.Path should reflect the script's file path, and $MyInvocation should be populated appropriately.

Actual behavior

$PSCommandPath:
$MyInvocation.MyCommand.Path:
$MyInvocation:

MyCommand             : #!/usr/bin/env powershell

                        '$PSCommandPath: ' + $PSCommandPath
                        '$MyInvocation.MyCommand.Path: ' + $MyInvocation.MyCommand.Path
                        '$MyInvocation: ' + ($MyInvocation | Out-String)

BoundParameters       : {}
UnboundArguments      : {}
ScriptLineNumber      : 0
OffsetInLine          : 0
HistoryId             : 1
ScriptName            :
Line                  :
PositionMessage       :
PSScriptRoot          :
PSCommandPath         :
InvocationName        :
PipelineLength        : 2
PipelinePosition      : 1
ExpectingInput        : False
CommandOrigin         : Runspace
DisplayScriptPosition :

Environment data

PowerShell Core v6.0.0-beta.3 on macOS 10.12.5
PowerShell Core v6.0.0-beta.3 on Ubuntu 16.04.1 LTS
Issue-Bug OS-Linux OS-macOS WG-Engine

Most helpful comment

Reopen the issue as there is an open PR for this.

All 20 comments

Is it work well without "env"? ( #!/usr/bin/powershell)

No, that doesn't make a difference.

Also keep in mind that using env (#!/usr/bin/env powershell) is the only way to _portably_ (across Unix platforms) specify the shebang line.
(On macOS, the location is /usr/local/bin/powershell, not /usr/bin/powershell).

What parameter do the shebang use to run powershell? powershell -f filename ?

#!/usr/bin/env powershell is the full shebang line, to which the system on invocation passes the absolute script file path as an argument.

In other words: the system calls env with powershell and the script file path, effectively resulting in invocation /path/to/powershell <script-file-path>.

Given that we've switched to defaulting to -File, that is all that is needed (except that to suppress the profile loading you'd also need -NoProfile - see below).

Note that _portably_ (across Unix platforms) only _one_ argument is supported in the shebang line, which due to using indirect invocation via env is already "used up" by the powershell argument.

macOS supports multiple arguments, but Linux does not, so if you wanted a shebang line that is both portable _and_ uses -NoProfile, you're out of luck.

Of course, the larger issue is that -NoProfile should be the _default_ - see #3743

Thanks for clarify! Have we the Issue if run /path/to/powershell from bash?

Yes, same issue, because these two invocation methods are effectively the same.

Please add this to first post and maybe change the Issue subject. Thanks!

@iSazonov: Done.

This is still affecting PowerShell 7.0.0-preview.2

This is still affecting PowerShell 7.0.0-RC3 and applies to the Windows environment - in Visual Studio Code.
If you have a library that uses $PSScriptRoot (ex: $Global:R = $PSScriptRoot), and you open a ps1 and selected and run (F8) "Import-Module Library.psm1" The $PSScriptRoot is not evaluated (in the library load).
This appears to be a problem with Visual Studio Code insiders edition. It is not a problem with regular Visual Studio Code. I will add that issue there.

I can confirm this issue still exists on PowerShell 7.0.0 final (OS Linux). Is there by any chance any workaround?

Same issue on Windows 10.

PSVersion 7.0.2
PSEdition Core
OS Microsoft Windows 10.0.19041

MyCommand             : test.ps1
BoundParameters       : {}
UnboundArguments      : {}
ScriptLineNumber      : 0
OffsetInLine          : 0
HistoryId             : 1
ScriptName            :
Line                  :
PositionMessage       :
PSScriptRoot          :
PSCommandPath         :
InvocationName        : D:\test.ps1
PipelineLength        : 2
PipelinePosition      : 1
ExpectingInput        : False
CommandOrigin         : Runspace
DisplayScriptPosition :

Took a look at this. This is currently "by-design". This line explicitly handles the case of a shebang script that doesn't have .ps1 extension by running the contents of the script so the file path is not preserved. Workaround is to have .ps1 extension even if using shebang to have invocation info.

Is there any reason this design should be kept?

Is there any reason this design should be changed? :-)

@iSazonov, of course there is:

A script should provide invocation information _irrespective of the specific invocation method_.

The proposed workaround is only a workaround _from within PowerShell_ and would also switch from running in a child process to running in-process; when called from outside PowerShell, you'd have to call the script _with_ the .ps1 extension, whereas the primary advantage of a shebang-line-based script is to _not_ require a filename extension.

@SteveL-MSFT's statement is open to interpretation, but I read it to mean: "While the current behavior is somewhat intentional (in the sense that there is a code path for it), it should be changed - here's the relevant source-code location for someone who wants to work on this."
@SteveL-MSFT, can you confirm?

Either way, the current behavior is clearly a bug that should be fixed, so please reopen this issue.

A script should provide invocation information _irrespective of the specific invocation method_.

Exactly. To me it also seems logical to expect external scripts to have the invocation info available no matter what the file name is. And PowerShell knows from the shebang line that the file is an external script so why not treat is as such?

I have proposed such a solution in #12494 but it does not have necessary reviews to be merged nor explanations why.

Will #12494 fix the issue too?

The stated intent of #12494 is to fix this issue.

Unfortunately, activity there has stalled after an initial flurry, as @m5x states.

Therefore:

  • Please reopen this issue.

  • Please finish reviewing #12494, so that it can be merged.

That is, unless there truly are objections to fixing this, which I find hard to imagine.
If so, we need an unambiguous statement to that effect.

Reopen the issue as there is an open PR for this.

Was this page helpful?
0 / 5 - 0 ratings