如何向 PowerShell ps1文件传递命令行参数

多年来,我一直使用 cmd/DOS/Windows shell 并将命令行参数传递给批处理文件。例如,我有一个文件 zuzu.bat,在这个文件中,我访问 %1%2等等。现在,我想在调用 PowerShell脚本 when I am in a Cmd.exe shell时执行相同的操作。我有一个脚本 xuxu.ps1(我已经将 PS1添加到我的 PATHEXT 变量中,并将 PS1文件与 PowerShell 相关联)。但无论我做什么,我似乎无法从 $args变量得到任何东西。它的长度总是为0。

如果我使用的是 PowerShell shell,而不是 cmd.exe,那么它可以工作(当然)。但是,我还没有完全适应 PowerShell 环境。我不想打 powershell.exe -command xuxu.ps1 p1 p2 p3 p4。我想输入 xuxu p1 p2 p3 p4

这可能吗? 如果可能,怎么做?

我无法得到的样本是微不足道的,foo.ps1:

Write-Host "Num Args:" $args.Length;
foreach ($arg in $args) {
Write-Host "Arg: $arg";
}

结果总是这样:

C:\temp> foo
Num Args: 0
C:\temp> foo a b c d
Num Args: 0
c:\temp>
330268 次浏览

OK, so first this is breaking a basic security feature in PowerShell. With that understanding, here is how you can do it:

  1. Open an Windows Explorer window
  2. Menu Tools -> Folder Options -> tab File Types
  3. Find the PS1 file type and click the advanced button
  4. Click the New button
  5. For Action put: Open
  6. For the Application put: "C:\WINNT\system32\WindowsPowerShell\v1.0\powershell.exe" "-file" "%1" %*

You may want to put a -NoProfile argument in there too depending on what your profile does.

Maybe you can wrap the PowerShell invocation in a .bat file like so:

rem ps.bat
@echo off
powershell.exe -command "%*"

If you then placed this file under a folder in your PATH, you could call PowerShell scripts like this:

ps foo 1 2 3

Quoting can get a little messy, though:

ps write-host """hello from cmd!""" -foregroundcolor green

You may not get "xuxu p1 p2 p3 p4" as it seems. But when you are in PowerShell and you set

PS > Set-ExecutionPolicy Unrestricted -Scope CurrentUser

You can run those scripts like this:

./xuxu p1 p2 p3 p4

or

.\xuxu p1 p2 p3 p4

or

./xuxu.ps1 p1 p2 p3 p4

I hope that makes you a bit more comfortable with PowerShell.

This article helps. In particular, this section:

-File

Runs the specified script in the local scope ("dot-sourced"), so that the functions and variables that the script creates are available in the current session. Enter the script file path and any parameters. File must be the last parameter in the command, because all characters typed after the File parameter name are interpreted as the script file path followed by the script parameters.

i.e.

powershell.exe -File "C:\myfile.ps1" arg1 arg2 arg3

means run the file myfile.ps1 and arg1 arg2 & arg3 are the parameters for the PowerShell script.

You could declare your parameters in the file, like param:

[string]$param1
[string]$param2

And then call the PowerShell file like so .\temp.ps1 param1 param2....param10, etc.

After digging through the PowerShell documentation, I discovered some useful information about this issue. You can't use the $args if you used the param(...) at the beginning of your file; instead you will need to use $PSBoundParameters. I copy/pasted your code into a PowerShell script, and it worked as you'd expect in PowerShell version 2 (I am not sure what version you were on when you ran into this issue).

If you are using $PSBoundParameters (and this ONLY works if you are using param(...) at the beginning of your script), then it is not an array, it is a hash table, so you will need to reference it using the key / value pair.

param($p1, $p2, $p3, $p4)
$Script:args=""
write-host "Num Args: " $PSBoundParameters.Keys.Count
foreach ($key in $PSBoundParameters.keys) {
$Script:args+= "`$$key=" + $PSBoundParameters["$key"] + "  "
}
write-host $Script:args

And when called with...

PS> ./foo.ps1 a b c d

The result is...

Num Args:  4
$p1=a  $p2=b  $p3=c  $p4=d

if you want to invoke ps1 scripts from cmd and pass arguments without invoking the script like

powershell.exe script.ps1 -c test
script -c test ( wont work )

you can do the following

setx PATHEXT "%PATHEXT%;.PS1;" /m
assoc .ps1=Microsoft.PowerShellScript.1
ftype Microsoft.PowerShellScript.1=powershell.exe "%1" %*

This is assuming powershell.exe is in your path

https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/ftype