Reputation: 16236
Why are these returning different results? What am I missing about the cmd command?
PS C:\src\t\cad> Get-ChildItem -Directory -Recurse -Path $Env:ProgramFiles -ErrorAction SilentlyContinue | Measure-Object
Count : 17381
And from 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
Upvotes: 2
Views: 348
Reputation: 110
I think the -ErrorAction SilentlyContinue
is suppressing an error in the first command so then nothing is being passed down the pipeline to Measure-Object
.
Testing this on PSCore I get:
pwsh -command "get-process ^| measure-object"
get-process : Cannot find a process with the name "^".
Count : 0
But removing the '^' character:
bash-3.2$ pwsh -command "get-process | measure-object"
Count : 318
So I assume that's the same for Windows PowerShell. Try without the ^
powershell -NoProfile -Command "Get-ChildItem -Directory -Recurse -Path '"%ProgramFiles%"' -ErrorAction SilentlyContinue | Measure-Object"
Upvotes: 1
Reputation: 47792
This is happening because of the caret ^
. You are trying to escape the pipe |
for the command interpreter, but you don't need to because it's already in a quoted string, so it doesn't get interpreted and gets sent directly to PowerShell.
As a result, PowerShell sees this:
Get-ChildItem -Directory -Recurse -Path 'C:\Program Files' -ErrorAction SilentlyContinue ^| Measure-Object
So why doesn't that work?
Parameters to PowerShell commands are separated by spaces, and when a parameter is not named specifically it's treated positionally, if possible.
Let's look at a simpler example to demonstrate:
Get-ChildItem -Path . ^
Similarly you'll see no output, but with a trace, we can see why:
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
That caret was bound positionally to the -Filter
parameter. It seems the filtering is rather lenient in that it doesn't care if the value is nonsense; I guess it just treats it as non-matching and doesn't throw an error.
Per mklement0's comment:
^
is technically a valid filename, and-Filter
accepts filename (patterns); thus, if you had a file literally named^
, it would be matched. Using illegal-in-a-filename characters (which vary by platform) does break, though the helpfulness of the error messages varies.
So what you have with -Filter ^
is a filter that never matches, hence 0 results.
Upvotes: 3
Reputation: 437363
To complement briantist's helpful answer with the cmd.exe
perspective:
In cmd.exe
, ^
only serves as the escape character in unquoted strings.
Inside double-quoted strings ("..."
):
"
itself.^
has no special meaning and is retained as-is.Given that the |
character you intend to pass through to PowerShell is inside "..."
, you therefore need not - and must not - use ^
to escape it.
Upvotes: 1