Private/Select-WriteHost.ps1
function Select-WriteHost { <# .SYNOPSIS Captures Write-Host output to standard output stream .DESCRIPTION Creates a proxy function for Write-Host and redirects the console output to the standard output stream. .PARAMETER InputObject The input object parameter corresponds to in-line values passed from the pi- peline. .PARAMETER ScriptBlock The script block parameter corresponds to the script to capture. .PARAMETER Quiet The quiet parameter is a flag whether the Write-Host output should be sup- pressed or kept. .INPUTS [System.Objects] Select-WriteHost accepts objects from the pipeline. .OUTPUTS [System.String] Select-WriteHost returns a string. .EXAMPLE $Output = 1..10 | % { Write-Host $_ } | Select-WriteHost In this example, Select-WriteHost will store the list of numbers from one to 10 into the $Output variable but still output the results to the console. .EXAMPLE $Output = 1..10 | % { Write-Host $_ } | Select-WriteHost -Quiet In this example, Select-WriteHost will store the list of numbers from one to 10 into the $Output variable and suppress the console output. .EXAMPLE $Output = Select-WriteHost -ScriptBlock { 1..10 | % { Write-Host $_ } } -OutputFile "test" In this example, Select-WriteHost will store the list of numbers from one to 10 into the $Output variable but still output the results to the console. .EXAMPLE $Output = Select-WriteHost -ScriptBlock { 1..10 | % { Write-Host $_ } } -OutputFile "test" -Quiet In this example, Select-WriteHost will store the list of numbers from one to 10 into the $Output variable and suppress the console output. .NOTES File name: Select-WriteHost.ps1 Author: Florian Carrier Creation date: 2018-10-16 Last modified: 2018-10-16 Credit: @LincolnAtkinson .LINK http://www.latkin.org/blog/2012/04/25/how-to-capture-or-redirect-write-host-output-in-powershell/ #> [CmdletBinding (DefaultParameterSetName = "FromPipeline")] Param ( [Parameter ( ValueFromPipeline = $true, ParameterSetName = "FromPipeline", HelpMessage = "In-line script input to capture" )] [Object] $InputObject, [Parameter ( Position = 1, Mandatory = $true, ParameterSetName = "FromScriptblock", HelpMessage = "Script to capture" )] [ScriptBlock] $ScriptBlock, [Parameter ( Position = 2, Mandatory = $false, ParameterSetName = "FromScriptblock", HelpMessage = "Path to the output file" )] [String] $OutputFile, [Parameter ( HelpMessage = "Define if console output has to be suppressed" )] [Switch] $Quiet ) Begin { function Unregister-WriteHost { # Clear out the proxy version of Write-Host Remove-Item Function:Write-Host -ErrorAction 0 } function Edit-WriteHost ([String] $Scope, [Switch] $Quiet) { # Create a proxy for Write-Host $MetaData = New-Object -TypeName "System.Management.Automation.CommandMetaData" (Get-Command -Name "Microsoft.PowerShell.Utility\Write-Host") $Proxy = [System.Management.Automation.ProxyCommand]::Create($MetaData) # Amend its behaviour $Content = if ($Quiet) { # In quiet mode, whack the entire function body, simply pass input di- # rectly to the pipeline $Proxy -replace '(?s)\bbegin\b.+', '$Object' } else { # In default mode, pass input to the pipeline, but allow real Write-Host # to process as well $Proxy -replace '($SteppablePipeline.Process)', '$Object; $1' } # load our version into the specified scope Invoke-Expression "Function ${Scope}:Write-Host { $Content }" } Unregister-WriteHost # If we are running at the end of a pipeline, need to immediately inject the # proxy into global scope, so that everybody else in the pipeline uses it. # This works great, but dangerous if we don't clean up properly. if ($PSCmdlet.ParameterSetName -eq "FromPipeline") { Edit-WriteHost -Scope "global" -Quiet:$Quiet } } Process { if ($PSCmdlet.ParameterSetName -eq "FromScriptBlock") { # If a scriptblock was passed to us, then we can declare the proxy as # local scope and let the runtime take it out of scope for us. # The scriptblock will inherit the proxy automatically as it's in a child # scope. . Edit-WriteHost -Scope "local" -Quiet:$Quiet if ($OutputFile) { & $Scriptblock | Out-File -FilePath $OutputFile -Encoding "UTF8" -Append } else { & $Scriptblock } } else { # In pipeline scenario, just pass input along if ($OutputFile) { $InputObject | Out-File -FilePath $OutputFile -Encoding "UTF8" -Append } else { $InputObject } } } End { Unregister-WriteHost } } |