Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Powershell 如何确定写入主机是否适用于当前主机_Powershell_Write Host_Powershell Hosting - Fatal编程技术网

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

是否存在任何合理、可靠的契约,规定给定PowerShell主机实现中是否支持
写主机
,脚本可以针对任何合理的主机实现运行

(假设我理解
写主机
写输出
/
写详细
之间的区别,并且我确实希望
写主机
语义(如果支持)用于此特定的人类可读文本。)

我曾考虑尝试询问
$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版本,但我希望它们是不同的
  • $Host.UI.RawUI
    中:

    • Windows powershell.exe命令行返回
      $Host.UI.RawUI的所有属性的值
    • ISE不对
      $Host.UI.RawUI
      的某些属性返回值(或
      $null
      ),例如
      $Host.UI.RawUI.CursorSize
    • SQL Server代理作业步骤不会为所有
      $Host.UI.RawUI
    • 再说一次,我不能签入任何其他平台
维护支持写入主机的
$Host.Name
值列表似乎有点麻烦,尤其是现在PowerShell已经跨平台了。我有理由希望脚本能够从任何主机调用,并且只做正确的事情

背景 我编写了一个脚本,可以从PowerShell命令提示符、ISE或SQL Server代理作业中合理运行。这个脚本的输出完全是文本的,供人阅读。从命令提示符或ISE运行时,使用
Write Host
对输出进行着色

SQL Server作业可以通过两种不同的方式进行设置,并且都支持将输出捕获到SQL Server代理日志查看器中:

  • 通过CmdExec步骤,这是一种简单的命令行执行,其中作业步骤命令文本是一个可执行文件及其参数,因此可以调用powershell.exe可执行文件。捕获的输出是进程的stdout/sterr:

    powershell.exe -Command x:\pathto\script.ps1 -Arg1 -Arg2 -Etc
    
  • 通过PowerShell步骤,其中作业步骤命令文本是由其自己的嵌入式PowerShell主机实现解释的原始PS脚本。捕获的输出是通过
    写入输出
    写入错误
    写入的内容:

    #whatever
    Do-WhateverPowershellCommandYouWant
    x:\pathto\script.ps1 -Arg1 -Arg2 -Etc
    
  • 由于SQL Server主机实现的其他一些缺点,我发现您可以使用
    写入输出
    写入错误
    发出输出,但不能同时使用这两种方法。如果作业步骤失败(即,如果
    抛出
    写入错误'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()) }
         }
     }