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.