PowerShell 7 silently "swallows" InvalidOperationException Error

Created on 19 Jun 2020  Â·  8Comments  Â·  Source: PowerShell/PowerShell

Steps to reproduce

This is a function I wrote today:

function Get-PingableServers {
    [CmdletBinding()]
    Param (
        [Parameter(Position = 0, ValueFromPipeline = $true)]
        [string[]]$Server
    )

    begin {
        $pingTasks = [System.Collections.Generic.Dictionary[string, System.Threading.Tasks.Task]]::new()
        $ping = [System.Net.NetworkInformation.Ping]::new()
    }

    process {
        foreach ($pingTarget in $Server) {
            $pingTasks.Add($pingTarget, $ping.SendPingAsync($pingTarget, $PingTimeoutMS))
        }
    }

    end {
        while ($pingTasks.Values.IsCompleted -contains $false) {
            Start-Sleep -Milliseconds 200
        }
        $pingTasks.GetEnumerator().Where{ $_.Value.Result.Status -eq 0 }.Key
    }
}

Expected behavior

When passing in more than 1 Hostname, it should throw a System.Management.Automation.MethodInvocationException
and fail. This is what happens in PowerShell 5.1:

jantari@NBFFM0037:C:\Users\jantari
└─ PS> Get-PingableServers -Server fakehost01, fakehost02
Ausnahme beim Aufrufen von "SendPingAsync" mit 2 Argument(en):  "Es läuft bereits ein asynchroner Aufruf. Er muss abgeschlossen oder abgebrochen werden,
bevor Sie diese Methode aufrufen können."
In Zeile:15 Zeichen:13
+             $pingTasks.Add($pingTarget, $ping.SendPingAsync($pingTarg ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : InvalidOperationException

I am terribly sorry for the localized german error message, but that is a catastrophe Microsoft is responsible for and not me. It basically says there is already an asynchronous procedure running and it must be completed before the method can be called again.

Actual behavior

In PowerShell 7.0.2 and PowerShell 7.1.0-preview3, there is just no output. It doesn't work, but since there's no error message it's also impossible to diagnose. I had to run this in PowerShell 5.1 to learn what was wrong.

jantari@NBFFM0037:C:\Users\jantari
└─ PS> Get-PingableServers -Server fakehost01, fakehost02
jantari@NBFFM0037:C:\Users\jantari
└─ PS>

Environment data

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

ErrorActionPreference is set to continue for all shells.

jantari@NBFFM0037:C:\Users\jantari
└─ PS> $ErrorActionPreference
Continue
Issue-Question Resolution-Answered WG-Engine

All 8 comments

Is there anything stored in $Error in these cases?

$Error | Format-List -Force

If so, it may be a bug in the ConciseView error formatting; try setting $ErrorView = 'NormalView' and see if the errors appear there.

No, $Error is empty and changing the view does not make anything appear either.

Very strange... and I'm seeing the same, as well. Even wrapping the code that should be throwing in a try/catch and trying to handle the error manually gives me absolutely nothing.

PowerShell utilizes .Net API and the API is not throw. You should ask in .Net Rintime repository.

In .NET Framework 4.8, InvalidOperationException is thrown out of Ping.SendPingAsync if an asynchronous operation is already in progress. The implementation uses TaskCompletionSource to wrap a task around an event-based asynchronous operation.

In .NET 5 Preview 4, Ping.SendPingAsync instead returns a task whose Task.Exception contains an InvalidOperationException. The implementation uses C# async methods.

When PowerShell code reads the Task\.Result property, an exception is thrown but PowerShell swallows it. If PowerShell code instead calls the underlying Task\.get_Result() accessor method, then PowerShell does not swallow the exception.

Windows PowerShell 5.1 using .NET Framework 4.8 on Windows 10.0.19041

PS C:\> $ping = [System.Net.NetworkInformation.Ping]::new()
PS C:\> $pingtask1 = $ping.SendPingAsync("fakehost1"); $pingtask2 = $ping.SendPingAsync("fakehost2")
Exception calling "SendPingAsync" with "1" argument(s): "An asynchronous call is already in progress. It must be completed or canceled before you can call this method."
At line:1 char:48
+ ... PingAsync("fakehost1"); $pingtask2 = $ping.SendPingAsync("fakehost2")
+                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : InvalidOperationException

PowerShell 7.1.0-preview.3 using .NET 5.0.0-preview.4.20251.6 on Windows 10.0.19041

PS C:\> $ping = [System.Net.NetworkInformation.Ping]::new()
PS C:\> $pingtask1 = $ping.SendPingAsync("fakehost1"); $pingtask2 = $ping.SendPingAsync("fakehost2")
PS C:\> $pingtask1

Id IsCompleted Status
-- ----------- ------
3  True        RanToCompletion

PS C:\> $pingtask2

Id IsCompleted Status
-- ----------- ------
4  True        Faulted

PS C:\> $pingtask2.Exception

InnerExceptions : {System.InvalidOperationException: An asynchronous call is already in progress. It must be completed or canceled before you can call this method.
                     at System.Net.NetworkInformation.Ping.CheckStart()
                     at System.Net.NetworkInformation.Ping.GetAddressAndSendAsync(String hostNameOrAddress, Int32 timeout, Byte[] buffer, PingOptions options)}
Message         : One or more errors occurred. (An asynchronous call is already in progress. It must be completed or canceled before you can call this method.)
TargetSite      :
StackTrace      :
Data            : {}
InnerException  : System.InvalidOperationException: An asynchronous call is already in progress. It must be completed or canceled before you can call this method.
                     at System.Net.NetworkInformation.Ping.CheckStart()
                     at System.Net.NetworkInformation.Ping.GetAddressAndSendAsync(String hostNameOrAddress, Int32 timeout, Byte[] buffer, PingOptions options)
HelpLink        :
Source          :
HResult         : −2146233088


PS C:\> $pingtask2.Result
PS C:\> $pingtask2.get_Result()
MethodInvocationException: Exception calling "get_Result" with "0" argument(s): "One or more errors occurred. (An asynchronous call is already in progress. It must be completed or canceled before you can call this method.)"
PS C:\>

Ah, I see. Yeah, PowerShell doesn't really allow property accesses to throw in general. You would need to check the Exception property I suppose. 🤔

Just as a general FYI, the .NET Core API for Ping is... weird, at best. We filed an issue in dotnet/runtime months ago to try to get at least some of the issues with it fixed, but not a lot of progress has been made. If you can comment on that issue with any additional problems you find there it might help get some of them sorted out/prioritized.

PowerShell doesn't really allow property accesses to throw in general.

We could discuss this in new issue.

This issue has been marked as answered and has not had any activity for 1 day. It has been closed for housekeeping purposes.

Was this page helpful?
0 / 5 - 0 ratings