Powershell echo vs write-host and different outputs

11,435

Solution 1

In PowerShell, echo maps to Write-Output instead of Write-Host. If you want to output the objects resulting from some operation, you should be outputting them instead of attempting to Write-Host. Content written via Write-Host doesn't make it to the output stream, so you can't (for example) use it in subsequent calls or pipes.

You see that nasty garbled output with Write-Host because it is trying to write the whole object out, and doesn't understand that you would probably prefer a nice table with cleanly listed properties. You should reserve Write-Host for when you need to convey some simple information to the user that you don't mind being consumed, and even then there may be better alternatives like Write-Debug or Write-Verbose.

More info here.

You can always check mappings like this by calling a cmdlet with Help or Get-Help:

PS C:\> help echo

NAME
    Write-Output

Solution 2

The Write-Host cmdlet outputs to the host (i.e. the powershell or ISE window). It accepts an object as input and simply calls the .ToString() method of the object (or if it is an array it calls .ToString() or each element of the array.

Write-Output or its alias echo simply writes the input object to the current pipeline. Any objects that reach the end of the pipeline are then returned from the current function, cmdlet or script if there is one (where they may then continue down some other pipeline). Eventually objects may reach the end of a pipeline not inside a function, cmdlet or script and it appears they are output to the host. What actually happens is that at the end of the outermost pipeline all the objects are sent to an extra hidden cmdlet: Out-Default.

Out-Default sends the objects to the default formatter and then the default output cmdlet. It is the default formatter that converts your disk objects into a bunch of FormatStartData, GroupStartData, FormatEntryData, GroupEndData, and FormatEndData objects (pipe the output of something like Format-Table into Get-Member to see these objects). Finally the format objects are what get sent to the host to produce the formatted output.

If you want a bit of fun try redefining Out-Default so you can see where it is called:

PS C:\scripts> function Out-Default {
>>   Write-Verbose "Called Out-Default" -Verbose
>>   $input | Format-Table | Out-Host
>> }
>>
PS C:\scripts> cd mod2
VERBOSE: Called Out-Default
PS C:\scripts\mod2> ls
VERBOSE: Called Out-Default


    Directory: C:\scripts\mod2


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        29/12/2013     11:00        308 1Var.ps1
-a---        29/12/2013     11:00        326 2Quotes.ps1
-a---        29/12/2013     11:00        416 3ObjectMembers.ps1
-a---        29/12/2013     11:00        665 4Parenthesis.ps1
-a---        29/12/2013     11:00        392 5If.ps1
-a---        29/12/2013     11:00        325 6Switch.ps1
-a---        29/12/2013     11:00        226 7Do_While.ps1
-a---        29/12/2013     11:00        272 8For_Foreach.ps1
-a---        29/12/2013     11:00        150 _Startup.ps1
Share:
11,435

Related videos on Youtube

Admin
Author by

Admin

Updated on September 14, 2022

Comments

  • Admin
    Admin over 1 year

    I am trying to write my first script but am having some issues with powershell.

    I am using the following code:

    $Disk = Get-Disk | Where-Object {$_.Path -match "USBSTOR" -and $_.Size -gt 20Gb -and $_.Size -lt 200Gb -and -not $_.IsBoot }
    

    I can't figure out why

    PS C:\> echo $disk
    Number Friendly Name                            OperationalStatus                    Total Size Partition Style
     ------ -------------                            -----------------                    ---------- ---------------
    1      Imation IronKey Wkspace USB Device       Online                                 59.63 GB MBR
    

    and

    PS C:\> write-host $disk
    MSFT_Disk (ObjectId = "\\?\usbstor#disk&ven_imation&prod_ironk...)
    

    It is more complicated by the following powershell script:

    $Disk = Get-Disk | Where-Object {$_.Path -match "USBSTOR" -and $_.Size -gt 20Gb -and $_.Size -lt 200Gb -and -not $_.IsBoot }
    $WIM = Get-PSDrive -PSProvider FileSystem | Where { Test-Path (join-path $_.Root "\sources\install.wim") }
    echo $Disk
    echo $WIM
    Write-Host $WIM
    Write-Host $Disk
    

    and then change the order of the echo's and writes I get different outputs

    can someone explain what is going on?