Tag Archives: Test-TMWriteOutputVsHost

Write-Host, Does it Have a Place?

I’ve been working on an advanced function that I can’t wait to share (and no, it’s not the one in this post). I really think it’s something that the Windows PowerShell community has been missing. Okay fine, maybe it’s just something I’ve been missing.

I noticed in development that my Write-Output messages to the user were crossing the pipeline, when the custom object (created by the function), was passed to Select-Object (in certain manners). I have a function below that does the same thing as the one in development.

Here’s how this thing works: The function requires the user to provide the value Write-Output (or, wo), or Write-Host (or, wh) for the -Option parameter. This will determine how the message to the user is written inside the Begin block. The only other thing that’s happening in this function, is that a custom object is being created in the Process block, based on some properties of Win32_BIOS.

Function Test-TMWriteOutputVsHost {
    [CmdletBinding()]
    Param (
    [Parameter(Mandatory=$true,
        HelpMessage="Enter Write-Output or Write-Host")]
    [ValidateSet('Write-Output','wo','Write-Host','wh')]
    [string]$Option
    )

    Begin {
        If ($Option -eq 'Write-Output' -or $Option -eq 'wo') {
            Write-Output 'Inside the Begin block (using Write-Output).'

        } ElseIf ($Option -eq 'Write-Host' -or $Option -eq 'wh') {
            Write-Host 'Inside the Begin block (using Write-Host).'
        }
    } # End Begin

    Process {
        $CollectionVariable = Get-WmiObject -Class Win32_BIOS
        $Object = @()
        $Object += [pscustomobject]@{
            Manufacturer = $CollectionVariable.Manufacturer;
            Name = $CollectionVariable.Name;
            Version = $CollectionVariable.Version
        }
    } # End Process

    End {
        Write-Output $Object
    }
    # End, End
} # End Function

As we can see below, everything works great with both Write-Output or Write-Host, when we don’t pipe the function to the Select-Object cmdlet.

PS C:\> Test-TMWriteOutputVsHost -Option Write-Output
Inside the Begin block (using Write-Output).

Manufacturer                            Name                                    Version
------------                            ----                                    -------
Dell Inc.                               BIOS Date: 08/27/13 11:12:44 Ver: A1... DELL   - 1072009

PS C:\> Test-TMWriteOutputVsHost -Option Write-Host
Inside the Begin block (using Write-Host).

Manufacturer                            Name                                    Version
------------                            ----                                    -------
Dell Inc.                               BIOS Date: 08/27/13 11:12:44 Ver: A1... DELL   - 1072009

Now, let’s pipe our object to some variations of the Select-Object cmdlet and watch some things blow up (when using Write-Output).

PS C:\> # Use the horizontal scrollbar to see the results...
PS C:\> Test-TMWriteOutputVsHost -Option Write-Output | select *

                                                                                                                 Length
                                                                                                                 ------
                                                                                                                     44

PS C:\> Test-TMWriteOutputVsHost -Option Write-Output | select Name,Ver*

Name                                                        Ver*
----                                                        ----

BIOS Date: 08/27/13 11:12:44 Ver: A13.00

PS C:\> Test-TMWriteOutputVsHost -Option Write-Host | select *
Inside the Begin block (using Write-Host).

Manufacturer                            Name                                    Version
------------                            ----                                    -------
Dell Inc.                               BIOS Date: 08/27/13 11:12:44 Ver: A1... DELL   - 1072009

PS C:\> Test-TMWriteOutputVsHost -Option Write-Host | select Name,Ver*
Inside the Begin block (using Write-Host).

Name                                                        Version
----                                                        -------
BIOS Date: 08/27/13 11:12:44 Ver: A13.00                    DELL   - 1072009

The problem with Write-Output, is that the object it’s producing is crossing our pipeline and causing unpredictable behavior—something we can’t include in a function we want to distribute. Here’s the proof: When we pipe our function to Get-Member, we reveal the objects that show up on the other side, and we don’t want the string object coming over with us.

PS C:\> Test-TMWriteOutputVsHost -Option Write-Output | Get-Member | Select-Object TypeName -Unique

TypeName
--------
System.String
System.Management.Automation.PSCustomObject

PS C:\> Test-TMWriteOutputVsHost -Option Write-Host | Get-Member | Select-Object TypeName -Unique
Inside the Begin block (using Write-Host).

TypeName
--------
System.Management.Automation.PSCustomObject

I don’t profess to know it all, so if there’s a way to get around this using Write-Output, then I’d love to hear about it. While I haven’t tried it, I suspect I may be able to create an embedded function—that might be the trick I need. Perhaps I’ll play with that option at another time. Thanks for reading!

Oh, and before someone mentions it, I explained how I feel about Write-Verbose in the comments on a post by Adam Bertram: http://www.adamtheautomator.com/use-write-host-lot.