简体   繁体   English

将 Write-Host 语句重定向到文件

[英]Redirect Write-Host statements to a file

I have a PowerShell script that I am debugging and would like to redirect all Write-Host statements to a file.我有一个正在调试的 PowerShell 脚本,我想将所有Write-Host语句重定向到一个文件。 Is there an easy way to do that?有没有简单的方法可以做到这一点?

Until PowerShell 4.0, Write-Host sends the objects to the host.在 PowerShell 4.0 之前, Write-Host将对象发送到主机。 It does not return any objects.它不返回任何对象。

Beginning with PowerShell 5.0 and newer, Write-Host is a wrapper for Write-Information , which allows to output to the information stream and redirect it with 6>> file_name .从 PowerShell 5.0 及更新版本开始, Write-HostWrite-Information的包装器,它允许输出到信息流并使用6>> file_name重定向它。

http://technet.microsoft.com/en-us/library/hh849877.aspx http://technet.microsoft.com/en-us/library/hh849877.aspx

However, if you have a lot of Write-Host statements, replace them all with Write-Log , which lets you decide whether output to console, file or event log, or all three.但是,如果您有很多Write-Host语句,请将它们全部替换为Write-Log ,这样您就可以决定是输出到控制台、文件还是事件日志,或者同时输出到这三者。

Check also:还要检查:

You can create a proxy function for Write-Host which sends objects to the standard output stream instead of merely printing them.您可以为Write-Host创建一个代理函数,它将对象发送到标准输出流,而不仅仅是打印它们。 I wrote the below cmdlet for just this purpose.为此,我编写了以下 cmdlet。 It will create a proxy on the fly which lasts only for the duration of the current pipeline.它将动态创建一个仅在当前管道持续时间内持续的代理。

A full writeup is on my blog here , but I've included the code below.完整的文章我的博客上,但我在下面包含了代码。 Use the -Quiet switch to suppress the console write.使用-Quiet开关抑制控制台写入。

Usage:用法:

PS> .\SomeScriptWithWriteHost.ps1 | Select-WriteHost | out-file .\data.log  # Pipeline usage
PS> Select-WriteHost { .\SomeScriptWithWriteHost.ps1 } | out-file .\data.log  # Scriptblock usage (safer)

function Select-WriteHost
{
   [CmdletBinding(DefaultParameterSetName = 'FromPipeline')]
   param(
     [Parameter(ValueFromPipeline = $true, ParameterSetName = 'FromPipeline')]
     [object] $InputObject,

     [Parameter(Mandatory = $true, ParameterSetName = 'FromScriptblock', Position = 0)]
     [ScriptBlock] $ScriptBlock,

     [switch] $Quiet
   )

   begin
   {
     function Cleanup
     {
       # Clear out our proxy version of write-host
       remove-item function:\write-host -ea 0
     }

     function ReplaceWriteHost([switch] $Quiet, [string] $Scope)
     {
         # Create a proxy for write-host
         $metaData = New-Object System.Management.Automation.CommandMetaData (Get-Command 'Microsoft.PowerShell.Utility\Write-Host')
         $proxy = [System.Management.Automation.ProxyCommand]::create($metaData)

         # Change its behavior
         $content = if($quiet)
                    {
                       # In quiet mode, whack the entire function body,
                       # simply pass input directly to the pipeline
                       $proxy -replace '(?s)\bbegin\b.+', '$Object'
                    }
                    else
                    {
                       # In noisy 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 }"
     }

     Cleanup

     # If we are running at the end of a pipeline, we 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 -Quiet:$quiet -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 -Quiet:$quiet -Scope 'local'
        & $scriptblock
      }
      else
      {
         # In a pipeline scenario, just pass input along
         $InputObject
      }
   }

   end
   {
      Cleanup
   }
}

You can run your script in a secondary PowerShell shell and capture the output like this:您可以在辅助 PowerShell shell 中运行脚本并捕获如下输出:

powershell -File 'Your-Script.ps1' > output.log

That worked for me.那对我有用。

Using redirection will cause Write-Host to hang.使用重定向将导致Write-Host挂起。 This is because Write-Host deals with various formatting issues that are specific to the current terminal being used.这是因为 Write-Host 处理特定于当前使用的终端的各种格式问题。 If you just want your script to have flexibility to output as normal (default to shell, with capability for > , 2> , etc.), use Write-Output .如果您只是希望您的脚本能够灵活地正常输出(默认为 shell,具有>2>等功能),请使用Write-Output

Otherwise, if you really want to capture the peculiarities of the current terminal, Start-Transcript is a good place to start.否则,如果您真的想捕捉当前终端的特性, Start-Transcript是一个不错的起点。 Otherwise you'll have to hand-test or write some complicated test suites.否则,您将不得不手动测试或编写一些复杂的测试套件。

This worked for me in my first PowerShell script that I wrote few days back:这在我几天前写的第一个 PowerShell 脚本中对我有用:

function logMsg($msg)
{
    Write-Output $msg
    Write-Host   $msg
}

Usage in a script:在脚本中的用法:

logMsg("My error message")
logMsg("My info message")

PowerShell script execution call: PowerShell 脚本执行调用:

ps> .\myFirstScript.ps1 >> testOutputFile.txt

