PowerShell / PowerShell

PowerShell for every system!
https://microsoft.com/PowerShell
MIT License
43.42k stars 7.03k forks source link

Expression in parameter defaults: Cannot process argument transformation on parameter #21281

Open BasBerk opened 2 months ago

BasBerk commented 2 months ago

Prerequisites

Steps to reproduce

In powershell 7.3 we could have expressions as default for the parameters:

simplified:


[CmdletBinding()]
Param(
  [Parameter(Mandatory = $False)]
  [ValidateNotNullOrEmpty()]
  [String] $TestString = $(If (-not ([String]::IsNullOrEmpty($env:TESTSTRING))) { Return ($env:TESTSTRING) } Else { "Audit" }),

  [Parameter(Mandatory = $False)]
  [Bool] $testBool = $(If (-not ([String]::IsNullOrEmpty($env:TESTBOOL))) { Return [Bool]::Parse($env:TESTBOOL) } Else { $True })
)
$PSVersionTable
write-host $testBool
write-host $TestString

Starting from 7.4.1 this is not working anymore.

Expected behavior

run.ps1
True
YourStringValue

Actual behavior

run.ps1: Cannot process argument transformation on parameter 'testBool'. Cannot convert value "" to type "System.Boolean". Boolean parameters accept only Boolean values and numbers, such as $True, $False, 1 or 0.

Error details

No response

Environment data

Name                           Value
----                           -----
PSVersion                      7.5.0-preview.2
PSEdition                      Core
GitCommitId                    7.5.0-preview.2
OS                             Ubuntu 20.04.6 LTS
Platform                       Unix
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
param values

Visuals

No response

MartinGC94 commented 2 months ago

It's because of your return statement. You can't assign the value of a return statement to a variable, even if you wrap it in a subexpression. See the following demonstration:

$Res = return "Hello"
$Res | Out-Host
$Res = $(return "Hello")
$Res | Out-Host
$Res = "Hello"
$Res | Out-Host

This behavior is consistent with what I see in 5.1 so I doubt 7.3 behaved differently. Most likely you were just hitting the branch without the return statement when you were using 7.3.

dbrennand commented 3 weeks ago

@BasBerk @MartinGC94

I've also seen this behavioural change. We noticed this from one of our Pester tests failing in our CI. I believe this issue is related to the sub-expression operator.

Seems to be that PowerShell versions 7.4.0-rc.1, 7.4.1, 7.5.0-preview.2 are affected. Interestingly, PowerShell 7.4.2 is not affected.

Take the simple example below, using the sub-expression operator:

function Get-Planet {
    [CmdletBinding()]
    param (
        $Planet = $(
            return "Earth"
        )
    )

    process {
        Write-Output -InputObject "Planet is $Planet"
    }
}
Get-Planet

PowerShell 5.1:

PS > $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.22000.2713
...

PS > function Get-Planet {
>>     [CmdletBinding()]
>>     param (
>>         $Planet = $(
>>             return "Earth"
>>         )
>>     )
>>
>>     process {
>>         Write-Output -InputObject "Planet is $Planet"
>>     }
>> }
PS > Get-Planet
Planet is Earth

PowerShell 7.3.9

docker run -it mcr.microsoft.com/powershell:7.3-ubuntu-22.04
PowerShell 7.3.9
PS /> function Get-Planet {
>>     [CmdletBinding()]
>>     param (
>>         $Planet = $(
>>             return "Earth"
>>         )
>>     )
>>
>>     process {
>>         Write-Output -InputObject "Planet is $Planet"
>>     }
>> }
PS /> Get-Planet
Planet is Earth

PowerShell 7.4.0-rc1

docker run -it mcr.microsoft.com/powershell:preview-7.4-ubuntu-22.04
PowerShell 7.4.0-rc.1
PS /> function Get-Planet {
>>     [CmdletBinding()]
>>     param (
>>         $Planet = $(
>>             return "Earth"
>>         )
>>     )
>>
>>     process {
>>         Write-Output -InputObject "Planet is $Planet"
>>     }
>> }
PS /> Get-Planet
Planet is

PowerShell 7.4.1

PS > $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.4.1
...

PS > function Get-Planet {
>>     [CmdletBinding()]
>>     param (
>>         $Planet = $(
>>             return "Earth"
>>         )
>>     )
>>
>>     process {
>>         Write-Output -InputObject "Planet is $Planet"
>>     }
>> }
PS > Get-Planet
Planet is

PowerShell 7.4.2

docker run -it mcr.microsoft.com/powershell:7.4-ubuntu-22.04
PowerShell 7.4.2
PS /> function Get-Planet {
>>     [CmdletBinding()]
>>     param (
>>         $Planet = $(
>>             return "Earth"
>>         )
>>     )
>>
>>     process {
>>         Write-Output -InputObject "Planet is $Planet"
>>     }
>> }
PS /> Get-Planet
Planet is Earth

PowerShell 7.5.0-preview.2

docker run -it mcr.microsoft.com/powershell:preview-7.5-ubuntu-22.04
PowerShell 7.5.0-preview.2
PS /> function Get-Planet {
>>     [CmdletBinding()]
>>     param (
>>         $Planet = $(
>>             return "Earth"
>>         )
>>     )
>>
>>     process {
>>         Write-Output -InputObject "Planet is $Planet"
>>     }
>> }
PS /> Get-Planet
Planet is