Private/Invoke-NSPEntraConnectLocalRead.ps1

function Invoke-NSPEntraConnectLocalRead {
    [CmdletBinding()]
    param([Parameter(Mandatory)][scriptblock]$ReadScript)
    if ($PSVersionTable.PSEdition -ne 'Core') { return & $ReadScript }
    # ADSync targets Windows PowerShell. Keep output in memory, with no topology file.
    $exe = Join-Path $env:SystemRoot 'System32\WindowsPowerShell\v1.0\powershell.exe'
    if (-not (Test-Path -LiteralPath $exe)) { throw 'Windows PowerShell 5.1 is required on the sync server.' }
    $code = '$ErrorActionPreference="Stop"; try { $state = & {' + $ReadScript.ToString() +
        '}; [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes([Management.Automation.PSSerializer]::Serialize($state,20))) } catch { [Console]::Error.WriteLine($_.Exception.Message); exit 1 }'
    $info = New-Object Diagnostics.ProcessStartInfo
    $info.FileName = $exe
    $info.Arguments = '-NoLogo -NoProfile -NonInteractive -EncodedCommand ' + [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($code))
    $info.UseShellExecute = $false; $info.CreateNoWindow = $true
    $info.RedirectStandardOutput = $true; $info.RedirectStandardError = $true
    $process = [Diagnostics.Process]::Start($info)
    try {
        $output = $process.StandardOutput.ReadToEndAsync()
        $errors = $process.StandardError.ReadToEndAsync()
        if (-not $process.WaitForExit(120000)) { $process.Kill(); throw 'The local sync-rule read timed out. Try again on the sync server.' }
        if ($process.ExitCode -ne 0) { throw ('The local sync-rule read failed: ' + $errors.Result.Trim()) }
        [Management.Automation.PSSerializer]::Deserialize([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($output.Result.Trim())))
    } finally { $process.Dispose() }
}