< 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@ca54e35c77799b76774b3805b6f075cdbc0c5fbe
Line coverage
58%
Covered lines: 24
Uncovered lines: 17
Coverable lines: 41
Total lines: 122
Line coverage: 58.5%
Branch coverage
61%
Covered branches: 11
Total branches: 18
Branch coverage: 61.1%
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@0d738bf294e6281b936d031e1979d928007495ff12/21/2025 - 06:07:10 Line coverage: 85.1% (23/27) Branch coverage: 71.4% (10/14) Total lines: 86 Tag: Kestrun/Kestrun@8cf7f77e55fd1fd046ea4e5413eb9ef96e49fe6a12/21/2025 - 19:25:34 Line coverage: 88.8% (24/27) Branch coverage: 78.5% (11/14) Total lines: 86 Tag: Kestrun/Kestrun@63eee3e6ff7662a7eb5bb3603d667daccb809f2d12/23/2025 - 19:23:04 Line coverage: 85.1% (23/27) Branch coverage: 71.4% (10/14) Total lines: 86 Tag: Kestrun/Kestrun@d062f281460e6c123c372aef61f8d957bbb6c90112/25/2025 - 19:20:44 Line coverage: 88.8% (24/27) Branch coverage: 78.5% (11/14) Total lines: 86 Tag: Kestrun/Kestrun@5251f12f253e29f8a1dfb77edc2ef50b90a4f26f12/26/2025 - 04:28:42 Line coverage: 85.1% (23/27) Branch coverage: 71.4% (10/14) Total lines: 86 Tag: Kestrun/Kestrun@078efbc0494329762e193e7b43b6ce82e494276412/28/2025 - 06:48:51 Line coverage: 88.8% (24/27) Branch coverage: 78.5% (11/14) Total lines: 86 Tag: Kestrun/Kestrun@4939cb68f5bc90e7d415ff811c4182dc0e086f3c12/28/2025 - 21:05:19 Line coverage: 85.1% (23/27) Branch coverage: 71.4% (10/14) Total lines: 86 Tag: Kestrun/Kestrun@1f86b77fc2bddfa8444a4bce466be6fec80b6db701/02/2026 - 00:16:25 Line coverage: 88.8% (24/27) Branch coverage: 78.5% (11/14) Total lines: 86 Tag: Kestrun/Kestrun@8405dc23b786b9d436fba0d65fb80baa4171e1d001/02/2026 - 21:56:10 Line coverage: 85.1% (23/27) Branch coverage: 71.4% (10/14) Total lines: 86 Tag: Kestrun/Kestrun@f60326065ebb24cf70b241e459b37baf142e6ed601/08/2026 - 08:19:25 Line coverage: 88.8% (24/27) Branch coverage: 78.5% (11/14) Total lines: 86 Tag: Kestrun/Kestrun@6ab94ca7560634c2ac58b36c2b98e2a9b1bf305d01/12/2026 - 18:03:06 Line coverage: 85.1% (23/27) Branch coverage: 71.4% (10/14) Total lines: 86 Tag: Kestrun/Kestrun@956332ccc921363590dccd99d5707fb20b50966b01/14/2026 - 21:08:55 Line coverage: 88.8% (24/27) Branch coverage: 78.5% (11/14) Total lines: 86 Tag: Kestrun/Kestrun@b584423d949a5193ed8cd45cf9df490f06d1c54501/15/2026 - 23:50:39 Line coverage: 85.1% (23/27) Branch coverage: 71.4% (10/14) Total lines: 86 Tag: Kestrun/Kestrun@2d823cb7ceae127151c8880ca073ffbb9c6322aa01/16/2026 - 21:00:04 Line coverage: 88.8% (24/27) Branch coverage: 78.5% (11/14) Total lines: 86 Tag: Kestrun/Kestrun@df9880d7a39a5a6d74ae9a66d624a7522b7ba76d01/17/2026 - 04:33:35 Line coverage: 85.1% (23/27) Branch coverage: 71.4% (10/14) Total lines: 86 Tag: Kestrun/Kestrun@aca34ea8d284564e2f9f6616dc937668dce926ba01/24/2026 - 19:35:59 Line coverage: 58.5% (24/41) Branch coverage: 61.1% (11/18) Total lines: 122 Tag: Kestrun/Kestrun@f59dcba478ea75f69584d696e5f1fb1cfa40aa5101/26/2026 - 05:11:18 Line coverage: 56% (23/41) Branch coverage: 55.5% (10/18) Total lines: 122 Tag: Kestrun/Kestrun@698a353442ed1dc2deec89391a324a20b0f74e0b02/03/2026 - 18:01:44 Line coverage: 58.5% (24/41) Branch coverage: 61.1% (11/18) Total lines: 122 Tag: Kestrun/Kestrun@ca54e35c77799b76774b3805b6f075cdbc0c5fbe 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@0d738bf294e6281b936d031e1979d928007495ff12/21/2025 - 06:07:10 Line coverage: 85.1% (23/27) Branch coverage: 71.4% (10/14) Total lines: 86 Tag: Kestrun/Kestrun@8cf7f77e55fd1fd046ea4e5413eb9ef96e49fe6a12/21/2025 - 19:25:34 Line coverage: 88.8% (24/27) Branch coverage: 78.5% (11/14) Total lines: 86 Tag: Kestrun/Kestrun@63eee3e6ff7662a7eb5bb3603d667daccb809f2d12/23/2025 - 19:23:04 Line coverage: 85.1% (23/27) Branch coverage: 71.4% (10/14) Total lines: 86 Tag: Kestrun/Kestrun@d062f281460e6c123c372aef61f8d957bbb6c90112/25/2025 - 19:20:44 Line coverage: 88.8% (24/27) Branch coverage: 78.5% (11/14) Total lines: 86 Tag: Kestrun/Kestrun@5251f12f253e29f8a1dfb77edc2ef50b90a4f26f12/26/2025 - 04:28:42 Line coverage: 85.1% (23/27) Branch coverage: 71.4% (10/14) Total lines: 86 Tag: Kestrun/Kestrun@078efbc0494329762e193e7b43b6ce82e494276412/28/2025 - 06:48:51 Line coverage: 88.8% (24/27) Branch coverage: 78.5% (11/14) Total lines: 86 Tag: Kestrun/Kestrun@4939cb68f5bc90e7d415ff811c4182dc0e086f3c12/28/2025 - 21:05:19 Line coverage: 85.1% (23/27) Branch coverage: 71.4% (10/14) Total lines: 86 Tag: Kestrun/Kestrun@1f86b77fc2bddfa8444a4bce466be6fec80b6db701/02/2026 - 00:16:25 Line coverage: 88.8% (24/27) Branch coverage: 78.5% (11/14) Total lines: 86 Tag: Kestrun/Kestrun@8405dc23b786b9d436fba0d65fb80baa4171e1d001/02/2026 - 21:56:10 Line coverage: 85.1% (23/27) Branch coverage: 71.4% (10/14) Total lines: 86 Tag: Kestrun/Kestrun@f60326065ebb24cf70b241e459b37baf142e6ed601/08/2026 - 08:19:25 Line coverage: 88.8% (24/27) Branch coverage: 78.5% (11/14) Total lines: 86 Tag: Kestrun/Kestrun@6ab94ca7560634c2ac58b36c2b98e2a9b1bf305d01/12/2026 - 18:03:06 Line coverage: 85.1% (23/27) Branch coverage: 71.4% (10/14) Total lines: 86 Tag: Kestrun/Kestrun@956332ccc921363590dccd99d5707fb20b50966b01/14/2026 - 21:08:55 Line coverage: 88.8% (24/27) Branch coverage: 78.5% (11/14) Total lines: 86 Tag: Kestrun/Kestrun@b584423d949a5193ed8cd45cf9df490f06d1c54501/15/2026 - 23:50:39 Line coverage: 85.1% (23/27) Branch coverage: 71.4% (10/14) Total lines: 86 Tag: Kestrun/Kestrun@2d823cb7ceae127151c8880ca073ffbb9c6322aa01/16/2026 - 21:00:04 Line coverage: 88.8% (24/27) Branch coverage: 78.5% (11/14) Total lines: 86 Tag: Kestrun/Kestrun@df9880d7a39a5a6d74ae9a66d624a7522b7ba76d01/17/2026 - 04:33:35 Line coverage: 85.1% (23/27) Branch coverage: 71.4% (10/14) Total lines: 86 Tag: Kestrun/Kestrun@aca34ea8d284564e2f9f6616dc937668dce926ba01/24/2026 - 19:35:59 Line coverage: 58.5% (24/41) Branch coverage: 61.1% (11/18) Total lines: 122 Tag: Kestrun/Kestrun@f59dcba478ea75f69584d696e5f1fb1cfa40aa5101/26/2026 - 05:11:18 Line coverage: 56% (23/41) Branch coverage: 55.5% (10/18) Total lines: 122 Tag: Kestrun/Kestrun@698a353442ed1dc2deec89391a324a20b0f74e0b02/03/2026 - 18:01:44 Line coverage: 58.5% (24/41) Branch coverage: 61.1% (11/18) Total lines: 122 Tag: Kestrun/Kestrun@ca54e35c77799b76774b3805b6f075cdbc0c5fbe

