【问题标题】:PowerShell Redirection Does Not Always WorkPowerShell 重定向并不总是有效
【发布时间】:2020-08-16 09:05:55
【问题描述】:

重定向New-PSSession警告流 不起作用,正如我认为的那样。无论我如何尝试抑制/重定向它,我总是会收到以下(黄色)警告消息到控制台:

WARNING: Using New-PSSession with Basic Authentication is going to be deprecated soon, checkout https://aka.ms/exops-docs for using Exchange Online V2 Module which uses Modern Authentication.

关于允许该消息渗透到控制台/std_out 的 PowerShell 重定向/流,我缺少什么?

什么不起作用

根据互联网的智慧,我尝试了以下方法:

New-PSSession *>$null ...
New-PSSession ... | Out-Null
New-PSSession *>$null ... -OutVariable x -ErrorVariable y -WarningVariable z
New-PSSession *>$null ... -WarningAction SilentlyContinue
$WarningPreference = 'SilentlyContinue'
New-PSSession ...

我什至尝试过临时控制std_out

$std_out = [System.Console]::Out
$out_writer = New-Object IO.StringWriter
[System.Console]::SetOut($out_writer)

$std_err = [System.Console]::Error
$err_writer = New-Object IO.StringWriter
[System.Console]::SetOut($err_writer)

$sess = New-PSSession ...

[System.Console]::SetOut($std_out)
[System.Console]::SetError($std_err)

除了我能想到的上述所有组合外,还有几个我忘记的方法。

应该做什么

使用Invoke-Command 测试这些技术中的每一种都适用于其他警告,正如预期的那样:


$std_out = [System.Console]::Out
$out_writer = New-Object IO.StringWriter
[System.Console]::SetOut($out_writer)

$std_err = [System.Console]::Error
$err_writer = New-Object IO.StringWriter
[System.Console]::SetOut($err_writer)

Invoke-Command -ScriptBlock {

    Write-Error "My Error"
    Write-Warning "My Warning"
    [console]::WriteLine('Directly to std_out!')

} *>$null -OutVariable x -ErrorVariable y -WarningVariable z

[System.Console]::SetOut($std_out)
[System.Console]::SetError($std_err)

但我尝试过的任何方法都不会抑制或重定向来自 New-PSSession 的消息。

重现

param (
    $username,
    $password
)

$secpasswd = ConvertTo-SecureString $password -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential ($username, $secpasswd)
$URL = "https://ps.outlook.com/powershell"
New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $URL -Credential $creds -Authentication Basic -AllowRedirection

环境测试

Windows 10:

Name                           Value
----                           -----
PSVersion                      7.1.0-preview.2
PSEdition                      Core
GitCommitId                    7.1.0-preview.2
OS                             Microsoft Windows 10.0.18363
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Windows 10:

Name                           Value
----                           -----
PSVersion                      5.1.18362.752
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.18362.752
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

服务器 2019:

Name                           Value
----                           -----
PSVersion                      5.1.17763.1007
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.17763.1007
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

WinRM(所有系统都相同):

Config
    MaxEnvelopeSizekb = 500
    MaxTimeoutms = 60000
    MaxBatchItems = 32000
    MaxProviderRequests = 4294967295
    Client
        NetworkDelayms = 5000
        URLPrefix = wsman
        AllowUnencrypted = false
        Auth
            Basic = true
            Digest = true
            Kerberos = true
            Negotiate = true
            Certificate = true
            CredSSP = false
        DefaultPorts
            HTTP = 5985
            HTTPS = 5986
        TrustedHosts
    Service
        RootSDDL = O:NSG:BAD:P(A;;GA;;;BA)(A;;GR;;;IU)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD)
        MaxConcurrentOperations = 4294967295
        MaxConcurrentOperationsPerUser = 1500
        EnumerationTimeoutms = 240000
        MaxConnections = 300
        MaxPacketRetrievalTimeSeconds = 120
        AllowUnencrypted = false
        Auth
            Basic = false
            Kerberos = true
            Negotiate = true
            Certificate = false
            CredSSP = false
            CbtHardeningLevel = Relaxed
        DefaultPorts
            HTTP = 5985
            HTTPS = 5986
        IPv4Filter = *
        IPv6Filter = *
        EnableCompatibilityHttpListener = false
        EnableCompatibilityHttpsListener = false
        CertificateThumbprint
        AllowRemoteAccess = true
    Winrs
        AllowRemoteShellAccess = true
        IdleTimeout = 7200000
        MaxConcurrentUsers = 2147483647
        MaxShellRunTime = 2147483647
        MaxProcessesPerShell = 2147483647
        MaxMemoryPerShellMB = 2147483647
        MaxShellsPerUser = 2147483647

