Fixed more threading issues in PowerShell cmdlets to ensure WriteObject and WriteError are only called from the main thread

This commit is contained in:
GraceSolutions
2025-04-15 12:34:43 -04:00
parent 9c4d3f2eb3
commit 2b31bf23a9
8 changed files with 267 additions and 236 deletions
@@ -34,29 +34,34 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
protected override void ProcessRecordInternal()
{
try
var cronService = new CronService(ApiClient, Logger);
// Use our safe execution method
var result = ExecuteAsyncTask(() => cronService.ToggleJobAsync(Uuid, true));
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
var cronService = new CronService(ApiClient, Logger);
var task = Task.Run(async () => await cronService.ToggleJobAsync(Uuid, true));
var result = task.GetAwaiter().GetResult();
WriteVerbose($"Cron job {Uuid} enabled: {result.Result}");
// Apply the changes if requested
if (Apply.IsPresent)
{
var applyTask = Task.Run(async () => await cronService.ApplyChangesAsync());
var applyResult = applyTask.GetAwaiter().GetResult();
WriteVerbose($"Cron changes applied: {applyResult.Status}");
}
return;
}
catch (Exception ex)
WriteVerbose($"Cron job {Uuid} enabled: {result.Result}");
// Apply the changes if requested
if (Apply.IsPresent)
{
HandleException(ex);
// Use our safe execution method
var applyResult = ExecuteAsyncTask(() => cronService.ApplyChangesAsync());
// Only continue if no exception occurred
if (ProcessingException != null || applyResult == null)
{
return;
}
WriteVerbose($"Cron changes applied: {applyResult.Status}");
}
}
}
@@ -33,28 +33,35 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
protected override void ProcessRecordInternal()
{
try
{
var cronService = new CronService(ApiClient, Logger);
var cronService = new CronService(ApiClient, Logger);
if (ParameterSetName == "ByUuid")
{
var task = Task.Run(async () => await cronService.GetJobAsync(Uuid));
var result = task.GetAwaiter().GetResult();
WriteObject(result.Job);
}
else
{
var task = Task.Run(async () => await cronService.GetJobsAsync());
var result = task.GetAwaiter().GetResult();
WriteObject(result.Rows, true);
}
}
catch (Exception ex)
if (ParameterSetName == "ByUuid")
{
HandleException(ex);
// Use our safe execution method
var result = ExecuteAsyncTask(() => cronService.GetJobAsync(Uuid));
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
return;
}
WriteObject(result.Job);
}
else
{
// Use our safe execution method
var result = ExecuteAsyncTask(() => cronService.GetJobsAsync());
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
return;
}
WriteObject(result.Rows, true);
}
}
}
@@ -33,28 +33,35 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
protected override void ProcessRecordInternal()
{
try
{
var userService = new UserService(ApiClient, Logger);
var userService = new UserService(ApiClient, Logger);
if (ParameterSetName == "ByUuid")
{
var task = Task.Run(async () => await userService.GetUserAsync(Uuid));
var result = task.GetAwaiter().GetResult();
WriteObject(result.User);
}
else
{
var task = Task.Run(async () => await userService.GetUsersAsync());
var result = task.GetAwaiter().GetResult();
WriteObject(result.Rows, true);
}
}
catch (Exception ex)
if (ParameterSetName == "ByUuid")
{
HandleException(ex);
// Use our safe execution method
var result = ExecuteAsyncTask(() => userService.GetUserAsync(Uuid));
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
return;
}
WriteObject(result.User);
}
else
{
// Use our safe execution method
var result = ExecuteAsyncTask(() => userService.GetUsersAsync());
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
return;
}
WriteObject(result.Rows, true);
}
}
}
@@ -103,47 +103,52 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
protected override void ProcessRecordInternal()
{
try
var gatewayService = new GatewayService(ApiClient, Logger);
var gateway = new GatewayConfig
{
var gatewayService = new GatewayService(ApiClient, Logger);
Name = Name,
Interface = Interface,
IpAddress = IpAddress,
MonitorIp = MonitorIp ?? IpAddress,
Description = Description,
IsDefault = Default.IsPresent ? "1" : "0",
Disabled = Disabled.IsPresent ? "1" : "0",
Weight = Weight?.ToString() ?? "1",
IpProtocol = IpProtocol,
MonitorDisable = DisableMonitoring.IsPresent ? "1" : "0",
ForceDown = ForceDown.IsPresent ? "1" : "0"
};
var gateway = new GatewayConfig
// Use our safe execution method
var createResult = ExecuteAsyncTask(() => gatewayService.CreateGatewayAsync(gateway));
// Only continue if no exception occurred
if (ProcessingException != null || createResult == null)
{
return;
}
WriteVerbose($"Created gateway with UUID {createResult.Uuid}");
// Apply changes if requested
if (Apply.IsPresent)
{
// Use our safe execution method
var applyResult = ExecuteAsyncTask(() => gatewayService.ApplyGatewayChangesAsync());
// Only continue if no exception occurred
if (ProcessingException != null || applyResult == null)
{
Name = Name,
Interface = Interface,
IpAddress = IpAddress,
MonitorIp = MonitorIp ?? IpAddress,
Description = Description,
IsDefault = Default.IsPresent ? "1" : "0",
Disabled = Disabled.IsPresent ? "1" : "0",
Weight = Weight?.ToString() ?? "1",
IpProtocol = IpProtocol,
MonitorDisable = DisableMonitoring.IsPresent ? "1" : "0",
ForceDown = ForceDown.IsPresent ? "1" : "0"
};
var createTask = Task.Run(async () => await gatewayService.CreateGatewayAsync(gateway));
var createResult = createTask.GetAwaiter().GetResult();
WriteVerbose($"Created gateway with UUID {createResult.Uuid}");
// Apply changes if requested
if (Apply.IsPresent)
{
var applyTask = Task.Run(async () => await gatewayService.ApplyGatewayChangesAsync());
var applyResult = applyTask.GetAwaiter().GetResult();
WriteVerbose($"Gateway changes applied: {applyResult.Status}");
return;
}
WriteObject(createResult.Uuid);
}
catch (Exception ex)
{
HandleException(ex);
WriteVerbose($"Gateway changes applied: {applyResult.Status}");
}
WriteObject(createResult.Uuid);
}
}
}
@@ -66,33 +66,32 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
protected override void ProcessRecordInternal()
{
try
var userService = new UserService(ApiClient, Logger);
var user = new UserConfig
{
var userService = new UserService(ApiClient, Logger);
Username = Username,
Password = Password,
FullName = FullName,
Email = Email,
Disabled = Disabled.IsPresent ? "1" : "0",
Groups = Groups != null ? new List<string>(Groups) : new List<string>(),
Authorizations = Authorizations != null ? new List<string>(Authorizations) : new List<string>()
};
var user = new UserConfig
{
Username = Username,
Password = Password,
FullName = FullName,
Email = Email,
Disabled = Disabled.IsPresent ? "1" : "0",
Groups = Groups != null ? new List<string>(Groups) : new List<string>(),
Authorizations = Authorizations != null ? new List<string>(Authorizations) : new List<string>()
};
// Use our safe execution method
var result = ExecuteAsyncTask(() => userService.CreateUserAsync(user));
var task = Task.Run(async () => await userService.CreateUserAsync(user));
var result = task.GetAwaiter().GetResult();
WriteVerbose($"Created user with UUID {result.Uuid}");
WriteObject(result.Uuid);
}
catch (Exception ex)
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
HandleException(ex);
return;
}
WriteVerbose($"Created user with UUID {result.Uuid}");
WriteObject(result.Uuid);
}
}
}
@@ -47,67 +47,69 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
protected override void ProcessRecordInternal()
{
try
if (!ShouldProcess("OPNSense firewall", "Update firmware"))
{
if (!ShouldProcess("OPNSense firewall", "Update firmware"))
{
return;
}
var firmwareService = new FirmwareService(ApiClient, Logger);
var task = Task.Run(async () => await firmwareService.UpdateAsync());
var result = task.GetAwaiter().GetResult();
WriteVerbose($"Firmware update initiated: {result.Status}");
WriteObject($"Firmware update initiated: {result.Status}");
if (Wait.IsPresent)
{
WriteVerbose($"Waiting for firmware update to complete (timeout: {Timeout} seconds, interval: {Interval} seconds)");
WriteObject("Waiting for firmware update to complete...");
DateTime startTime = DateTime.Now;
bool completed = false;
while (DateTime.Now - startTime < TimeSpan.FromSeconds(Timeout))
{
var statusTask = Task.Run(async () => await firmwareService.GetStatusAsync());
var statusResult = statusTask.GetAwaiter().GetResult();
if (statusResult.Status == "done")
{
WriteVerbose("Firmware update completed successfully");
WriteObject("Firmware update completed successfully");
completed = true;
break;
}
else if (statusResult.Status == "error")
{
WriteError(new ErrorRecord(
new Exception($"Firmware update failed: {statusResult.Log}"),
"FirmwareUpdateFailed",
ErrorCategory.InvalidOperation,
null));
completed = true;
break;
}
WriteVerbose($"Firmware update status: {statusResult.Status}");
Thread.Sleep(Interval * 1000);
}
if (!completed)
{
WriteWarning($"Timed out waiting for firmware update to complete after {Timeout} seconds");
}
}
return;
}
catch (Exception ex)
var firmwareService = new FirmwareService(ApiClient, Logger);
// Use our safe execution method
var result = ExecuteAsyncTask(() => firmwareService.UpdateAsync());
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
HandleException(ex);
return;
}
WriteVerbose($"Firmware update initiated: {result.Status}");
WriteObject($"Firmware update initiated: {result.Status}");
if (Wait.IsPresent)
{
WriteVerbose($"Waiting for firmware update to complete (timeout: {Timeout} seconds, interval: {Interval} seconds)");
WriteObject("Waiting for firmware update to complete...");
DateTime startTime = DateTime.Now;
bool completed = false;
while (DateTime.Now - startTime < TimeSpan.FromSeconds(Timeout))
{
// Use our safe execution method
var statusResult = ExecuteAsyncTask(() => firmwareService.GetStatusAsync());
// Break if an exception occurred
if (ProcessingException != null || statusResult == null)
{
break;
}
if (statusResult.Status == "done")
{
WriteVerbose("Firmware update completed successfully");
WriteObject("Firmware update completed successfully");
completed = true;
break;
}
else if (statusResult.Status == "error")
{
// Store the exception to be processed in ProcessRecord
ProcessingException = new Exception($"Firmware update failed: {statusResult.Log}");
completed = true;
break;
}
WriteVerbose($"Firmware update status: {statusResult.Status}");
Thread.Sleep(Interval * 1000);
}
if (!completed && ProcessingException == null)
{
WriteWarning($"Timed out waiting for firmware update to complete after {Timeout} seconds");
}
}
}
}
@@ -54,76 +54,82 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecord()
protected override void ProcessRecordInternal()
{
try
if (!Force.IsPresent && !ShouldProcess("OPNSense firewall", "Upgrade firmware"))
{
if (!Force.IsPresent && !ShouldProcess("OPNSense firewall", "Upgrade firmware"))
{
return;
}
var firmwareService = new FirmwareService(ApiClient, Logger);
var task = Task.Run(async () => await firmwareService.UpgradeAsync());
var result = task.GetAwaiter().GetResult();
WriteVerbose($"Firmware upgrade initiated: {result.Status}");
WriteObject($"Firmware upgrade initiated: {result.Status}");
if (Wait.IsPresent)
{
WriteVerbose($"Waiting for firmware upgrade to complete (timeout: {Timeout} seconds, interval: {Interval} seconds)");
WriteObject("Waiting for firmware upgrade to complete...");
DateTime startTime = DateTime.Now;
bool completed = false;
while (DateTime.Now - startTime < TimeSpan.FromSeconds(Timeout))
{
try
{
var statusTask = Task.Run(async () => await firmwareService.GetStatusAsync());
var statusResult = statusTask.GetAwaiter().GetResult();
if (statusResult.Status == "done")
{
WriteVerbose("Firmware upgrade completed successfully");
WriteObject("Firmware upgrade completed successfully");
completed = true;
break;
}
else if (statusResult.Status == "error")
{
WriteError(new ErrorRecord(
new Exception($"Firmware upgrade failed: {statusResult.Log}"),
"FirmwareUpgradeFailed",
ErrorCategory.InvalidOperation,
null));
completed = true;
break;
}
WriteVerbose($"Firmware upgrade status: {statusResult.Status}");
}
catch (Exception ex)
{
// The firewall might be rebooting, so we'll ignore errors during the wait
WriteVerbose($"Error checking status (firewall might be rebooting): {ex.Message}");
}
Thread.Sleep(Interval * 1000);
}
if (!completed)
{
WriteWarning($"Timed out waiting for firmware upgrade to complete after {Timeout} seconds");
}
}
return;
}
catch (Exception ex)
var firmwareService = new FirmwareService(ApiClient, Logger);
// Use our safe execution method
var result = ExecuteAsyncTask(() => firmwareService.UpgradeAsync());
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
HandleException(ex);
return;
}
WriteVerbose($"Firmware upgrade initiated: {result.Status}");
WriteObject($"Firmware upgrade initiated: {result.Status}");
if (Wait.IsPresent)
{
WriteVerbose($"Waiting for firmware upgrade to complete (timeout: {Timeout} seconds, interval: {Interval} seconds)");
WriteObject("Waiting for firmware upgrade to complete...");
DateTime startTime = DateTime.Now;
bool completed = false;
while (DateTime.Now - startTime < TimeSpan.FromSeconds(Timeout))
{
try
{
// Use our safe execution method
var statusResult = ExecuteAsyncTask(() => firmwareService.GetStatusAsync());
// Skip this iteration if an exception occurred
if (ProcessingException != null || statusResult == null)
{
// Clear the exception since we're ignoring it during the wait
ProcessingException = null;
WriteVerbose("Error checking status (firewall might be rebooting)");
Thread.Sleep(Interval * 1000);
continue;
}
if (statusResult.Status == "done")
{
WriteVerbose("Firmware upgrade completed successfully");
WriteObject("Firmware upgrade completed successfully");
completed = true;
break;
}
else if (statusResult.Status == "error")
{
// Store the exception to be processed in ProcessRecord
ProcessingException = new Exception($"Firmware upgrade failed: {statusResult.Log}");
completed = true;
break;
}
WriteVerbose($"Firmware upgrade status: {statusResult.Status}");
}
catch (Exception ex)
{
// The firewall might be rebooting, so we'll ignore errors during the wait
WriteVerbose($"Error checking status (firewall might be rebooting): {ex.Message}");
}
Thread.Sleep(Interval * 1000);
}
if (!completed && ProcessingException == null)
{
WriteWarning($"Timed out waiting for firmware upgrade to complete after {Timeout} seconds");
}
}
}
}
+1 -1
View File
@@ -3,7 +3,7 @@
RootModule = 'lib\PSOPNSenseAPI.dll'
# Version number of this module.
ModuleVersion = '2025.04.15.1228'
ModuleVersion = '2025.04.15.1234'
# Supported PSEditions
CompatiblePSEditions = @('Desktop', 'Core')