Metrics

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

File(s)

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

#LineLine coverage
 1using System.Globalization;
 2using System.Management.Automation;
 3using Serilog.Events;
 4
 5namespace Kestrun.Languages;
 6
 7/// <summary>
 8/// Shared helper methods for configuring and invoking PowerShell scripts in a consistent manner.
 9/// Extracted to reduce duplication between <see cref="PowerShellDelegateBuilder"/> and script-based probes.
 10/// </summary>
 11internal static class PowerShellExecutionHelpers
 12{
 13    /// <summary>
 14    /// Sets variables in the PowerShell runspace from the provided argument dictionary.
 15    /// Existing variables are overwritten. Null or empty collections are ignored.
 16    /// </summary>
 17    internal static void SetVariables(PowerShell ps, IReadOnlyDictionary<string, object?>? arguments, Serilog.ILogger lo
 18    {
 719        if (arguments is null || arguments.Count == 0)
 20        {
 421            return;
 22        }
 23
 324        if (log.IsEnabled(LogEventLevel.Verbose))
 25        {
 026            log.Verbose("Setting PowerShell variables from arguments: {Count}", arguments.Count);
 27        }
 328        var proxy = ps.Runspace.SessionStateProxy;
 1829        foreach (var kv in arguments)
 30        {
 631            proxy.SetVariable(kv.Key, kv.Value);
 32        }
 333    }
 34
 35    /// <summary>
 36    /// Adds a script block to the pipeline.
 37    /// </summary>
 438    internal static void AddScript(PowerShell ps, string code) => _ = ps.AddScript(code);
 39
 40    /// <summary>
 41    /// Adds a culture initialization prelude to the PowerShell pipeline.
 42    /// </summary>
 43    /// <param name="ps">The PowerShell instance to configure.</param>
 44    /// <param name="cultureName">The culture name to apply.</param>
 45    /// <param name="log">The logger instance.</param>
 46    internal static void AddCulturePrelude(PowerShell ps, string? cultureName, Serilog.ILogger log)
 47    {
 048        if (string.IsNullOrWhiteSpace(cultureName))
 49        {
 050            return;
 51        }
 52
 53        string normalized;
 54        try
 55        {
 056            normalized = CultureInfo.GetCultureInfo(cultureName).Name;
 057        }
 058        catch (CultureNotFoundException)
 59        {
 060            return;
 61        }
 62
 063        if (log.IsEnabled(LogEventLevel.Verbose))
 64        {
 065            log.Verbose("Applying PowerShell culture: {Culture}", normalized);
 66        }
 67
 068        var escaped = normalized.Replace("'", "''", StringComparison.Ordinal);
 069        var prelude = "$__krCulture = [System.Globalization.CultureInfo]::GetCultureInfo('" + escaped + "'); " +
 070                      "[System.Globalization.CultureInfo]::CurrentCulture = $__krCulture; " +
 071                      "[System.Globalization.CultureInfo]::CurrentUICulture = $__krCulture;";
 072        _ = ps.AddScript(prelude);
 073    }
 74
 75    /// <summary>
 76    /// Invokes the configured PowerShell pipeline asynchronously with cooperative cancellation.
 77    /// Cancellation attempts to stop the pipeline gracefully.
 78    /// </summary>
 79    internal static async Task<PSDataCollection<PSObject>> InvokeAsync(this PowerShell ps, Serilog.ILogger log, Cancella
 80    {
 1781        if (log.IsEnabled(LogEventLevel.Verbose))
 82        {
 083            log.Verbose("Executing PowerShell script...");
 84        }
 85
 86        // If cancellation is already requested before the pipeline starts, do not invoke at all.
 87        // On some platforms/runtimes, calling Stop() before invocation begins is a no-op and
 88        // the pipeline may still start and run indefinitely.
 1789        ct.ThrowIfCancellationRequested();
 90
 1791        using var registration = ct.Register(static state =>
 1792        {
 393            var shell = (PowerShell)state!;
 694            try { shell.Stop(); } catch { /* ignored */ }
 2095        }, ps);
 96
 97        try
 98        {
 1799            var invokeTask = ps.InvokeAsync();
 100
 101            // If cancellation is requested during the short window between registration and invocation,
 102            // attempt to stop immediately.
 17103            if (ct.IsCancellationRequested)
 104            {
 2105                try { ps.Stop(); } catch { /* ignored */ }
 106            }
 107
 17108            var results = await invokeTask.ConfigureAwait(false);
 109
 14110            if (log.IsEnabled(LogEventLevel.Verbose))
 111            {
 0112                log.Verbose("PowerShell script executed with {Count} results.", results.Count);
 113            }
 14114            return results;
 115        }
 3116        catch (PipelineStoppedException) when (ct.IsCancellationRequested)
 117        {
 118            // Convert PipelineStoppedException to OperationCanceledException when cancellation was requested
 3119            throw new OperationCanceledException("PowerShell pipeline was stopped due to cancellation.", ct);
 120        }
 14121    }
 122}