【问题标题】:PowerShell: how to capture (or suppress) write-hostPowerShell:如何捕获(或抑制)写主机
【发布时间】:2013-01-06 09:57:48
【问题描述】:

我有一个脚本调用“a.ps1”:

write-host "hello host"
"output object"

我想调用脚本获取输出对象,但我也想抑制标准输出:

$result = .\a.ps1
# Don't want anything printed to the console here

有什么提示吗?

【问题讨论】:

    标签: powershell


    【解决方案1】:

    好的,我稍微挖掘了一下。您可以使用:

    The Following Link

    然后做:

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

    然后选择变量中的第二个对象:

    Another explanation

    您还可以以一种不会将 Write-Host 更改为 Write-Output 的方式更改脚本,而只是“删除” Write-Host。

    完成...

    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
    

    感谢“latkin”的原始功能:)

    【讨论】:

    • 您的解决方案基本上是覆盖写入主机。如果对 write-host 的调用是名称限定的,则它不起作用。不是通用解决方案。
    【解决方案2】:

    确实没有简单的方法来做到这一点。

    一种解决方法是通过定义一个具有相同名称的函数来覆盖 Write-Host 的默认行为:

    function global:Write-Host() {}
    

    这是非常灵活的。它适用于我上面的简单示例。但是,由于某些未知原因,它不适用于我想要应用的真实案例(可能是因为被调用的脚本已签名,并且出于安全原因,它不允许调用者任意更改行为)。

    我尝试的另一种方法是通过以下方式修改底层控制台的标准输出:

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

    但是如你所见,它仍然不起作用。

    【讨论】:

      【解决方案3】:

      输出对象,即"output object" 被输出到standard output。所以我不认为你想抑制标准输出。如果你不想在控制台打印任何东西,不要使用Write-Host as绕过所有流(stdout、stderr、警告、详细、调试)并直接显示到主机。目前我知道没有简单的机制来重定向主机输出。

      顺便说一句,如果您不想稍后看到它显示,为什么需要将“hello host”写入控制台?

      【讨论】:

      • 在这种情况下,您可以尝试 Start-Transcript & Stop-Transcript 但请注意它不会捕获 EXE 输出。
      猜你喜欢
      • 2018-11-28
      • 1970-01-01
      • 2017-05-01
      • 2018-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多