Search code examples
powershellbatch-filewindows-10-universalpowershell-5.0

Run powershell script as administrator via batch file with parameter passing


When I run the script, without an administrator, via batch file it passes the parameter, but when I run the script, as an administrator, it does not pass the parameter.

I'm trying the command in the link below, but with no success:
run-script-within-batch-file-with-parameters

Command that executes the script, as an administrator, via batch file:

PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File "D:\z_Batchs e Scripts\Batchs\Normaliza_LUFS\ArqsNorms_LUFS_pass.ps1' '%_vLUF%'  -Verb RunAs}" 

The %_vLUF% is the parameter to be passed.

Error message:

No line:1 character:4
+ & {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolic ...
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Start-Process], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.StartProcessCommand

Command in powershell script to receive the parameter:

Param(
     [decimal]$env:_vLUF
)

What could be wrong, the command in the batch file or in the powershell script?

Test:
When the script is executed, without being an administrator, via batch file and the Parameter in the powershell script is defined as:

Parameter in powershell:

Param(
     [decimal]$env:_vLUF
)

Command in the batch file running the script without being an administrator:

powershell.exe -executionpolicy remotesigned -File "D:\z_Batchs e Scripts\Batchs\Normaliza_LUFS\ArqsNorms_LUFS_pass.ps1" %_vLUF%

Note:
No need to use a named argument with the target parameter name.

Result: enter image description here

Conclusion:
When the script is running, without being an administrator, via a batch file it works correctly even if the parameter used in the script is defined as an environment parameter, eg: [decimal]$env:_vLUF and regardless of the parameter value being negative, eg : -11.0.

Why Powershell when running a script without being as an administrator correctly interprets the minus sign in the argument and when run as an administrator it does not interpret the minus sign correctly is a question I leave to the experts!

However, my question was very well answered by Mr. @mklement0.


Solution

  • Your .ps1 script's parameter declaration is flawed:

    Param(
         [decimal]$env:_vLUF  # !! WRONG - don't use $env:
    )
    

    See the bottom section for more information.

    It should be:

    Param(
         [decimal] $_vLUF  # OK - regular PowerShell variable
    )
    

    Parameters in PowerShell are declared as regular variables, not as environment variables ($env:).

    (While environment variables can be passed as an argument (parameter value), an alternative is to simply reference them by name directly in the body of your script.)


    Your PowerShell CLI call has problems too, namely with quoting.

    Try the following instead:

    powershell -NoProfile -ExecutionPolicy Bypass -Command "Start-Process -Verb RunAs powershell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File \"D:\z_Batchs e Scripts\Batchs\Normaliza_LUFS\ArqsNorms_LUFS_pass.ps1\" -_vLUF %_vLUF%'"
    

    Specifically:

    • Embedded " chars. must be escaped as \" (sic) when using the Windows PowerShell CLI (powershell.exe); however, given that %_vLUF% represents a [decimal], you needn't quote it at all.

      • However, you appear to have hit a bug that affects PowerShell versions up to at least 7.2.4 (current as of this writing): if the argument starts with -, such as in negative number -11.0, the -File CLI parameter invariably interprets it as a parameter name - even quoting doesn't help. See GitHub issue #17519.

      • The workaround, as used above is to use a named argument, i.e. to precede the value with the target parameter name: -_vLUF %_vLUF%

    • As an aside: There's no reason to use & { ... } in order to invoke code passed to PowerShell's CLI via the -Command (-c) parameter - just use ... directly, as shown above. Older versions of the CLI documentation erroneously suggested that & { ... } is required, but this has since been corrected.


    As for the broken attempt to use [decimal]$env:_vLUF as a parameter declaration:

    Param(
         [decimal]$env:_vLUF  # !! EFFECTIVELY IGNORED
    )
    

    is effectively ignored.

    However, if an environment variable _vLUF happens to be defined, it is accessible in the body of a script, independently of which parameters, if any, have been passed.

    • In direct invocation of your .ps1 script from your batch file, _vLUF indeed exists as an environment variable, because in cmd.exe (the interpreter of batch files), variables are invariably also environment variables - unlike in PowerShell.

      • That is, if %_vLUF% has a value in your batch file, a powershell child process you launch from it automatically sees it as $env:_vLUF
    • By contrast, if you launch an elevated process via Start-Process from such a PowerShell child process, that new, elevated process does not see the caller's environment variables - by security-minded design.

    Note:

    • That PowerShell even syntactically accepts [decimal]$env:_vLUF as a parameter declaration should be considered a bug.

    • What happens is that a regular variable named env:_vLUF is indeed created and bound, if an argument passed to it, but on trying to get the value of that variable in the body of your script, it is preempted by the environment variable.

      • As such, an invocation can break, namely if the parameter is type-constrained and you pass a value that cannot be converted to that type ([decimal] in the case at hand).

      • If the invocation doesn't break, the type constraint is ignored: $env:_vLUF is invariably of type [string], as all environment variables are.