[英]How to determine if Write-Host will work for the current host
Is there any sane, reliable contract that dictates whether Write-Host
is supported in a given PowerShell host implementation, in a script that could be run against any reasonable host implementation?在可以针对任何合理的主机实现运行的脚本中,是否有任何理智、可靠的合同规定在给定的 PowerShell 主机实现中是否支持Write-Host
?
(Assume that I understand the difference between Write-Host
and Write-Output
/ Write-Verbose
and that I definitely do want Write-Host
semantics, if supported, for this specific human-readable text.) (假设我了解Write-Host
和Write-Output
/ Write-Verbose
之间的区别,并且如果支持,对于这个特定的人类可读文本,我肯定想要Write-Host
语义。)
I thought about trying to interrogate the $Host
variable, or $Host.UI
/ $Host.UI.RawUI
but the only pertinent differences I am spotting are:我想过尝试询问$Host
变量或$Host.UI
/ $Host.UI.RawUI
但我发现的唯一相关差异是:
in $Host.Name
:在$Host.Name
:
$Host.Name = 'ConsoleHost'
Windows powershell.exe 命令行具有$Host.Name = 'ConsoleHost'
$Host.Name = 'Windows PowerShell ISE Host'
ISE 有$Host.Name = 'Windows PowerShell ISE Host'
$Host.Name = 'Default Host'
SQL 服务器代理作业步骤具有$Host.Name = 'Default Host'
in $Host.UI.RawUI
:在$Host.UI.RawUI
:
$Host.UI.RawUI
Windows powershell.exe 命令行返回$Host.UI.RawUI
的所有属性的值$null
) for some properties of $Host.UI.RawUI
, eg $Host.UI.RawUI.CursorSize
对于$Host.UI.RawUI
的某些属性,ISE 不返回任何值(或$null
),例如$Host.UI.RawUI.CursorSize
$Host.UI.RawUI
SQL 服务器代理作业步骤不返回所有$Host.UI.RawUI
的值Maintaining a list of $Host.Name
values that support Write-Host
seems like it would be bit of a burden, especially with PowerShell being cross-platform now.维护支持Write-Host
的$Host.Name
值列表似乎有点负担,尤其是 PowerShell 现在是跨平台的。 I would reasonably want the script to be able to be called from any host and just do the right thing .我会合理地希望脚本能够从任何主机调用并且只是做正确的事情。
I have written a script that can be reasonably run from within the PowerShell command prompt, from within the ISE or from within a SQL Server Agent job.我编写了一个脚本,可以从 PowerShell 命令提示符、ISE 或 SQL 服务器代理作业中合理运行。 The output of this script is entirely textual, for human reading.此脚本的 output 完全是文本,供人类阅读。 When run from the command prompt or ISE, the output is colorized using Write-Host
.从命令提示符或 ISE 运行时,output 使用Write-Host
着色。
SQL Server jobs can be set up in two different ways, and both support capturing the output into the SQL Server Agent log viewer: SQL 服务器作业可以通过两种不同的方式设置,并且都支持将 output 捕获到 SQL 服务器代理日志查看器中:
via a CmdExec step, which is simple command-line execution, where the Job Step command text is an executable and its arguments, so you invoke the powershell.exe executable.通过 CmdExec 步骤,这是简单的命令行执行,其中 Job Step 命令文本是可执行文件及其 arguments,因此您调用 powershell.exe 可执行文件。 Captured output is the stdout/sterr of the process:捕获的 output 是该过程的 stdout/sterr:
powershell.exe -Command x:\pathto\script.ps1 -Arg1 -Arg2 -Etc
via a PowerShell step, where the Job Step command text is raw PS script interpreted by its own embedded PowerShell host implementation.通过 PowerShell 步骤,其中作业步骤命令文本是由其自己的嵌入式 PowerShell 主机实现解释的原始 PS 脚本。 Captured output is whatever is written via Write-Output
or Write-Error
:捕获的 output 是通过Write-Output
或Write-Error
内容:
#whatever Do-WhateverPowershellCommandYouWant x:\pathto\script.ps1 -Arg1 -Arg2 -Etc
Due to some other foibles of the SQL Server host implementation, I find that you can emit output using either Write-Output
or Write-Error
, but not both.由于 SQL 服务器主机实现的其他一些缺点,我发现您可以使用Write-Output
或Write-Error
发出 output ,但不能同时使用。 If the job step fails (ie if you throw
or Write-Error 'foo' -EA 'Stop'
), you only get the error stream in the log and, if it succeeds, you only get the output stream in the log.如果作业步骤失败(即如果您throw
或Write-Error 'foo' -EA 'Stop'
),您只会在日志中收到错误 stream ,如果成功,您只会在日志中收到 output ZF7B44CFAFD5C5222E 错误。
Additionally, the embedded PS implementation does not support Write-Host
.此外,嵌入式 PS 实现不支持Write-Host
。 Up to at least SQL Server 2016, Write-Host
throws a System.Management.Automation.Host.HostException
with the message A command that prompts the user failed because the host program or the command type does not support user interaction .至少在 SQL Server 2016 之前, Write-Host
抛出System.Management.Automation.Host.HostException
并带有消息A command that prompt the user failed because the host program or command type does not support user interaction 。
To support all of my use-cases, so far, I took to using a custom function Write-Message
which was essentially set up like (simplified):为了支持我的所有用例,到目前为止,我开始使用自定义 function Write-Message
,它基本上设置为(简化):
$script:can_write_host = $true
$script:has_errors = $false
$script:message_stream = New-Object Text.StringBuilder
function Write-Message {
Param($message, [Switch]$iserror)
if ($script:can_write_host) {
$private:color = if ($iserror) { 'Red' } else { 'White' }
try { Write-Host $message -ForegroundColor $private:color }
catch [Management.Automation.Host.HostException] { $script:can_write_host = $false }
}
if (-not $script:can_write_host) {
$script:message_stream.AppendLine($message) | Out-Null
}
if ($iserror) { $script:has_errors = $true }
}
try {
<# MAIN SCRIPT BODY RUNS HERE #>
}
catch {
Write-Message -Message ("Unhandled error: " + ($_ | Format-List | Out-String)) -IsError
}
finally {
if (-not $script:can_write_host) {
if ($script:has_errors) { Write-Error ($script:message_stream.ToString()) -EA 'Stop' }
else { Write-Output ($script:message_stream.ToString()) }
}
}
As of SQL Server 2019 (perhaps earlier), it appears Write-Host
no longer throws an exception in the embedded SQL Server Agent PS host, but is instead a no-op that emits nothing to either output or error streams. As of SQL Server 2019 (perhaps earlier), it appears Write-Host
no longer throws an exception in the embedded SQL Server Agent PS host, but is instead a no-op that emits nothing to either output or error streams. Since there is no exception, my script's Write-Message
function can no longer reliably detect whether it should use Write-Host
or StringBuilder.AppendLine
.由于没有例外,我的脚本的Write-Message
function 无法再可靠地检测它是否应该使用Write-Host
或StringBuilder.AppendLine
。
The basic workaround for SQL Server Agent jobs is to use the more-mature CmdExec step type (where Write-Output
and Write-Host
both get captured as stdout), but I do prefer the PowerShell step type for (among other reasons) its ability to split the command reliably across multiple lines, so I am keen to see if there is a more-holistic, PowerShell-based approach to solve the problem of whether Write-Host
does anything useful for the host I am in. SQL 服务器代理作业的基本解决方法是使用更成熟的 CmdExec 步骤类型(其中Write-Output
和Write-Host
都被捕获为标准输出),但我更喜欢 PowerShell 步骤类型,因为(除其他原因外)它的能力将命令可靠地拆分为多行,因此我很想看看是否有更全面的、基于 PowerShell 的方法来解决Write-Host
是否对我所在的主机有用的问题。
Just check if your host is UserInteractive or an service type environment.只需检查您的主机是 UserInteractive 还是服务类型环境。
$script:can_write_host = [Environment]::UserInteractive
Another way to track the output of a script in real time is to push that output to a log file and then monitor it in real time using trace32.另一种实时跟踪脚本的 output 的方法是将 output 推送到日志文件,然后使用 trace32 对其进行实时监控。 This is just a workaround, but it might work out for you.这只是一种解决方法,但它可能对您有用。
Add-Content -Path "C:\Users\username\Documents\PS_log.log" -Value $variablewithvalue
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.