PowerShell: how to capture (or suppress) write-host

后端 未结 3 1987
清酒与你
清酒与你 2021-01-20 00:37

I have a script call \"a.ps1\":

write-host \"hello host\"
\"output object\"

I want to call the script and obtain the output object, but I a

相关标签:
3条回答
  • 2021-01-20 00:41

    The output object i.e. "output object" is output to standard output. So I don't think you want to suppress standard output. If you don't want anything printed to the console don't use Write-Host as that bypasses all streams (stdout, stderr, warning, verbose, debug) and displays directly to the host. There is currently no easy mechanism I'm aware of to redirect host output.

    BTW why do you need to write "hello host" to the console if you don't want to see it displayed later?

    0 讨论(0)
  • 2021-01-20 00:45

    OK, I did a little digging over it. You can use:

    The Following Link

    And do:

    $result = .\1.ps1 | Select-WriteHost -Quiet
    $result[1]
    

    And then select the second object in the variable:

    Another explanation

    You can also change the script in a way that will not change Write-Host to Write-Output and just "remove" the Write-Host.

    Done...

    function Remove-WriteHost
    {
       [CmdletBinding(DefaultParameterSetName = 'FromPipeline')]
       param(
         [Parameter(ValueFromPipeline = $true, ParameterSetName = 'FromPipeline')]
         [object] $InputObject,
    
         [Parameter(Mandatory = $true, ParameterSetName = 'FromScriptblock', Position = 0)]
         [ScriptBlock] $ScriptBlock
       )
    
       begin
       {
         function Cleanup
         {
           # Clear out our proxy version of Write-Host
           remove-item function:\write-host -ea 0
         }
    
         function ReplaceWriteHost([string] $Scope)
         {
             Invoke-Expression "function ${scope}:Write-Host { }"
         }
    
         Cleanup
    
         # If we are running at the end of a pipeline, need to
         # immediately inject our version into global scope,
         # so that everybody else in the pipeline uses it.
         #
         # This works great, but it is dangerous if we don't
         # clean up properly.
         if($pscmdlet.ParameterSetName -eq 'FromPipeline')
         {
            ReplaceWriteHost -Scope 'global'
         }
       }
    
       process
       {
          # If a scriptblock was passed to us, then we can declare
          # our version as local scope and let the runtime take it
          # out of scope for us. It is much safer, but it won't
          # work in the pipeline scenario.
          #
          # The scriptblock will inherit our version automatically
          # as it's in a child scope.
          if($pscmdlet.ParameterSetName -eq 'FromScriptBlock')
          {
            . ReplaceWriteHost -Scope 'local'
            & $scriptblock
          }
          else
          {
             # In a pipeline scenario, just pass input along
             $InputObject
          }
       }
    
       end
       {
          Cleanup
       }
    }
    $result = .\1.ps1 | Remove-WriteHost
    

    Thanks to "latkin" for the original function :)

    0 讨论(0)
  • 2021-01-20 01:00

    There really is no easy way to do this.

    A workaround is to override the default behavior of Write-Host by defining a function with the same name:

    function global:Write-Host() {}
    

    This is very flexible. And it works for my simplistic example above. However, for some unknown reason, it doesn't work for the real case where I wanted to apply (maybe because the called script is signed and for security reasons it doesn't allow caller to arbitrarily change the behavior).

    Another way I tried was to modify the underlying Console's stdout by:

    $stringWriter = New-Object System.IO.StringWriter
    [System.Console]::SetOut($stringWriter)
    [System.Console]::WriteLine("HI") # Outputs to $stringWriter
    Write-Host("HI") # STILL OUTPUTS TO HOST :(
    

    But as you can see, it still doesn't work.

    0 讨论(0)
提交回复
热议问题