memstechtips/Winhance · error · InvalidOperationException

In-memory PowerShell script failed (exit code {exitCode}): {

Error message

In-memory PowerShell script failed (exit code {exitCode}):
{errors}

What it means

InvalidOperationException thrown by PowerShellRunner's in-memory script path (the -EncodedCommand route) when the launched powershell.exe returned a non-zero exit code AND produced stderr output. The script bytes are Base64-encoded and passed via -EncodedCommand to bypass execution policy; if PowerShell errors, the combined errors string is folded into the message.

Source

Thrown at src/Winhance.Infrastructure/Features/Common/Utilities/PowerShellRunner.cs:91

        if (string.IsNullOrEmpty(script))
            throw new ArgumentException("Script cannot be null or empty.", nameof(script));

        var scriptBytes = Encoding.Unicode.GetBytes(script);
        if (scriptBytes.Length > MaxEncodedScriptBytes)
        {
            throw new ArgumentException(
                $"Script is {scriptBytes.Length} bytes (UTF-16); -EncodedCommand path supports up to {MaxEncodedScriptBytes}. Use RunScriptAsync for larger scripts.",
                nameof(script));
        }

        var encoded = Convert.ToBase64String(scriptBytes);
        var args = $"-ExecutionPolicy Bypass -NoProfile -EncodedCommand {encoded}";

        var (output, errors, exitCode) = await LaunchPowerShellAsync(args, progress, ct).ConfigureAwait(false);

        if (exitCode != 0 && errors.Length > 0)
        {
            throw new InvalidOperationException(
                $"In-memory PowerShell script failed (exit code {exitCode}):\n{errors}");
        }

        return output.ToString();
    }

    /// <summary>
    /// Executes a PowerShell script file via Windows PowerShell 5.1 (powershell.exe).
    /// Stdout is captured line-by-line for progress reporting (Write-Host output).
    /// If execution policy blocks the script, retries with -EncodedCommand.
    /// </summary>
    public async Task<string> RunScriptFileAsync(
        string scriptPath,
        string arguments = "",
        IProgress<TaskProgressDetail>? progress = null,
        CancellationToken ct = default)
    {
        if (string.IsNullOrEmpty(scriptPath))

View on GitHub (pinned to f23d554eb2)

Solutions

  1. Read the {errors} portion of the message — it contains PowerShell's own error record (usually the most direct clue).
  2. Run the same script from a file via RunScriptFileAsync, or paste it into a powershell.exe window, to reproduce interactively.
  3. If Constrained Language Mode is active, relax the AppLocker/WDAC policy for the script path or run from a trusted location.
  4. Ensure any modules/cmdlets the script uses are installed (Install-Module) for the same user/edition running powershell.exe (5.1, not pwsh).
  5. Add explicit `try/catch` and `$ErrorActionPreference` handling inside the script so it reports a clean exit instead of surfacing as stderr.

Example fix

// before: throw only when exitCode != 0 AND errors present — a failing-but-silent script slips through
if (exitCode != 0 && errors.Length > 0)
    throw new InvalidOperationException($"In-memory PowerShell script failed (exit code {exitCode}):\n{errors}");

// after: treat any non-zero exit as failure and always include available output
if (exitCode != 0)
    throw new InvalidOperationException($"In-memory PowerShell script failed (exit code {exitCode}). Errors: {errors}. Output: {output}");
Defensive patterns

Strategy: try-catch

Validate before calling

// Optional pre-flight: ensure the script has no obvious syntax issue and required modules exist.
// At minimum, gate EncodedCommand use on script size.
bool ShouldUseEncodedCommand(byte[] scriptBytes) => scriptBytes.Length <= MaxEncodedScriptBytes;

Try / catch

catch (InvalidOperationException ex) when (ex.Message.Contains("In-memory PowerShell script failed"))
{
    // The {errors} substring carries PowerShell's own error record — surface it verbatim to the user.
    // Fall back to RunScriptFileAsync (writes the script to disk) if Constrained Language Mode blocked the encoded form.
}

Prevention

When it happens

Trigger: RunScript via the EncodedCommand path: scriptBytes (UTF-16) are under the MaxEncodedScriptBytes cap, encoded, and powershell.exe runs with -ExecutionPolicy Bypass -NoProfile -EncodedCommand <base64>. Non-zero exit + non-empty errors triggers the throw. Causes: the script itself errors (bad cmdlet, missing module, syntax), a terminating exception inside the script, or PowerShell's Constrained Language Mode blocking the script.

Common situations: The script references a module/cmdlet not present on the machine. Constrained Language Mode (AppLocker/WDAC policy) blocks the encoded script even with -ExecutionPolicy Bypass. The script reads a registry key/path that does not exist and uses -ErrorAction Stop. A different PowerShell edition (Core vs 5.1) is implied but powershell.exe (5.1) is what runs.

Related errors


AI-assisted analysis of memstechtips/Winhance@f23d554eb2 (2026-08-13). Data as JSON: /api/errors/8c23b2b05273b0c9. Report an issue: GitHub.