PowerShell 5 中的写入主机与写入信息 [英] Write-Host vs Write-Information in PowerShell 5

查看:34
本文介绍了PowerShell 5 中的写入主机与写入信息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

众所周知,Write-Host 是邪恶的.在PowerShell 5中,增加了Write-Information,并被认为是替代Write-Host.

但是,真的,哪个更好?
Write-Host 是邪恶的,因为它不使用管道,因此输入消息不能被重用.
但是,Write-Host 所做的只是在控制台中显示一些东西,对吗?在什么情况下我们应该重用输入?
无论如何,如果我们真的想重用输入,为什么不写这样的东西:

$foo = "一些消息可以重复使用,比如保存到文件中"写主机 $foo$foo |Out-File -Path "D:\foo.log"

Write-Host 的另一个缺点是,Write-Host 可以使用 -ForegroundColor-BackgroundColor.

另一方面,通过使用Write-Information,可以通过No.6 管道在任何我们想要的地方使用输入消息.并且不需要像我上面写的那样编写额外的代码.但不利的一面是,如果我们想将消息写入控制台并保存到文件中,我们必须这样做:

# 始终将 $InformationPreference 变量设置为Continue"$InformationPreference = "继续";# 如果我们不想要这样的东西:# ======== 示例 1 ========# 文件 Foo.ps1$InformationPreference = "继续";写信息一些消息"写信息另一条消息"# 文件 AlwaysRunThisBeforeEverything.ps1.\Foo.ps1 6>"D:\foo.log"# ======== 示例 1 结束 =======# 然后我们必须像这样将 '6>"D:\foo.log"' 添加到 Write-Information 的每一行中:# ======== 示例 2 ========$InformationPreference = "继续";Write-Information "Some Message" 6>"D:\foo.log"写入信息另一条消息"6>D:\foo.log"# ======== 示例 2 结束 =======

我觉得有点多余.

我只知道这个vs"事情的一小部分,而且我脑子里一定有什么东西.那么还有什么可以让我相信 Write-InformationWrite-Host 更好,请在这里留下你的回答.
谢谢.

解决方案

