PowerShell和cmd返回不同的结果

时间:2018-06-02 15:33:36

标签: powershell cmd

为什么这些结果不同?我对cmd命令缺少什么?

PS C:\src\t\cad> Get-ChildItem -Directory -Recurse -Path $Env:ProgramFiles -ErrorAction SilentlyContinue | Measure-Object

Count    : 17381

来自cmd.exe:

10:28:18.87  C:\src\t\cad
C:>powershell -NoProfile -Command "Get-ChildItem -Directory -Recurse -Path '"%ProgramFiles%"' -ErrorAction SilentlyContinue ^| Measure-Object"

Count    : 0

3 个答案:

答案 0 :(得分:3)

这是因为插入符^而发生的。您正在尝试为命令解释器转义管道|,但您不需要因为它已经在带引号的字符串中,因此它不会被解释并直接发送到PowerShell。

因此,PowerShell看到了这一点:

Get-ChildItem -Directory -Recurse -Path 'C:\Program Files' -ErrorAction SilentlyContinue ^| Measure-Object

那为什么不起作用?

PowerShell命令的参数由空格分隔,如果参数未具体命名,则在可能的情况下按位置处理。

让我们看一个更简单的例子来证明:

Get-ChildItem -Path . ^

同样地,你会看到没有输出,但有了跟踪,我们可以看到原因:

Trace-Command -Name ParameterBinding -Expression { Get-ChildItem -Path . ^ } -PSHost
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Get-ChildItem]
DEBUG: ParameterBinding Information: 0 :     BIND arg [.] to parameter [Path]
DEBUG: ParameterBinding Information: 0 :         COERCE arg to [System.String[]]
DEBUG: ParameterBinding Information: 0 :             Trying to convert argument value from System.String to
System.String[]
DEBUG: ParameterBinding Information: 0 :             ENCODING arg into collection
DEBUG: ParameterBinding Information: 0 :             Binding collection parameter Path: argument type [String],
parameter type [System.String[]], collection type Array, element type [System.String], coerceElementType
DEBUG: ParameterBinding Information: 0 :             Creating array with element type [System.String] and 1 elements
DEBUG: ParameterBinding Information: 0 :             Argument type String is not IList, treating this as scalar
DEBUG: ParameterBinding Information: 0 :             COERCE arg to [System.String]
DEBUG: ParameterBinding Information: 0 :                 Parameter and arg types the same, no coercion is needed.
DEBUG: ParameterBinding Information: 0 :             Adding scalar element of type String to array position 0
DEBUG: ParameterBinding Information: 0 :         BIND arg [System.String[]] to param [Path] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Get-ChildItem]
DEBUG: ParameterBinding Information: 0 :     BIND arg [^] to parameter [Filter]
DEBUG: ParameterBinding Information: 0 :         BIND arg [^] to param [Filter] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : BIND cmd line args to DYNAMIC parameters.
DEBUG: ParameterBinding Information: 0 :     DYNAMIC parameter object:
[Microsoft.PowerShell.Commands.GetChildDynamicParameters]
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Get-ChildItem]
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing

该插入符号位于-Filter参数的位置。 似乎过滤相当宽松,因为它不关心这个值是无意义的;我想它只是将它视为不匹配而且不会抛出错误

根据mklement0的评论:

  

^在技术上是有效的文件名,-Filter接受文件名   (模式);因此,如果你有一个名为^的文件,那就是。{   匹配。使用非法的文件名字符(因字符而异)   平台)确实打破了,虽然错误消息的帮助   而变化。

所以-Filter ^所拥有的是一个永不匹配的过滤器,因此结果为0。

答案 1 :(得分:1)

我认为-ErrorAction SilentlyContinue正在抑制第一个命令中的错误,因此没有任何内容传递到管道Measure-Object

在PSCore上测试这个我得到:

pwsh -command "get-process ^| measure-object"
get-process : Cannot find a process with the name "^".
Count    : 0

但删除&​​#39; ^'字符:

bash-3.2$ pwsh -command "get-process | measure-object"
Count    : 318

所以我认为对于Windows PowerShell来说是一样的。尝试没有^

powershell -NoProfile -Command "Get-ChildItem -Directory -Recurse -Path '"%ProgramFiles%"' -ErrorAction SilentlyContinue | Measure-Object"

答案 2 :(得分:1)

使用cmd.exe视角来补充briantist's helpful answer

  • cmd.exe中,^仅用作未加引号字符串中的转义字符。

  • 内部双引号字符串("..."):

    • 需要转义的字符本身为"
    • ^没有特殊含义,并按原样保留。

鉴于您打算传递给PowerShell的|字符位于"..."内,因此您不必 - 也不能 - 使用^来逃避它。