Перенаправить операторы Write-Host в файл

У меня есть сценарий PowerShell, который я отлаживаю и хочу перенаправить все операторы Write-Host в файл. Есть ли простой способ сделать это?

Ответ 1

  До PowerShell 4.0 Write-Host отправлял объекты на хост. Он не возвращает никаких объектов.

Начиная с PowerShell 5.0 и новее, Write-Host является оболочкой для Write-Information, которая позволяет выводить в информационный поток и перенаправлять его с помощью 6>> file_name.

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

Однако, если у вас много операторов Write-Host, замените их все на Write-Log, что позволит вам решить, выводить ли в консоль, файл или журнал событий, или все три.

Проверьте также:

Ответ 2

Вы можете создать функцию прокси для Write-Host, которая отправляет объекты в стандартный поток вывода, а не просто печатает их. Я написал ниже командлет только для этой цели. Он создаст прокси на лету, который действует только на время текущего конвейера.

Полная запись в моем блоге здесь, но я включил код ниже. Используйте переключатель -Quiet для подавления записи консоли.

Использование:

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 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
   }
}

Ответ 3

Использование перенаправления приведет к зависанию Write-Host. Это связано с тем, что Write-Host имеет дело с различными проблемами форматирования, которые характерны для текущего используемого терминала. Если вы просто хотите, чтобы ваш сценарий имел гибкость для вывода в обычном режиме (по умолчанию для оболочки, с возможностью >, 2> и т.д.), Используйте Write-Output.

В противном случае, если вы действительно хотите уловить особенности текущего терминала, Start-Transcript - хорошее место для начала. В противном случае вам придется пройти тестирование вручную или написать несколько сложных наборов тестов.

Ответ 4

Вы можете запустить свой сценарий во вторичной оболочке PowerShell и записать вывод следующим образом:

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

Это сработало для меня.

Ответ 5

Это сработало для меня в моем первом скрипте PowerShell, который я написал несколько дней назад:

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

Использование в скрипте:

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

Вызов выполнения сценария PowerShell:

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

Это не совсем ответ на этот вопрос, но он может помочь кому-то, пытающемуся выполнить как вход в консоль, так и вывод в какой-либо файл журнала, делая то, что я достиг здесь :)

Ответ 6

Определите функцию Write-Host. Попросите его записать файл. У вас могут быть проблемы, если некоторые вызовы используют странный набор аргументов. Кроме того, это будет работать только для вызовов, которые не относятся к Snapin.

Ответ 7

Я только что добавил Start-Transcript вверху скрипта и Stop-Transcript внизу.

Выходной файл должен был называться <folder where script resides>-<datestamp>.rtf, но по какой-то причине файл трассировки помещался туда, где я этого не ожидал &— рабочий стол!

Ответ 8

Вам не следует использовать Write-Host, если вы хотите иметь сообщения в файле. Он предназначен только для записи на хост.

Вместо этого вы должны использовать модуль регистрации или Set/Add-Content.

Ответ 9

Я обнаружил, что лучший способ справиться с этим - иметь функцию ведения журнала, которая будет определять, существует ли пользовательский интерфейс хоста, и действовать соответствующим образом. Когда скрипт выполняется в интерактивном режиме, он отображает детали в пользовательском интерфейсе хоста, но когда он запускается через WinRM или в неинтерактивном режиме, он переключается на Write-Output , так что вы можете захватить его, используя операторы перенаправления > или *> redirection operators

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"
    }
}

В тех случаях, когда вы хотите получить полный вывод с помощью раскраски Write-Host, вы можете использовать скрипт Get-ConsoleAsHtml.ps1, чтобы экспортировать буфер прокрутки хоста в HTML или RTF файл.

Ответ 10

Используйте Write-Output вместо Write-Host и перенаправьте его в файл, подобный следующему:

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

Ответ 11

Попробуйте использовать Write-Output вместо Write-Host.

Вывод идет по конвейеру, но если это конец конвейера, он отправляется на консоль.

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

Ответ 12

Если у вас всего несколько операторов Write-Host, вы можете использовать оператор перенаправителя "6>>" для файла:

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

Это "Пример 5: Подавить вывод с Write-Host", предоставленный Microsoft, измененный в соответствии с about_Operators.