won*_*sia 24 powershell powershell-5.0
众所周知,这Write-Host是邪恶的.In PowerShell 5,Write-Information被添加并被认为是替换Write-Host.
但是,真的,哪个更好?
Write-Host因为它不使用管道是邪恶的,所以输入消息不能被重用.
但是,Write-Host只是在控制台中展示一些东西呢?在什么情况下我们应该重用输入?
无论如何,如果我们真的想重用输入,为什么不写这样的东西:
$foo = "Some message to be reused like saving to a file"
Write-Host $foo
$foo | Out-File -Path "D:\foo.log"
Run Code Online (Sandbox Code Playgroud)
另一个缺点Write-Host是,Write-Host可以通过使用-ForegroundColor和指定消息在控制台中显示的颜色-BackgroundColor.
另一方面,通过使用Write-Information,输入消息可以通过No.6管道在任何我们想要的地方使用.并且不需要像我上面写的那样编写额外的代码.但是黑暗的一面是,如果我们想要将消息写入控制台并保存到文件中,我们必须这样做:
# 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 =======
Run Code Online (Sandbox Code Playgroud)
我觉得有点多余.
我只知道这个"vs"事情的一个方面,我必须要有一些东西.那么还有什么能让我相信Write-Information的更好Write-Host,请在这里留下你的答案.
谢谢.
Ans*_*ers 34
该Write-*cmdlet,您可以引导你的PowerShell代码输出结构化的方式,所以你可以很容易地从彼此区分不同严重程度的信息.
Write-Host:在控制台上向交互式用户显示消息.与其他Write-*cmdlet 不同,这个cmdlet既不适合也不打算用于自动化/重定向目的.不是邪恶,只是不同.Write-Output:将代码的"正常"输出写入默认(成功)输出流("STDOUT").Write-Error:将错误信息写入单独的流("STDERR").Write-Warning:将您认为警告的消息(即非故障的内容,但用户应该关注的内容)写入单独的流.Write-Verbose:将您认为比"正常"输出更详细的信息写入单独的流.Write-Debug:将您认为与调试代码相关的信息写入单独的流.Write-Information只是这种方法的延续.它可以让你实现你的输出(日志级别Debug,Verbose,Information,Warning,Error),并且仍然具有可用于定期输出成功输出流.
至于为什么Write-Host成为一个包装Write-Information:我不知道这个决定的实际原因,但我怀疑这是因为大多数人不明白Write-Host实际上是如何工作的,即它可以用于什么以及它应该是什么用于.
据我所知,没有一种普遍接受或推荐的方法来登录PowerShell.例如,你可以实现像@JeremyMontgomery在他的回答中建议的单一记录功能:
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'
Run Code Online (Sandbox Code Playgroud)
或一组日志记录功能(每个日志级别一个):
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'
Run Code Online (Sandbox Code Playgroud)
另一种选择是创建自定义记录器对象:
$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')
Run Code Online (Sandbox Code Playgroud)
无论哪种方式,您都可以通过外部化日志代码
将它放入一个单独的脚本文件并点源该文件:
. 'C:\path\to\logger.ps1'
Run Code Online (Sandbox Code Playgroud)将它放入模块并导入该模块:
Import-Module Logger
Run Code Online (Sandbox Code Playgroud)mkl*_*nt0 16
为了补充Ansgar的有用和全面的答案:
Write-Host变成(实质上)
Write-Information -InformationAction Continue PSv5中的包装器,大概是因为:
它可以抑制或重定向Write-Host消息,这在以前是不可能的(在PowerShell 4或更低版本中,Write-Host绕过PowerShell的流并直接输出到主机),
同时保留向后兼容性,默认情况下输出消息- Write-Information与其默认行为是静默的(因为它尊重偏好变量$InformationPreference,其默认值为SilentlyContinue).
虽然Write-Host现在(PSv5 +)有点用词不当 - 它不一定写入主机 - 它仍然有一个明显的优势Write-Information(如你所述):它可以用-ForegroundColor和产生彩色输出-BackgroundColor.
Ansgar的答案涵盖了传统的日志记录视角,但PowerShell的Start-Transcriptcmdlet 可以作为内置替代方案(见下文).
至于您希望将消息输出到主机,同时还要在日志文件中捕获它们:
PowerShell的会话记录 - 通过Start-Transcript和Stop-Transcript - 可能会给你你想要的.
顾名思义,成绩单捕获任何打印到屏幕上(没有着色),因此默认情况下包括成功输出.
适用于您的示例:
$null = Start-Transcript "D:\foo.log"
$InformationPreference = "Continue"
Write-Information "Some Message"
Write-Information "Another Message"
$null = Stop-Transcript
Run Code Online (Sandbox Code Playgroud)
以上将打印消息,都在屏幕和成绩单文件; 请注意,奇怪的是,只有在文件中它们才会带有前缀INFO:.
(与此相反,Write-Warning,Write-Verbose和Write-Debug-如果配置成产生输出-使用前缀WARNING:,VERBOSE:,DEBUG:都在屏幕上,在该文件中;类似地,Write-Error既产生在屏幕上,在该文件中的"噪声"多行输入).
注意一个奇怪的事情(我不清楚它是一个bug还是设计,在PSv5.1中观察到):输出来自Write-Information转录文件(但不在屏幕上),即使$InformationPreference设置为SilentlyContinue(默认值); 排除Write-Information输出的唯一方法(通过首选项变量或-InformationAction参数)似乎是一个值Ignore- 它会明确地使输出静音- 或者奇怪的Continue是,它只会打印到控制台,就像PetSerAl指出的那样.
概括地说,你可以使用Start-Transcript作为一种方便,内置近似一个日志工具,其详细程度可以从通过偏好变量(外部控制$InformationPreference,$VerbosePreference...) ,具有以下重要区别常规测井:
通常,转录文件中的内容也会输出到控制台(通常可以认为是加号).
但是,成功输出(数据输出)默认也会发送到成绩单 - 除非您捕获它或完全禁止它 - 并且您无法选择性地将其保留在成绩单之外:
通常,从 Windows PowerShell v5.1/PowerShell Core v6.0.0-beta.5开始,外部重定向会将流保留在转录本之外,但有两个例外:
Write-Host输出,即使使用6>或*>重定向.2>或*>重定向也是如此.$ErrorActionPreference = 'SilentlyContinue'/ 'Ignore' 确实会将非终止错误保留在转录本之外,但不会终止转义.脚本文件不是面向行的(有一个带有调用信息的标题行块,并且无法保证脚本生成的输出仅限于一行),因此您不能指望逐行解析它们方式.
[1] PetSerAl提到了以下有限且有些麻烦的解决方法(PSv5 +),仅用于将成功输出发送到控制台,这显着排除了通过管道发送输出或捕获它:
'to console only' | Out-String -Stream | ForEach-Object { $Host.UI.WriteLine($_) }
PowerShell 是关于自动化的。
有时,您一天多次运行脚本,并且不想一直看到输出。
Write-Host没有隐藏输出的可能性。无论如何,它都会写在控制台上。
使用Write-Information,您可以-InformationAction在脚本上指定参数。使用此参数,您可以指定是否要查看消息 ( -InformationAction Continue) 或不查看( -InformationAction SilentlyContinue)
编辑:也请使用"Some Message" | out-file D:\foo.log日志记录,也不Write-Host或Write-Information
| 归档时间: |
|
| 查看次数: |
13808 次 |
| 最近记录: |