Private/Invoke-EFIsolatedCheck.ps1

function Invoke-EFIsolatedCheck {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateNotNull()]
        [scriptblock]$ScriptBlock,

        [Parameter(Mandatory)]
        [ValidateNotNull()]
        [hashtable]$InputData,

        [ValidateRange(100, 603000)]
        [int]$TimeoutMilliseconds,

        [ValidateRange(0, 10000)]
        [int]$StartupAllowanceMilliseconds = 0,

        [ValidateNotNullOrEmpty()]
        [string]$Activity = 'The isolated check'
    )

    $inputJson = $InputData | ConvertTo-Json -Compress -Depth 8
    $inputBase64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($inputJson))
    $checkBase64 = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($ScriptBlock.ToString()))
    $bootstrap = @"
`$ErrorActionPreference = 'Stop'
`$ProgressPreference = 'SilentlyContinue'
try {
    `$inputJson = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('$inputBase64'))
    `$inputObject = `$inputJson | ConvertFrom-Json -ErrorAction Stop
    `$checkText = [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('$checkBase64'))
    `$check = [scriptblock]::Create(`$checkText)
    `$result = & `$check `$inputObject
    [Console]::Out.Write((`$result | ConvertTo-Json -Compress -Depth 8))
    exit 0
}
catch {
    [Console]::Error.Write(`$_.Exception.GetType().FullName)
    exit 1
}
"@


    $engineFileName = if ($PSVersionTable.PSEdition -eq 'Core') { 'pwsh.exe' } else { 'powershell.exe' }
    $powerShellPath = Join-Path $PSHOME $engineFileName
    if (-not (Test-Path -LiteralPath $powerShellPath -PathType Leaf)) {
        throw [InvalidOperationException]::new(
            "$Activity requires '$engineFileName' in the active PowerShell engine folder, but it was not found."
        )
    }

    $startInfo = [Diagnostics.ProcessStartInfo]::new()
    $startInfo.FileName = $powerShellPath
    $readerScript = @'
[Console]::InputEncoding = [Text.UTF8Encoding]::new($false)
$workerText = [Console]::In.ReadToEnd()
if ($workerText.Length -gt 0 -and [int]$workerText[0] -eq 0xFEFF) { $workerText = $workerText.Substring(1) }
& ([scriptblock]::Create($workerText))
'@

    $encodedReader = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($readerScript))
    $startInfo.Arguments = "-NoLogo -NoProfile -NonInteractive -EncodedCommand $encodedReader"
    $startInfo.UseShellExecute = $false
    $startInfo.CreateNoWindow = $true
    $startInfo.RedirectStandardInput = $true
    $startInfo.RedirectStandardOutput = $true
    $startInfo.RedirectStandardError = $true

    $process = [Diagnostics.Process]::new()
    $process.StartInfo = $startInfo
    $outputTask = $null
    $errorTask = $null
    $processStarted = $false
    $stopwatch = [Diagnostics.Stopwatch]::StartNew()
    try {
        if (-not $process.Start()) {
            throw [InvalidOperationException]::new("$Activity could not start its isolated worker process.")
        }
        $processStarted = $true
        $outputTask = $process.StandardOutput.ReadToEndAsync()
        $errorTask = $process.StandardError.ReadToEndAsync()
        $hardTimeout = [int64]$TimeoutMilliseconds + [int64]$StartupAllowanceMilliseconds
        $inputBytes = [Text.Encoding]::ASCII.GetBytes($bootstrap + [Environment]::NewLine)
        $inputTask = $process.StandardInput.BaseStream.WriteAsync($inputBytes, 0, $inputBytes.Length)
        if (-not $inputTask.Wait([int]$hardTimeout)) {
            try { $process.Kill() }
            catch {
                throw [TimeoutException]::new("$Activity exceeded its time limit and its isolated worker could not be stopped.")
            }
            if (-not $process.WaitForExit(5000)) {
                throw [TimeoutException]::new("$Activity exceeded its time limit and worker termination could not be confirmed.")
            }
            throw [TimeoutException]::new("$Activity did not finish within its time limit.")
        }
        $null = $inputTask.GetAwaiter().GetResult()
        $process.StandardInput.Close()
        $remainingMilliseconds = [math]::Max(1, $hardTimeout - $stopwatch.ElapsedMilliseconds)
        if (-not $process.WaitForExit([int]$remainingMilliseconds)) {
            try { $process.Kill() }
            catch {
                throw [TimeoutException]::new("$Activity exceeded its time limit and its isolated worker could not be stopped.")
            }
            if (-not $process.WaitForExit(5000)) {
                throw [TimeoutException]::new("$Activity exceeded its time limit and worker termination could not be confirmed.")
            }
            throw [TimeoutException]::new("$Activity did not finish within its time limit.")
        }

        $standardOutput = $outputTask.GetAwaiter().GetResult()
        $null = $errorTask.GetAwaiter().GetResult()
        if ($process.ExitCode -ne 0) {
            throw [InvalidOperationException]::new("$Activity could not complete in its isolated worker.")
        }
        if ([string]::IsNullOrWhiteSpace($standardOutput)) {
            throw [InvalidOperationException]::new("$Activity returned no trustworthy result.")
        }
        try {
            return $standardOutput | ConvertFrom-Json -ErrorAction Stop
        }
        catch {
            throw [InvalidOperationException]::new("$Activity returned an unreadable result.")
        }
    }
    finally {
        $stopwatch.Stop()
        if ($processStarted -and -not $process.HasExited) {
            try {
                $process.Kill()
                $null = $process.WaitForExit(5000)
            }
            catch { Write-Verbose "$Activity worker cleanup could not be confirmed." }
        }
        if ($null -ne $process) { $process.Dispose() }
    }
}