Powershell 如何确定写入主机是否适用于当前主机
是否存在任何合理、可靠的契约,规定给定PowerShell主机实现中是否支持Powershell 如何确定写入主机是否适用于当前主机,powershell,write-host,powershell-hosting,Powershell,Write Host,Powershell Hosting,是否存在任何合理、可靠的契约,规定给定PowerShell主机实现中是否支持写主机,脚本可以针对任何合理的主机实现运行 (假设我理解写主机和写输出/写详细之间的区别,并且我确实希望写主机语义(如果支持)用于此特定的人类可读文本。) 我曾考虑尝试询问$Host变量或$Host.UI/$Host.UI.RawUI,但我发现的唯一相关差异是: 在$Host.Name中: Windows powershell.exe命令行具有$Host.Name='ConsoleHost' ISE有$Host.Na
写主机
,脚本可以针对任何合理的主机实现运行
(假设我理解写主机
和写输出
/写详细
之间的区别,并且我确实希望写主机
语义(如果支持)用于此特定的人类可读文本。)
我曾考虑尝试询问$Host
变量或$Host.UI
/$Host.UI.RawUI
,但我发现的唯一相关差异是:
- 在
中:$Host.Name
- Windows powershell.exe命令行具有
$Host.Name='ConsoleHost'
- ISE有
$Host.Name='Windows PowerShell ISE主机'
- SQL Server代理作业步骤具有
$Host.Name='Default Host'
- 我没有安装任何非Windows版本,但我希望它们是不同的
- Windows powershell.exe命令行具有
- 在
中:$Host.UI.RawUI
- Windows powershell.exe命令行返回
$Host.UI.RawUI的所有属性的值
- ISE不对
的某些属性返回值(或$Host.UI.RawUI
),例如$null
$Host.UI.RawUI.CursorSize
- SQL Server代理作业步骤不会为所有
$Host.UI.RawUI
- 再说一次,我不能签入任何其他平台
- Windows powershell.exe命令行返回
$Host.Name
值列表似乎有点麻烦,尤其是现在PowerShell已经跨平台了。我有理由希望脚本能够从任何主机调用,并且只做正确的事情
背景
我编写了一个脚本,可以从PowerShell命令提示符、ISE或SQL Server代理作业中合理运行。这个脚本的输出完全是文本的,供人阅读。从命令提示符或ISE运行时,使用Write Host
对输出进行着色
SQL Server作业可以通过两种不同的方式进行设置,并且都支持将输出捕获到SQL Server代理日志查看器中:
powershell.exe -Command x:\pathto\script.ps1 -Arg1 -Arg2 -Etc
写入输出
或写入错误
写入的内容:
#whatever
Do-WhateverPowershellCommandYouWant
x:\pathto\script.ps1 -Arg1 -Arg2 -Etc
写入输出
或写入错误
发出输出,但不能同时使用这两种方法。如果作业步骤失败(即,如果抛出
或写入错误'foo'-EA'Stop'
),则只在日志中获取错误流,如果成功,则只在日志中获取输出流
此外,嵌入式PS实现不支持写主机
。至少在SQL Server 2016之前,Write Host
抛出一个System.Management.Automation.Host.HostException
,其中包含一条消息,提示用户失败,因为主机程序或命令类型不支持用户交互
为了支持我的所有用例,到目前为止,我开始使用一个定制函数Write Message
,它的基本设置如下(简化):
$script:can_write_host=$true
$script:has_errors=$false
$script:message_stream=New Object Text.StringBuilder
函数写入消息{
参数($message,[Switch]$iserror)
if($script:can\u write\u host){
$private:color=if($iserror){'Red'}else{'White'}
尝试{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}
}
试试{
}
捕获{
写入消息-消息(“未处理的错误:+($|格式列表|输出字符串))-IsError
}
最后{
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())}
}
}
从SQL Server 2019开始(可能更早),它似乎不再在嵌入式SQL Server代理PS主机中引发异常,而是一个不会向输出或错误流发出任何信息的no op。由于没有例外,我的脚本的Write Message
函数无法再可靠地检测它是否应该使用Write Host
或StringBuilder.AppendLine
SQL Server代理作业的基本解决方法是使用更成熟的CmdExec步骤类型(其中
写入输出
和写入主机
都被捕获为stdout),但我确实更喜欢PowerShell步骤类型,因为它能够跨多行可靠地分割命令,因此,我很想看看是否有一种更全面的、基于PowerShell的方法来解决写主机
是否对我所在的主机有用的问题。PowerShell输出着色感觉像是一种附加的功能,然后被忽略了。我能想到的变通方法(不是解决方案):1)使用$Host.Name
检测支持写主机的已知场景,在其他情况下默认为写输出;2) 使用开关指定是否使用写入主机和着色,
$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()) }
}
}