{"record":{"id":"72758e772c38177f","repo":"BornToBeRoot/NETworkManager","slug":"string-join-ps-streams-error","errorCode":null,"errorMessage":"string.Join(\"; \", ps.Streams.Error)","messagePattern":"string\\.Join\\(\"; \", ps\\.Streams\\.Error\\)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"Source/NETworkManager.Models/Firewall/Firewall.cs","lineNumber":198,"sourceCode":"    /// </param>\n    /// <exception cref=\"Exception\">\n    /// Thrown when the PowerShell pipeline reports one or more errors.\n    /// </exception>\n    public static async Task SetRuleEnabledAsync(FirewallRule rule, bool enabled)\n    {\n        await RunspaceLock.WaitAsync();\n        try\n        {\n            await Task.Run(() =>\n            {\n                using var ps = SMA.PowerShell.Create();\n                ps.Runspace = SharedRunspace;\n\n                ps.AddScript($@\"{(enabled ? \"Enable\" : \"Disable\")}-NetFirewallRule -Name '{rule.Id}'\");\n                ps.Invoke();\n\n                if (ps.Streams.Error.Count > 0)\n                    throw new Exception(string.Join(\"; \", ps.Streams.Error));\n            });\n        }\n        finally\n        {\n            RunspaceLock.Release();\n        }\n    }\n\n    /// <summary>\n    /// Permanently removes the given <paramref name=\"rule\"/> by running\n    /// <c>Remove-NetFirewallRule</c> against the rule's internal <see cref=\"FirewallRule.Id\"/>.\n    /// </summary>\n    /// <param name=\"rule\">\n    /// The firewall rule to delete.\n    /// </param>\n    /// <exception cref=\"Exception\">\n    /// Thrown when the PowerShell pipeline reports one or more errors.\n    /// </exception>","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/BornToBeRoot/NETworkManager/blob/2780d65469917a296dbc15f206107d72e2d0115c/Source/NETworkManager.Models/Firewall/Firewall.cs#L180-L216","documentation":"SetRuleEnabledAsync runs Enable-NetFirewallRule or Disable-NetFirewallRule in a shared PowerShell runspace. If the cmdlet writes any records to the error stream, the method wraps them (joined with \"; \") in a generic System.Exception and throws. The message is the raw PowerShell error text, typically a non-terminating error such as a rule name that does not exist.","triggerScenarios":"Calling SetRuleEnabledAsync(rule, enabled) when rule.Id does not match an existing firewall rule name (e.g. the rule was deleted externally or the Id is stale from a cached GetRulesAsync snapshot), or when the process lacks admin rights so the NetSecurity cmdlet fails.","commonSituations":"App not running elevated (NetFirewall cmdlets require administrator); a stale FirewallRule object after the rule was removed by another tool or group policy refresh; localized Windows error text making the message hard to parse.","solutions":["Run the application elevated (as administrator) before calling firewall APIs.","Re-fetch the rule list with GetRulesAsync and retry with a fresh FirewallRule whose Id still exists.","Catch the exception and surface the joined PowerShell error text to the user, since it contains the actual NetSecurity cmdlet error.","Verify the rule name manually with PowerShell: Enable-NetFirewallRule -Name '<rule.Id>' to reproduce the error text."],"exampleFix":"// before\nawait Firewall.SetRuleEnabledAsync(staleRule, true);\n// after\nvar rules = await Firewall.GetRulesAsync();\nvar fresh = rules.FirstOrDefault(r => r.Id == staleRule.Id) ?? throw new InvalidOperationException($\"Rule {staleRule.Id} no longer exists\");\nawait Firewall.SetRuleEnabledAsync(fresh, true);","handlingStrategy":"try-catch","validationCode":"// refresh and verify the rule exists before toggling\nvar rules = await Firewall.GetRulesAsync();\nif (!rules.Any(r => r.Id == rule.Id)) throw new InvalidOperationException($\"Firewall rule '{rule.Id}' no longer exists\");","typeGuard":"static bool RuleExists(IEnumerable<FirewallRule> rules, FirewallRule rule) => rules.Any(r => r != null && !string.IsNullOrEmpty(r.Id) && r.Id == rule.Id);","tryCatchPattern":"try\n{\n    await Firewall.SetRuleEnabledAsync(rule, enabled);\n}\ncatch (Exception ex) when (ex.Message.Contains(\"NetFirewallRule\"))\n{\n    Log.Warn($\"Firewall toggle failed: {ex.Message}\");\n    // surface ex.Message (PowerShell error text) to the user\n}","preventionTips":["Always run elevated when touching Windows Firewall rules.","Refresh the rule list before acting on a cached FirewallRule object.","Log the full joined error text; localized Windows messages carry the real cause."],"tags":["powershell","firewall","windows"],"backgroundTag":"api-error-response","analyzedSha":"2780d65469917a296dbc15f206107d72e2d0115c","analyzedAt":"2026-09-12T17:00:17.986Z","contentChangedAt":"2026-09-12T17:00:17.986Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}