Home > Enterprise >  Can't call a Powershell script through the registry properly. A positional parameter cannot be
Can't call a Powershell script through the registry properly. A positional parameter cannot be

Time:11-16

Here is a simple test function called RegistryBoundParams.ps1:

[CmdletBinding()]
param (
    [Parameter(Mandatory = $true)]
    [string]
    $Target,

    [Parameter(Mandatory = $false)]
    [switch]
    $MySwitch
)

if(!(Test-IsAdmin)){
    Request-AdminRights -NoExit
    Exit
}

if($MySwitch){
    "Do something" | Out-Host
}else {
    "Do something else" | Out-Host
}

Show-AllArguments

If I call it via the PS terminal, everything works as expected:

Exact call: C:\Tools\scripts> .\RegistryBoundParams.ps1 -Target "C:\Test\" -MySwitch

enter image description here

enter image description here

If I call it through the registry (adding the command to a context menu), I get:

pwsh -noexit -file "C:\Tools\scripts\RegistryBoundParams.ps1" -Target "C:\Program Files\Python39\python.exe" -MySwitch

enter image description here enter image description here enter image description here

Plaintext of the error: RegistryBoundParams.ps1: A positional parameter cannot be found that accepts argument '$null'.

Here's a reg file that shows exactly what I added in the registry:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\*\shell\1_TestRegistry]
@="Test Powershell Script from Registry"
"Icon"="C:\\Tools\\icons\\apps\\Powershell 1.ico,0"
"NeverDefault"=""

[HKEY_CLASSES_ROOT\*\shell\1_TestRegistry\command]
@="pwsh -noexit -file \"C:\\Tools\\scripts\\RegistryBoundParams.ps1\" -Target \"C:\\Program Files\\Python39\\python.exe\""

So somewhere along the lines $Null is being passed to the script, and I have no Idea why.

I could really, really use some help here.

Thanks so much for any guidance.

Edit:


I found that if I add a new string variable called $catchall, the script works. I suspect that when being called from the registry it's appending a null value for some reason. Which is why the script works when I define an additional "catch all" variable.

This is definitely not an ideal solution at all, so I am still looking for a solution here. Really appreciate any help!

Edit2:


It turns out that the Request-AdminRights script I was using that mklement0 authored had a bug that has now been fixed. Anyone who wants one-line self elevation with bound/unbound parameter support that's cross-platform... go get it!

CodePudding user response:

The problem was a (since-fixed) bug in the code that you based your self-elevating function Request-AdminRights on:

The bug was that in the case of an advanced script such as yours, $args - which is never bound in advanced scripts - was mistakenly serialized as $null instead of translated to @(), resulting in that $null getting passed as an extra argument on re-invocation.

If you redefine your Request-AdminRights function based on the now updated body of the Ensure-Elevated function in the original answer, your problem should go away - no need to modify the enclosing script.

  • Related