【问题讨论】:

  • 3>$null*>$null 应该可以工作,但我无法在此处复制该特定警告以进行验证。
  • 为我工作。 $('hi'; write-warning warning) 3>$null
  • 我无法复制,因为不推荐使用基本身份验证,但是添加“-WarningAction SilentlyContinue”怎么样?
  • @Brice 感谢您的建议,但这是我提到的“更多方法”之一。我会更新答案以包含它。
  • 我在尝试时没有收到该错误,.\test joe here。我可以像往常一样隐藏其他警告。

标签: powershell


【解决方案1】:

通常,重定向输出的工作方式与您已经尝试过的一样。具体来说:

New-PSSession -... 3> $null

将重定向您不需要的警告,因为3 描述了自 PowerShell 3.0 (see docs) 以来的警告流。

在这种特殊情况下它不起作用的事实似乎是一个错误,并且几天前已经打开了一个问题here


this article中可能有解释:

发生这种情况是因为 Write-Host 未写入任何流。它是 发送到主机程序,主机程序决定如何处理 它。 Windows PowerShell 控制台和 Windows PowerShell ISE 显示 在控制台上托管消息。

好吧,它不再正确(从 PowerShell 5.0 开始),因为 Write-Host 现在是 Write-Information 的包装器,因此写入信息流 (6)。但有趣的是,有些主机消息没有写入任何流。这里可能就是这种情况,您无法通过重定向所有流来抑制控制台输出。所以“警告”可能是由主机消息转发的,而不是使用任何流。

我看到了多次尝试压制这些主机消息(herehere),但据我所知,对您的情况没有任何帮助。

引用的文章进一步指出:

[...] 给主机程序的消息(不能被抑制或 重定向)。

【讨论】:

  • 感谢链接 GitHub 问题,我在旅途中没有看到它。我已经在 PowerShell 存储库上链接了这个问题和我自己的 GitHub issue
  • 仅供参考,错误报告中提到了一种解决方法:github.com/MicrosoftDocs/office-docs-powershell/issues/… 基本上将 HideBannermessage=true 添加到请求中。
  • @user2199860 我有一些解决方法,但我的问题归结为两件事:1. 我想要一个通用解决方案来处理来自任何命令/脚本的所有警告。 2. 我不想隐藏警告——它们的存在是有原因的。
  • 关于这个问题的更深入的讨论,尽管是一个可悲的冷漠回应,请参阅:this thread
  • @RichardDunn 伤心。但我喜欢this 代码重现问题,因为每个人都可以在离线环境下运行它(Enable-PSRemoting; Set-ExecutionPolicy RemoteSigned 之后)。您可能应该为未来的读者添加这些重现步骤。在我的编辑中,我指出可能值得研究“主机消息”以在您的情况下继续。
【解决方案2】:

也许不是答案,但评论太长了。不要让我解释它的作用或工作原理。 它是在这里或其他地方发现的。我把它放在这里是因为它似乎与powershell和某种线程交互有关......我让你从中取出你需要的东西。

这是我们的上下文:我们必须从 bat 脚本运行 powershell 脚本。 powershell 脚本正在启动一些系统命令(zip 等)。我们很难以正确的方式收集运行时信息。作为解决方案,我们必须将 ps1 脚本作为另一个 ps1 脚本的参数传递,我们称之为 bug.ps1。其内容如下所示。

这是 .bat 文件中的命令:

powershell.exe -ExecutionPolicy Bypass -command "C:\path\to\bug.ps1" "my_script.ps1" %arg%

这里是bug.ps1文件的内容

# <fix>
$bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField"
$objectRef = $host.GetType().GetField( "externalHostRef", $bindingFlags ).GetValue( $host )
$bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetProperty"
$consoleHost = $objectRef.GetType().GetProperty( "Value", $bindingFlags ).GetValue( $objectRef, @() )
[void] $consoleHost.GetType().GetProperty( "IsStandardOutputRedirected", $bindingFlags ).GetValue( $consoleHost, @() )
$bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField"
$field = $consoleHost.GetType().GetField( "standardOutputWriter", $bindingFlags )
$field.SetValue( $consoleHost, [Console]::Out )
$field2 = $consoleHost.GetType().GetField( "standardErrorWriter", $bindingFlags )
$field2.SetValue( $consoleHost, [Console]::Out )
# </fix>
invoke-expression "$args"
exit $lastexitcode

【讨论】:

  • 谢谢,这是一段有趣的 sn-p 代码。今天晚些时候我会仔细看看。可以证明是有用的。
  • 我猜你可以在你想要正确重定向的命令之前的某处“添加”fix
猜你喜欢
  • 2014-12-18
  • 1970-01-01
  • 2020-11-01
  • 2014-08-07
  • 1970-01-01
  • 1970-01-01
  • 2013-11-15
  • 2018-12-09
  • 2014-06-21
相关资源
最近更新 更多