< Summary - Kestrun — Combined Coverage

Information
Class: Kestrun.Languages.PowerShellExecutionHelpers
Assembly: Kestrun
File(s): /home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/Languages/PowerShellExecutionHelpers.cs
Tag: Kestrun/Kestrun@0d738bf294e6281b936d031e1979d928007495ff
Line coverage
88%
Covered lines: 24
Uncovered lines: 3
Coverable lines: 27
Total lines: 86
Line coverage: 88.8%
Branch coverage
78%
Covered branches: 11
Total branches: 14
Branch coverage: 78.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 10/13/2025 - 16:52:37 Line coverage: 52.3% (11/21) Branch coverage: 33.3% (4/12) Total lines: 64 Tag: Kestrun/Kestrun@10d476bee71c71ad215bb8ab59f219887b5b4a5e10/15/2025 - 01:01:18 Line coverage: 76.1% (16/21) Branch coverage: 75% (9/12) Total lines: 64 Tag: Kestrun/Kestrun@7c4ce528870211ad6c2d2398c31ec13097fc584012/18/2025 - 21:41:58 Line coverage: 88.8% (24/27) Branch coverage: 78.5% (11/14) Total lines: 86 Tag: Kestrun/Kestrun@0d738bf294e6281b936d031e1979d928007495ff 10/13/2025 - 16:52:37 Line coverage: 52.3% (11/21) Branch coverage: 33.3% (4/12) Total lines: 64 Tag: Kestrun/Kestrun@10d476bee71c71ad215bb8ab59f219887b5b4a5e10/15/2025 - 01:01:18 Line coverage: 76.1% (16/21) Branch coverage: 75% (9/12) Total lines: 64 Tag: Kestrun/Kestrun@7c4ce528870211ad6c2d2398c31ec13097fc584012/18/2025 - 21:41:58 Line coverage: 88.8% (24/27) Branch coverage: 78.5% (11/14) Total lines: 86 Tag: Kestrun/Kestrun@0d738bf294e6281b936d031e1979d928007495ff

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
SetVariables(...)87.5%8887.5%
AddScript(...)100%11100%
InvokeAsync()66.66%6686.66%

File(s)

/home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/Languages/PowerShellExecutionHelpers.cs

#LineLine coverage
 1using System.Management.Automation;
 2using Serilog.Events;
 3
 4namespace Kestrun.Languages;
 5
 6/// <summary>
 7/// Shared helper methods for configuring and invoking PowerShell scripts in a consistent manner.
 8/// Extracted to reduce duplication between <see cref="PowerShellDelegateBuilder"/> and script-based probes.
 9/// </summary>
 10internal static class PowerShellExecutionHelpers
 11{
 12    /// <summary>
 13    /// Sets variables in the PowerShell runspace from the provided argument dictionary.
 14    /// Existing variables are overwritten. Null or empty collections are ignored.
 15    /// </summary>
 16    internal static void SetVariables(PowerShell ps, IReadOnlyDictionary<string, object?>? arguments, Serilog.ILogger lo
 17    {
 718        if (arguments is null || arguments.Count == 0)
 19        {
 420            return;
 21        }
 22
 323        if (log.IsEnabled(LogEventLevel.Verbose))
 24        {
 025            log.Verbose("Setting PowerShell variables from arguments: {Count}", arguments.Count);
 26        }
 327        var proxy = ps.Runspace.SessionStateProxy;
 1828        foreach (var kv in arguments)
 29        {
 630            proxy.SetVariable(kv.Key, kv.Value);
 31        }
 332    }
 33
 34    /// <summary>
 35    /// Adds a script block to the pipeline.
 36    /// </summary>
 437    internal static void AddScript(PowerShell ps, string code) => _ = ps.AddScript(code);
 38
 39    /// <summary>
 40    /// Invokes the configured PowerShell pipeline asynchronously with cooperative cancellation.
 41    /// Cancellation attempts to stop the pipeline gracefully.
 42    /// </summary>
 43    internal static async Task<PSDataCollection<PSObject>> InvokeAsync(this PowerShell ps, Serilog.ILogger log, Cancella
 44    {
 1645        if (log.IsEnabled(LogEventLevel.Verbose))
 46        {
 047            log.Verbose("Executing PowerShell script...");
 48        }
 49
 50        // If cancellation is already requested before the pipeline starts, do not invoke at all.
 51        // On some platforms/runtimes, calling Stop() before invocation begins is a no-op and
 52        // the pipeline may still start and run indefinitely.
 1653        ct.ThrowIfCancellationRequested();
 54
 1655        using var registration = ct.Register(static state =>
 1656        {
 357            var shell = (PowerShell)state!;
 658            try { shell.Stop(); } catch { /* ignored */ }
 1959        }, ps);
 60
 61        try
 62        {
 1663            var invokeTask = ps.InvokeAsync();
 64
 65            // If cancellation is requested during the short window between registration and invocation,
 66            // attempt to stop immediately.
 1667            if (ct.IsCancellationRequested)
 68            {
 269                try { ps.Stop(); } catch { /* ignored */ }
 70            }
 71
 1672            var results = await invokeTask.ConfigureAwait(false);
 73
 1374            if (log.IsEnabled(LogEventLevel.Verbose))
 75            {
 076                log.Verbose("PowerShell script executed with {Count} results.", results.Count);
 77            }
 1378            return results;
 79        }
 380        catch (PipelineStoppedException) when (ct.IsCancellationRequested)
 81        {
 82            // Convert PipelineStoppedException to OperationCanceledException when cancellation was requested
 383            throw new OperationCanceledException("PowerShell pipeline was stopped due to cancellation.", ct);
 84        }
 1385    }
 86}