Powershell: $PSScriptRoot is not populated when used in a default value for a non-mandatory script parameter

Created on 28 Aug 2017  路  8Comments  路  Source: PowerShell/PowerShell

Steps to reproduce

Run this script (via PowerShell -File ....)

param(
    [Parameter(Mandatory = $false)]
    [string] $Foo = 'hi\{0}\hi' -f $PSScriptRoot
)

Write-Host $Foo

Function Bar {
    param(
        [Parameter(Mandatory = $false)]
        [string] $Bar = $PSScriptRoot
    )
    Write-Host $Bar
}

Function Baz {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [string] $Baz = $PSScriptRoot
    )
    Write-Host $Baz
}

Bar
Baz

Expected behavior

hi\C:\tmp\hi
C:\tmp
C:\tmp

Actual behavior

hi\\hi
C:\tmp
C:\tmp

Environment data

Name                           Value
----                           -----
PSVersion                      5.1.16353.1000
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.16353.1000
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

_[edited by @daxian-dbw to put the repro in code blocks]_

Issue-Question Resolution-Fixed WG-Language

Most helpful comment

@iSazonov valid point, I've been thinking about having different degrees of Breaking Change labels as they are not all equal

All 8 comments

Actually, what matters is whether the script is an _advanced_ (cmdlet-like) script or not.
By using a [Parameter(...)] attribute, you're _implicitly_ making your script an advanced script, even without decorating your param(...) block with an explicit [CmdletBinding()] attribute.

Combining an advanced script with invocation via powershell -File is what produces the symptom, as the following simplified script demonstrates:

Save the following as t.ps1 in the current dir:

[CmdletBinding()]
param(
  $Foo = $PSScriptRoot
)

"[$Foo]"
# Direct invocation works fine.
> ./t.ps1
[/Users/jdoe]

# Invocation via the external CLI with -File shows the symptom:
> powershell -File ./t.ps1
[]

Were you to omit [CmdletBinding()], the symptom would _not_ surface.


Two asides:

  • Your version table shows a _Windows PowerShell_ version. In this case, the symptom also surfaces in _PowerShell Core_. Generally, you should only report issues here that (also) surface in PS Core, using the latest released version. If a symptom surfaces _only_ in Windows PS, report it on uservoice.com.

  • Please use the fenced code and output blocks provided in the issue template (```powershell ... and ```none ...) - it makes for much more readable representations.

Thanks @mklement0 for the analysis and simple repro! It's really helpful.
It also repros when you dot source a script cmdlet in powershell, for example:

# use the same 't.ps1'
> . .\t.ps1
[]

This is because the automatic variables are not set up before parameter binding for a script cmdlet when they are not going to run in new local scopes. I'm preparing a fix.

@SteveL-MSFT
This fix does not have the 'Breaking-Change' label ? Is it correct ?

@LaurentDardenne agree this is technically a breaking change

:-) Any bug fix is a breaking change. I guess this label is useless here.

@iSazonov valid point, I've been thinking about having different degrees of Breaking Change labels as they are not all equal

It make sense only if we want strongly document breaking change buckets in docs and changelog.

I believe we've been trying to use Breaking-Change label on issues/PRs that we believe will have a high chance of impact or that the impact is high if encountered. Agree that technically any bug fix is a breaking change. So as to not dilute this label, I'm removing it from this issue as it's unlikely anyone is expecting the previous behavior.

Was this page helpful?
0 / 5 - 0 ratings