It's not exactly answer to this question, but it might help someone trying to achieve both logging to the console and output to some log file, doing what I reached here:)这不是这个问题的确切答案,但它可能会帮助那些试图同时记录到控制台和输出到某个日志文件的人,做我在这里到达的事情:)

Try adding a asterisk * before the angle bracket > to redirect all streams:尝试在尖括号>之前添加星号*以重定向所有流:

powershell -File Your-Script.ps1 * > output.log powershell -File Your-Script.ps1 * > output.log

When stream redirection is requested, if no specific stream is indicated then by default only the Success Stream ( 1> ) is redirected.请求流重定向时,如果未指示特定流,则默认情况下仅重定向Success Stream ( 1> )。 Write-Host is an alias for Write-Information which writes to the Information Stream ( 6> ). Write-Host是写入Information Stream ( 6> ) 的Write-Information的别名。 To redirect all streams use *> .要重定向所有流,请使用*>

Powershell-7.1 supports redirection of multiple output streams: Powershell-7.1支持重定向多个输出流:

  • Success Stream (#1): PowerShell 2.0 Write-Output成功流(#1):PowerShell 2.0 Write-Output
  • Error Stream (#2): PowerShell 2.0 Write-Error错误流(#2):PowerShell 2.0 Write-Error
  • Warning Stream (#3): PowerShell 3.0 Write-Warning警告流(#3):PowerShell 3.0 Write-Warning
  • Verbose Stream (#4): PowerShell 3.0 Write-Verbose详细流 (#4):PowerShell 3.0 Write-Verbose
  • Debug Stream (#5): PowerShell 3.0 Write-Debug调试流 (#5):PowerShell 3.0 Write-Debug
  • Information Stream (#6): PowerShell 5.0 Write-Information信息流(#6):PowerShell 5.0 Write-Information
  • All Streams (*): PowerShell 3.0所有流 (*):PowerShell 3.0

If you have just a few Write-Host statements, you can use the "6>>" redirector operator to a file:如果您只有几个 Write-Host 语句,则可以对文件使用"6>>"重定向器运算符:

Write-Host "Your message." 6>> file_path_or_file_name

This is the "Example 5: Suppress output from Write-Host" provided by Microsoft, modified accordingly to about_Operators .这是微软提供的“Example 5: Suppress output from Write-Host” ,相应修改为about_Operators

Define a function called Write-Host.定义一个名为 Write-Host 的函数。 Have it write to a file.让它写入文件。 You may have some trouble if some invocations use a weird set of arguments.如果某些调用使用一组奇怪的参数,您可能会遇到一些麻烦。 Also, this will only work for invocations that are not Snapin qualified.此外,这仅适用于非 Snapin 限定的调用。

I just added Start-Transcript at the top of the script and Stop-Transcript at the bottom.我刚刚在脚本顶部添加了Start-Transcript ,在底部添加了Stop-Transcript

The output file was intended to be named <folder where script resides>-<datestamp>.rtf , but for some reason the trace file was being put where I did not expect it — the desktop!输出文件原本打算命名为<folder where script resides>-<datestamp>.rtf ,但出于某种原因,跟踪文件被放在了我没有预料到的地方——桌面!

I have found the best way to handle this is to have a logging function that will detect if there is a host UI and act accordingly.我发现处理此问题的最佳方法是拥有一个日志记录功能,该功能将检测是否有主机 UI 并采取相应措施。 When the script is executed in interactive mode it will show the details in the host UI, but when it is run via WinRM or in a non-interactive mode it will fall back on the Write-Output so that you can capture it using the > or *> redirection operators当脚本以交互模式执行时,它将在主机 UI 中显示详细信息,但当它通过 WinRM 或非交互模式运行时,它将返回到Write-Output ,以便您可以使用>捕获它或*>重定向运算符

function Log-Info ($msg, $color = "Blue") {
    if($host.UI.RawUI.ForegroundColor -ne $null) {
        Write-Host "`n[$([datetime]::Now.ToLongTimeString())] $msg" -ForegroundColor $color -BackgroundColor "Gray"
    } else {
        Write-Output "`r`n[$([datetime]::Now.ToLongTimeString())] $msg"
    }
}

In cases where you want to capture the full output with the Write-Host coloring, you can use the Get-ConsoleAsHtml.ps1 script to export the host's scrolling buffer to an HTML or RTF file.在您想要使用Write-Host着色捕获完整输出的情况下,您可以使用Get-ConsoleAsHtml.ps1脚本将主机的滚动缓冲区导出到 HTML 或RTF文件。

Use Write-Output instead of Write-Host , and redirect it to a file like this:使用Write-Output而不是Write-Host ,并将其重定向到这样的文件:

Deploy.ps1 > mylog.log or Write-Output "Hello World!" > mylog.log

You should not use Write-Host if you wish to have the messages in a file.如果您希望将消息保存在文件中,则不应使用 Write-Host。 It is for writing to the host only.它仅用于写入主机。

Instead you should use a logging module, or Set/Add-Content.相反,您应该使用日志记录模块或 Set/Add-Content。

Try using Write-Output instead of Write-Host .尝试使用Write-Output而不是Write-Host

The output goes down the pipeline, but if this is the end of the pipe, it goes to the console.输出沿着管道向下,但如果这是管道的末端,它会转到控制台。

> Write-Output "test"
test
> Write-Output "test" > foo.txt
> Get-Content foo.txt
test

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM