10

Redirecting the Warning Stream for New-PSSession does not work as I believe it should. I am always getting the following (yellow) warning message to console regardless of what I do to try suppress / redirect it:

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.

What am I missing about PowerShell redirection / streams that's allowing that message to permeate through to the console / std_out?

What doesn't work

I have tried the following, as per the wisdom of the internet:

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 ...

I've even tried taking temporary control of 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)

Along with every combination of above that I can think of, plus several more methods that I'm forgetting.

What should work

Testing each of those techniques using Invoke-Command works for other warnings, as expected:


$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)

But nothing I have tried will suppress or redirect that message from New-PSSession.

To reproduce

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

Environments Tested

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

Server 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 (Identical for all systems):

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
Richard Dunn
  • 6,165
  • 1
  • 25
  • 36
  • `3>$null` or `*>$null` should work, but I cannot duplicate that particular warning here to verify. – dxiv May 01 '20 at 21:37
  • Works for me. `$('hi'; write-warning warning) 3>$null` – js2010 May 01 '20 at 23:41
  • i cannot duplicate as basic authentication is not recommanded, but what about adding " -WarningAction SilentlyContinue" ? – Brice May 02 '20 at 12:43
  • @Brice Thanks for the suggestion, but that is one of the "several more methods" I mention. I'll update the answer to include it. – Richard Dunn May 03 '20 at 13:16
  • I don't get that error when I try it, `.\test joe here`. I can hide other warnings in the usual way. – js2010 May 11 '20 at 15:41
  • @js2010 It is related to the `New-PSSession` cmdlet when used to connect to an exchange server. Not a general problem with warnings. – stackprotector May 12 '20 at 08:05
  • @js2010 Have you tried logging in with a real user/pass? Errors / Warnings about bad user pass will get suppressed, as per the question's details. The warning I'm referring to will only occur if you successfully login. – Richard Dunn May 12 '20 at 08:57

2 Answers2

4

Normally, redirecting the output works like you already tried. To be more specific:

New-PSSession -... 3> $null

would redirect your unwanted warning, as 3 describes the Warning Stream since PowerShell 3.0 (see docs).

The fact that it does not work in this particular case seems to be a bug and there has already been opened an issue here a few days ago.


There might be a possible explanation in this article:

This happens because Write-Host is not written to any stream. It's sent to the host program, and the host program decides what to do with it. The Windows PowerShell console and Windows PowerShell ISE display host messages on the console.

Well, it is not correct anymore (since PowerShell 5.0), as Write-Host is now a wrapper for Write-Information and thus writes to the Information Stream (6). But what is interesting, is the fact that there are host messages that are not written to any stream. This might be the case here, where you are not able to suppress a console output by redirecting all streams. So the "warning" is probably forwarded by a host message instead of using any stream.

I saw several attempts to suppress those host messages (here and here), but as far as I can tell, nothing would help in your case.

The cited article further states:

[...] messages to the host program (which can't be suppressed or redirected).

stackprotector
  • 10,498
  • 4
  • 35
  • 64
  • 1
    Thanks for linking the GitHub issue, I did not see it on my travels. I have linked this question and my own [GitHub issue](https://github.com/PowerShell/PowerShell/issues/12563) on the PowerShell repo. – Richard Dunn May 05 '20 at 13:36
  • 1
    FYI, there is a workaround mentioned in the bug report: https://github.com/MicrosoftDocs/office-docs-powershell/issues/5454#issuecomment-624162375 basically add HideBannermessage=true to the request. – user2199860 May 11 '20 at 21:48
  • @user2199860 I have a few workarounds, but my issue boils down to two things: 1. I want a general solution to handle all warnings from any command / script. 2. I don't want to suppress warnings - they're there for a reason. – Richard Dunn May 12 '20 at 09:02
  • For a slightly more in-depth discussion about the issue, albeit a sadly apathetic response, see: [this thread](https://github.com/PowerShell/PowerShell/issues/12563) – Richard Dunn May 12 '20 at 09:05
  • @RichardDunn Sad. But I like [this](https://github.com/PowerShell/PowerShell/issues/12563#issuecomment-624643630) code to reproduce the problem, because everyone can run it in an offline environment (after `Enable-PSRemoting; Set-ExecutionPolicy RemoteSigned`). You should probably add these repro steps for future readers. In my edit I point out that it might be worth looking into "host messages" to proceed in your case. – stackprotector May 12 '20 at 09:30
  • @Thomas Thanks, but `Write-Host` is already captured by my `Invoke-Command` wrapper. – Richard Dunn May 12 '20 at 09:41
  • @RichardDunn I mean less the cmdlet `Write-Host` as the fact that there are "host messages". I'd try looking into how to access/influence them. Might be a setting or behaviour of the console. Maybe the [answer of Tuckbros](https://stackoverflow.com/a/61740151/11942268) is exactly doing that. – stackprotector May 12 '20 at 09:47
  • In my question you'll see a section regarding this: "I've even tried taking temporary control of std_out". @Tuckbros pertains to this, but I'm not sure if there's some subtle differences, I have yet to check. However, if you read this (authoritative) comment on the [PowerShell GitHub page](https://github.com/PowerShell/PowerShell/issues/12563#issuecomment-624772456), you find that there's apparently no solution. Reading between the lines, there's an internal mechanism to access the standard out writer regardless of how the programmer tries to override it. Redirection is optional. – Richard Dunn May 12 '20 at 09:55
1

Maybe not an answer but too long for a comment. Don't ask me to explain what it does nor how it works. It was found somewhere here or somewhere else. I put it here because it seems to be related to powershell and some kind of thread interactions... I let you take what you need out of it.

Here was our context : We had to run a powershell script from a bat script. The powershell script was launching some system command (zip and so on). We had hard time to collect runtime informations the right way. As a solution we had to pass the ps1 script as a parameter of another ps1 script which we called bug.ps1. Its content is shown below.

Here is the command in the .bat file :

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

and here is the content of the bug.ps1 file

# <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
Tuckbros
  • 417
  • 3
  • 13