16

I'm trying to call an async method on a .Net object instantiated in Powershell :

Add-Type -Path 'my.dll'

$myobj = new-object mynamespace.MyObj()

$res = $myobj.MyAsyncMethod("arg").Result

Write-Host "Result : " $res

When executing the script, the shell doesn't seem to wait for MyAsyncMethod().Result and displays nothing, although inspecting the return value indicates it is the correct type (Task<T>). Various other attempts, such as intermediary variables, Wait(), etc. gave no results.

Most of the stuff I found on the web is about asynchronously calling a Powershell script from C#. I want the reverse, but nobody seems to be interested in doing that. Is that even possible and if not, why ?

guillaume31
  • 13,738
  • 1
  • 32
  • 51
  • That's weird. What happens if you call `myobj.MyAsyncMethod` in a similar way but from a C# console app? – noseratio Sep 15 '14 at 18:19
  • Works on my machine. Are you sure you create your instance successfully? Because the parenthesis are not needed. – i3arnon Sep 15 '14 at 19:54
  • Whenever you use Add-Type, make sure the script runs in a completely new AppDomain/Powershell process. Loaded assemblies can't be unloaded. – Eris Sep 15 '14 at 22:00
  • @Noseratio same code in C# from a console app works. – guillaume31 Sep 16 '14 at 07:26
  • @I3arnon I think so, otherwise I would have an exception right ? I simplified the code a bit, but the MyObj constructor actually takes parameters so I guess parentheses are OK ? – guillaume31 Sep 16 '14 at 07:27
  • @Eris Do you mean that if I change the dll and call Add-Type again, the new one won't be loaded ? (Anyway, the dll didn't change and I respawned a powershell console multiple times with the same problem so I guess it isn't that) – guillaume31 Sep 16 '14 at 07:32
  • @guillaume31 when I use parenthesis I get an error. I suggest you try without them. – i3arnon Sep 16 '14 at 07:43
  • @I3arnon you mean when you new up the object or when you call the async method (or both) ? – guillaume31 Sep 16 '14 at 07:59
  • @guillaume31 when creating a new instance with `new-object`. When calling a method you need parenthesis. – i3arnon Sep 16 '14 at 08:00

3 Answers3

15

I know this is a very old thread, but it might be that you were actually getting an error from the async method but it was being swallowed because you were using .Result.

Try using .GetAwaiter().GetResult() instead of .Result and that will cause any exceptions to be bubbled up.

Mike Goatly
  • 7,380
  • 2
  • 32
  • 33
5

For long running methods, use the PSRunspacedDelegate module, which will enable you to run the task asynchronously:

$task = $myobj.MyAsyncMethod("arg");
$continuation = New-RunspacedDelegate ( [Action[System.Threading.Tasks.Task[object]]] { 
    param($t)

    # do something with $t.Result here
} );

$task.ContinueWith($continuation);

See documentation on GitHub. (Disclaimer: I wrote it).

Tahir Hassan
  • 5,715
  • 6
  • 45
  • 65
  • I've been looking for a way to use ContinueWith so it doesn't throw an execution context error! Thank you. – Brain2000 Jan 11 '19 at 18:02
3

This works for me.

Add-Type -AssemblyName 'System.Net.Http'

$myobj = new-object System.Net.Http.HttpClient

$res = $myobj.GetStringAsync("https://google.com").Result

Write-Host "Result : " $res

Perhaps check that PowerShell is configured to use .NET 4:

How can I run PowerShell with the .NET 4 runtime?

Community
  • 1
  • 1
What Would Be Cool
  • 6,204
  • 5
  • 45
  • 42