Reputation: 110
I tried to make a one liner that executes a command and than prints out a message, for example:
dir; echo 1
which outputs:
PS C:\Users\Administrator\Documents> dir; echo 1
Directory: C:\Users\Administrator\Documents
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 8/18/2021 3:27 PM a
d----- 8/18/2021 3:27 PM vdb.1_1.dir
-a---- 8/30/2021 2:48 PM 12 a.txt
-a---- 8/30/2021 2:54 PM 2044 dir.txt
-a---- 8/30/2021 10:31 AM 8 hey.txt
1
PS C:\Users\Administrator\Documents>
When running only dir
, there are two blank lines at the end:
PS C:\Users\Administrator\Documents> dir
Directory: C:\Users\Administrator\Documents
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 8/18/2021 3:27 PM a
d----- 8/18/2021 3:27 PM vdb.1_1.dir
-a---- 8/30/2021 2:48 PM 12 a.txt
-a---- 8/30/2021 2:54 PM 2044 dir.txt
-a---- 8/30/2021 10:31 AM 8 hey.txt
PS C:\Users\Administrator\Documents>
But the combination of two commands seems to ruin the order (The '1' is printed before the two blank lines).
When I ran other versions the problem did not occur, even when the first command printed blank lines:
PS C:\Users\Administrator\Documents> echo 0; echo 1
0
1
PS C:\Users\Administrator\Documents>
PS C:\Users\Administrator\Documents> echo hello`n`n; echo 1
hello
1
PS C:\Users\Administrator\Documents>
What causes it? Does it happen with other commands too (besides ls
, Get-ChildItem
or other aliases)? How can I bypass that (the output is supposed to go to a script that assumes the message is at the end)?
** I'm running Windows server 2019, PowerShell version 5.1.17763.316
Upvotes: 1
Views: 197
Reputation: 21468
It's the display-formatter
output. What you see on screen is the default visual representation of an object's value, not exactly what that object's value is. Simpler, more primitive types might simply display True
, 1
, or the value of a string
when the variable displays to the console. More complex types will show a formatted output, often (but not always) formatted as a table or a grouped list of properties per object.
It's recommended to operate on objects and member values themselves instead of the formatted output that gets written to console, but there are some cases (e.g. regression testing your own class) where the latter is desirable. If you want to do this, you first need to pipe the cmdlet to Out-String
, and then you can inspect the output.
$gciFormatOutput = Get-ChildItem | Out-String
# Here you can inspect the formatted output of Get-ChildItem how you need
However, parsing this to get, say, the full path to the files in a directory is not recommended. Most of the time you'd want to do something like this:
# -File omits directories from the final output in this example
$filePathsInFolder = ( Get-ChildItem $someDir -File ).FullName
( Get-ChildItem $someDir -File )
runs first because of order of operations; expressions nested in parentheses ()
are evaluated first. We can then directly invoke the FullName
property of any returned files from the previous expression and we get a list of all of the files in that directory. This is a much cleaner approach than parsing the formatted display output of Get-ChildItem
, and showcases the power of working with objects over strings in PowerShell.
However, the way you're talking, it sounds like you are concerned with inconsistency when evaluating the output of external commands, for example, ping.exe
, tracert.exe
, etc. (these are poor examples since PS has built-in cmdlets for these functions). If you need to inspect the result of a command's output, you will get one or more strings returned (one string per line of output by default) and you can be certain that the command will return exactly the same lines of output. Consider this ping
example:
$output = & ping google.com -n 1
"Ping Succeeded: $($output[2] -match '^Reply'")
We ping google.com
, the third line if successful will begin with Reply
if the ping succeeded. This is a rudimentary example and one that can be better done with PowerShell cmdlets but I hope you get the gist of processing command output.
Worthy to note: all external commands (anything that isn't part of PowerShell itself) returns strings for the output; you don't have to worry about these being transformed by PowerShell in some funky, unexpected way.
Upvotes: 3