Redirect Write-Host statements to a file

前端 未结 12 1755
鱼传尺愫
鱼传尺愫 2020-11-29 08:39

I have a PowerShell script that I am debugging and would like to redirect all Write-Host statements to a file. Is there an easy way to do that?

相关标签:
12条回答
  • 2020-11-29 09:03

    I just added Start-Transcript at the top of the script and Stop-Transcript at the bottom.

    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!

    0 讨论(0)
  • 2020-11-29 09:08

    If you have just a few Write-Host statements, you can use the "6>>" redirector operator to a file:

    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.

    0 讨论(0)
  • 2020-11-29 09:12

    This worked for me in my first PowerShell script that I wrote few days back:

    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:

    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 :)

    0 讨论(0)
  • 2020-11-29 09:13

    You can run your script in a secondary PowerShell shell and capture the output like this:

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

    That worked for me.

    0 讨论(0)
  • 2020-11-29 09:14

    You can create a proxy function for Write-Host which sends objects to the standard output stream instead of merely printing them. I wrote the below cmdlet for just this purpose. 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.

    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
       }
    }
    
    0 讨论(0)
  • 2020-11-29 09:14

    Try using Write-Output instead of 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
    
    0 讨论(0)
提交回复
热议问题