3

I'm using the PowerShell (v7) script below to customize AWS SSO Login FLow. It's based on a working .net implementation:

$ErrorActionPreference = "Stop"
Import-Module -Name "AWSPowerShell.NetCore"

$profileName = "my-sso-profile"

$chain = New-Object Amazon.Runtime.CredentialManagement.CredentialProfileStoreChain

$credentials = $null
$chain.TryGetAWSCredentials($profileName, [ref]$credentials)

$ssoCredentials = [Amazon.Runtime.SSOAWSCredentials]$credentials
$ssoCredentials.Options.ClientName = "Example-SSO-Script"
$ssoCredentials.Options.SsoVerificationCallback = [System.Action[Amazon.Runtime.SsoVerificationArguments]]{
    param($x)
    # Launch SSO Login Flow in Browser
    Start-Process $x.VerificationUriComplete
}

Set-AWSCredential -Credential $ssoCredentials
# Print details about current Credential
Get-StsCallerIdentity

Error

When I run this script in Powershell (v7), I get an exception:

There is no Runspace available to run scripts in this thread. You can provide one in the DefaultRunspace property of the System.Management.Automation.Runspaces.Runspace type. The script block you attempted to invoke was: param($x) …cationUriComplete

Looks like there is an issue invoking my script delegate in$ssoCredentials.Options.SsoVerificationCallback

Question

How can I configure my Script/PowerShell Session so that my SsoVerificationCallback delegate executes without throwing an error?

Research

I'm guessing the problem has something to do with the C# code invoking the SsoVerificationCallback delegate, which is now a PSScriptBlock(?), and something going wrong marshalling back and forth between C# and PowerShell.

Looking around SO, the SsoVerificationCallback invocation isn't Async, though it is invoked inside an async method GetSsoTokenAsync, so I don't think Runspace issus using async APIs from Powershell applies.

And I'm not making a web call directly, so tips in blog such as https://www.agilepointnxblog.com/powershell-error-there-is-no-runspace-available-to-run-scripts-in-this-thread/ recommended setting [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $null also didn't make any impact.

Philip Pittle
  • 11,821
  • 8
  • 59
  • 123

1 Answers1

1

While I'm hazy on the details, the following general information may be helpful:

While PowerShell script blocks ({ ... }) generally can be used as .NET delegates, their invocation only succeeds if the calling thread has a PowerShell runspace associated with it - script blocks cannot execute otherwise.

If a given script-block-based delegate is called (back) from the PowerShell session's own foreground thread, this requirement is by definition met; e.g., passing a script block as a MatchEvaluator delegate to [regex]::Replace():

PS> [regex]::Replace('woo', 'o$', { param($m) $m.Value + 't!' })
woot!

However, it seems that in your case a different thread - one without an associated PowerShell runspace - is calling your script-block-based delegate, which results in the error you saw.

There may be a - cumbersome, nontrivial - workaround based on ad-hoc compilation of C# code, as shown in this answer.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    Thank you for this - it was extremely helpful. Thinking now I'll need to add some additional C# code to handle the multi-threading so a PowerShell doesn't need to pass in a delegate across multiple threads. – Philip Pittle Dec 01 '21 at 18:36
  • 1
    Glad to hear it, @PhilipPittle. Good luck, and if you find a solution, I encourage you to post it as an answer here. – mklement0 Dec 01 '21 at 18:57