简体   繁体   中英

Powershell removing commandlet flag altogether depending on powershell version

With Powershell 7 there have been several changes to Invoke-RestMethod . I've written some modules that are wrappers for several Invoke-RestMethod calls to simplify the interaction with our API for my colleagues. In Powershell 5.1 this code runs fine:

Invoke-RestMethod -Method Get -Uri "http://localhost/MyServer/MyApi" -UseDefaultCredentials

In Powershell 7 this generates an error because I'm using an HTTP resource rather than HTTPS:

Invoke-RestMethod: The cmdlet cannot protect plain text secrets sent over unencrypted connections. To suppress this warning and send plain text secrets over unencrypted networks, reissue the command specifying the AllowUnencryptedAuthentication parameter.

To get around this you just need to add -AllowUnencryptedAuthentication to the call and it works, but that only works for Powershell 7. If I add the flag in a Powershell 5.1 environment it generates an error because the flag doesn't exist:

Invoke-RestMethod : A parameter cannot be found that matches parameter name 'AllowUnencryptedAuthentication'.

There is a workaround by doing the following, but making this change to every single module is going to be a PITA since the Invoke-RestMethod varies from module to module:

if ($PSVersionTable.PSVersion.Major -gt 5) {
    Invoke-RestMethod -Method Get -Uri "http://localhost/MyServer/MyApi" -UseDefaultCredentials -AllowUnencryptedAuthentication
}
else {
    Invoke-RestMethod -Method Get -Uri "http://localhost/MyServer/MyApi" -UseDefaultCredentials
}

I know that you can pass values like -Verbose using something like $PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent as described here but I need to completely remove the flag if I'm in a 5.1 or earlier environment and add it for 7 or later. Is there a way to do this in one line or do I need to make the above change to every module?

You could do it using only one condition that checks if the version is PowerShell Core, and if it is, add AllowUnencryptedAuthentication = $true as default value using the preference variable $PSDefaultParameterValues :

if($IsCoreCLR) {
    $PSDefaultParameterValues['Invoke-RestMethod:AllowUnencryptedAuthentication'] = $true
}

A simple example using a temporary module with an advanced function:

$PSDefaultParameterValues = @{
    'Test-PSDefaultParameterValues:param1' = 'hello'
    'Test-PSDefaultParameterValues:param2' = 'world!'
}

New-Module -Name temp -ScriptBlock {
    function Test-PSDefaultParameterValues {
        [CmdletBinding()]
        param($param1, $param2)

        "$param1 $param2"
    }
} -Function Test-PSDefaultParameterValues | Import-Module

Test-PSDefaultParameterValues

You could also use Splatting as mclayton pointed out in a comment. This way would be preferable in my opinion instead of updating the session state of a possible user of your module, however this would also need to be updated in all your function calls:

# this would be the default params for calling the cmdlet
$param = @{
    Method = 'Get'
    Uri    = 'http://localhost/MyServer/MyApi'
    UseDefaultCredentials = $true
}

# then we check if this is Core, and then add the missing
# parameter to the splat hashtable
if($IsCoreCLR) {
    $param['AllowUnencryptedAuthentication'] = $true
}

Invoke-RestMethod @param

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM