1

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

4
  • 3
    The display formatter has rules for different object types. If you are sending the output to something that can read PowerShell objects, then there should be no issues. If you are trying to turn your output into strings first and remove blank lines, then your commands will need to be combined into an expression, converted into string elements, and then filtered -> ($(dir *.xml;echo 1) | Out-String -Stream) -ne ''. I would say this is not really PowerShell idiomatic. There's probably a better way to tackle this whole problem if you state the overall goal in the question. Commented Aug 30, 2021 at 12:53
  • @AdminOfThings Thanks, but I have a little problem with that solution - If all I do is to echo, using that template ($(echo a) | Out-String -Stream) -ne '', a is not printed and True is, I supposed because a is indeed not equal to ''. Why hasn't that occur when dir was there too? Is there any workaround to always just get the desired output? Commented Aug 30, 2021 at 16:42
  • 2
    This is because when a scalar is the left-hand side of a comparison operator, a boolean is returned. When the LHS is an array, only the elements that are true returned. You would need to force the array in all cases -> @($(dir *.xml;echo 1) | Out-String -Stream) -ne ''. Commented Aug 30, 2021 at 18:18
  • @AdminOfThings That solved everything, thanks! Commented Aug 31, 2021 at 8:14

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.