Write-* cmdlet 允许您以结构化的方式引导 PowerShell 代码的输出,因此您可以轻松区分消息彼此的严重程度不同.

  • Write-Host:在控制台上向交互式用户显示消息.与其他 Write-* cmdlet 不同,这个 cmdlet 既不适合也不打算用于自动化/重定向目的.不是邪恶,只是不同.
  • Write-Output:将代码的正常"输出写入默认(成功)输出流(STDOUT").
  • Write-Error:将错误信息写入单独的流(STDERR").
  • Write-Warning:将您认为是警告的消息(即不是失败的事情,而是用户应该关注的事情)写入单独的流.
  • Write-Verbose:将您认为比正常"输出更详细的信息写入单独的流.
  • Write-Debug:将您认为与调试代码相关的信息写入单独的流.

Write-Information 只是这种方法的延续.它允许您在输出中实现日志级别(DebugVerboseInformationWarningError) 并且仍然有成功的输出流可用于常规输出.

至于为什么 Write-Host 成为 Write-Information 的包装器:我不知道这个决定的真正原因,但我怀疑是因为大多数人不了解 Write-Host 实际上是如何工作的,即它可以用来做什么,不应该用来做什么.

<小时>

据我所知,没有普遍接受或推荐的登录 PowerShell 的方法.例如,您可以实现单个日志记录功能,例如 @JeremyMontgomery 在他的回答中建议:

function Write-Log {参数([参数(强制=$true,位置=0)][ValidateNotNullOrEmpty()][字符串]$消息,[参数(强制=$false,位置=1)][ValidateSet('错误','警告','信息','详细','调试')][string]$LogLevel = '信息')开关($LogLevel){'错误'       { ... }'警告'     { ... }'信息' { ... }'详细' { ... }'调试' { ... }默认 { 抛出无效的日志级别:$_"}}}Write-Log 'foo' # 默认日志级别:信息Write-Log 'foo' 'Information' # 显式日志级别:信息写日志 'bar' '调试'

或一组日志功能(每个日志级别一个):

function Write-LogInformation {参数([参数(强制=$true,位置=0)][ValidateNotNullOrEmpty()][字符串]$消息)...}函数写日志调试{参数([参数(强制=$true,位置=0)][ValidateNotNullOrEmpty()][字符串]$消息)...}...写日志信息 'foo'写日志调试 'bar'

另一种选择是创建自定义记录器对象:

$logger = New-Object -Type PSObject -Property @{文件名 = ''控制台 = $true}$logger |添加成员 -Type ScriptMethod -Name Log -Value {参数([参数(强制=$true,位置=0)][ValidateNotNullOrEmpty()][字符串]$消息,[参数(强制=$false,位置=1)][ValidateSet('错误','警告','信息','详细','调试')][string]$LogLevel = '信息')开关($LogLevel){'错误'       { ... }'警告'     { ... }'信息' { ... }'详细' { ... }'调试' { ... }默认 { 抛出无效的日志级别:$_"}}}$logger |添加成员 -Type ScriptMethod -Name LogDebug -Value {Param([Parameter(Mandatory=$true)][string]$Message)$this.Log($Message, '调试')}$logger |添加成员 -Type ScriptMethod -Name LogInfo -Value {Param([Parameter(Mandatory=$true)][string]$Message)$this.Log($Message, '信息')}...Write-Log 'foo' # 默认日志级别:信息$logger.Log('foo') # 默认日志级别:信息$logger.Log('foo', 'Information') # 显式日志级别:信息$logger.LogInfo('foo') #(方便)包装方法$logger.LogDebug('bar')

无论哪种方式,您都可以通过

将日志代码外部化
  • 将其放入单独的脚本文件中并dot-sourcing那个文件:

    <预><代码>.'C:\path\to\logger.ps1'

  • 将其放入模块 并导入该模块:

    导入模块记录器

It is well known that Write-Host is evil. In PowerShell 5, Write-Information is added and is considered to replace Write-Host.

But, really, which is better?
Write-Host is evil for it does not use pipeline, so the input message can't get reused.
But, what Write-Host do is just to show something in the console right? In what case shall we reuse the input?
Anyway, if we really want to reuse the input, why not just write something like this:

$foo = "Some message to be reused like saving to a file"
Write-Host $foo
$foo | Out-File -Path "D:\foo.log"

Another Cons of Write-Host is that, Write-Host can specified in what color the messages are shown in the console by using -ForegroundColor and -BackgroundColor.

On the other side, by using Write-Information, the input message can be used wherever we want via the No.6 pipeline. And doesn't need to write the extra codes like I write above. But the dark side of this is that, if we want to write messages to the console and also saved to the file, we have to do this:

# Always set the $InformationPreference variable to "Continue"
$InformationPreference = "Continue";

# if we don't want something like this:
# ======= Example 1 =======
# File Foo.ps1
$InformationPreference = "Continue";
Write-Information "Some Message"
Write-Information "Another Message"

# File AlwaysRunThisBeforeEverything.ps1
.\Foo.ps1 6>"D:\foo.log"
# ======= End of Example 1 =======

# then we have to add '6>"D:\foo.log"' to every lines of Write-Information like this:
# ======= Example 2 =======
$InformationPreference = "Continue";
Write-Information "Some Message" 6>"D:\foo.log"
Write-Information "Another Message" 6>"D:\foo.log"
# ======= End of Example 2 =======

A little bit redundant I think.

I only know a little aspect of this "vs" thing, and there must have something out of my mind. So is there anything else that can make me believe that Write-Information is better than Write-Host, please leave your kind answers here.
Thank you.

解决方案

The Write-* cmdlets allow you to channel the output of your PowerShell code in a structured way, so you can easily distinguish messages of different severity from each other.

  • Write-Host: display messages to an interactive user on the console. Unlike the other Write-* cmdlets this one is neither suitable nor intended for automation/redirection purposes. Not evil, just different.
  • Write-Output: write the "normal" output of the code to the default (success) output stream ("STDOUT").
  • Write-Error: write error information to a separate stream ("STDERR").
  • Write-Warning: write messages that you consider warnings (i.e. things that aren't failures, but something that the user should have an eye on) to a separate stream.
  • Write-Verbose: write information that you consider more verbose than "normal" output to a separate stream.
  • Write-Debug: write information that you consider relevant for debugging your code to a separate stream.

Write-Information is just a continuation of this approach. It allows you to implement log levels in your output (Debug, Verbose, Information, Warning, Error) and still have the success output stream available for regular output.

As for why Write-Host became a wrapper around Write-Information: I don't know the actual reason for this decision, but I'd suspect it's because most people don't understand how Write-Host actually works, i.e. what it can be used for and what it should not be used for.


To my knowledge there isn't a generally accepted or recommended approach to logging in PowerShell. You could for instance implement a single logging function like @JeremyMontgomery suggested in his answer:

function Write-Log {
  Param(
    [Parameter(Mandatory=$true, Position=0)]
    [ValidateNotNullOrEmpty()]
    [string]$Message,
    [Parameter(Mandatory=$false, Position=1)]
    [ValidateSet('Error', 'Warning', 'Information', 'Verbose', 'Debug')]
    [string]$LogLevel = 'Information'
  )

  switch ($LogLevel) {
    'Error'       { ... }
    'Warning'     { ... }
    'Information' { ... }
    'Verbose'     { ... }
    'Debug'       { ... }
    default       { throw "Invalid log level: $_" }
  }
}

Write-Log 'foo'                    # default log level: Information
Write-Log 'foo' 'Information'      # explicit log level: Information
Write-Log 'bar' 'Debug'

or a set of logging functions (one for each log level):

function Write-LogInformation {
  Param(
    [Parameter(Mandatory=$true, Position=0)]
    [ValidateNotNullOrEmpty()]
    [string]$Message
  )

  ...
}

function Write-LogDebug {
  Param(
    [Parameter(Mandatory=$true, Position=0)]
    [ValidateNotNullOrEmpty()]
    [string]$Message
  )

  ...
}

...

Write-LogInformation 'foo'
Write-LogDebug 'bar'

Another option is to create a custom logger object:

$logger = New-Object -Type PSObject -Property @{
  Filename = ''
  Console  = $true
}
$logger | Add-Member -Type ScriptMethod -Name Log -Value {
  Param(
    [Parameter(Mandatory=$true, Position=0)]
    [ValidateNotNullOrEmpty()]
    [string]$Message,
    [Parameter(Mandatory=$false, Position=1)]
    [ValidateSet('Error', 'Warning', 'Information', 'Verbose', 'Debug')]
    [string]$LogLevel = 'Information'
  )

  switch ($LogLevel) {
    'Error'       { ... }
    'Warning'     { ... }
    'Information' { ... }
    'Verbose'     { ... }
    'Debug'       { ... }
    default       { throw "Invalid log level: $_" }
  }
}
$logger | Add-Member -Type ScriptMethod -Name LogDebug -Value {
  Param([Parameter(Mandatory=$true)][string]$Message)
  $this.Log($Message, 'Debug')
}
$logger | Add-Member -Type ScriptMethod -Name LogInfo -Value {
  Param([Parameter(Mandatory=$true)][string]$Message)
  $this.Log($Message, 'Information')
}
...

Write-Log 'foo'                    # default log level: Information
$logger.Log('foo')                 # default log level: Information
$logger.Log('foo', 'Information')  # explicit log level: Information
$logger.LogInfo('foo')             # (convenience) wrapper method
$logger.LogDebug('bar')

Either way you can externalize the logging code by

  • putting it into a separate script file and dot-sourcing that file:

    . 'C:\path\to\logger.ps1'
    

  • putting it into a module and importing that module:

    Import-Module Logger
    

这篇关于PowerShell 5 中的写入主机与写入信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