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,30 +34,35 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary> /// <summary>
/// Processes the cmdlet /// Processes the cmdlet
/// </summary> /// </summary>
protected override void ProcessRecord() protected override void ProcessRecordInternal()
{
try
{ {
var cronService = new CronService(ApiClient, Logger); var cronService = new CronService(ApiClient, Logger);
var task = Task.Run(async () => await cronService.ToggleJobAsync(Uuid, true)); // Use our safe execution method
var result = task.GetAwaiter().GetResult(); var result = ExecuteAsyncTask(() => cronService.ToggleJobAsync(Uuid, true));
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
return;
}
WriteVerbose($"Cron job {Uuid} enabled: {result.Result}"); WriteVerbose($"Cron job {Uuid} enabled: {result.Result}");
// Apply the changes if requested // Apply the changes if requested
if (Apply.IsPresent) if (Apply.IsPresent)
{ {
var applyTask = Task.Run(async () => await cronService.ApplyChangesAsync()); // Use our safe execution method
var applyResult = applyTask.GetAwaiter().GetResult(); var applyResult = ExecuteAsyncTask(() => cronService.ApplyChangesAsync());
// Only continue if no exception occurred
if (ProcessingException != null || applyResult == null)
{
return;
}
WriteVerbose($"Cron changes applied: {applyResult.Status}"); WriteVerbose($"Cron changes applied: {applyResult.Status}");
} }
} }
catch (Exception ex)
{
HandleException(ex);
}
}
} }
} }
@@ -33,29 +33,36 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary> /// <summary>
/// Processes the cmdlet /// Processes the cmdlet
/// </summary> /// </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") if (ParameterSetName == "ByUuid")
{ {
var task = Task.Run(async () => await cronService.GetJobAsync(Uuid)); // Use our safe execution method
var result = task.GetAwaiter().GetResult(); var result = ExecuteAsyncTask(() => cronService.GetJobAsync(Uuid));
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
return;
}
WriteObject(result.Job); WriteObject(result.Job);
} }
else else
{ {
var task = Task.Run(async () => await cronService.GetJobsAsync()); // Use our safe execution method
var result = task.GetAwaiter().GetResult(); var result = ExecuteAsyncTask(() => cronService.GetJobsAsync());
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
return;
}
WriteObject(result.Rows, true); WriteObject(result.Rows, true);
} }
} }
catch (Exception ex)
{
HandleException(ex);
}
}
} }
} }
@@ -33,29 +33,36 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary> /// <summary>
/// Processes the cmdlet /// Processes the cmdlet
/// </summary> /// </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") if (ParameterSetName == "ByUuid")
{ {
var task = Task.Run(async () => await userService.GetUserAsync(Uuid)); // Use our safe execution method
var result = task.GetAwaiter().GetResult(); var result = ExecuteAsyncTask(() => userService.GetUserAsync(Uuid));
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
return;
}
WriteObject(result.User); WriteObject(result.User);
} }
else else
{ {
var task = Task.Run(async () => await userService.GetUsersAsync()); // Use our safe execution method
var result = task.GetAwaiter().GetResult(); var result = ExecuteAsyncTask(() => userService.GetUsersAsync());
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
return;
}
WriteObject(result.Rows, true); WriteObject(result.Rows, true);
} }
} }
catch (Exception ex)
{
HandleException(ex);
}
}
} }
} }
@@ -103,9 +103,7 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary> /// <summary>
/// Processes the cmdlet /// Processes the cmdlet
/// </summary> /// </summary>
protected override void ProcessRecord() protected override void ProcessRecordInternal()
{
try
{ {
var gatewayService = new GatewayService(ApiClient, Logger); var gatewayService = new GatewayService(ApiClient, Logger);
@@ -124,26 +122,33 @@ namespace PSOPNSenseAPI.Cmdlets
ForceDown = ForceDown.IsPresent ? "1" : "0" ForceDown = ForceDown.IsPresent ? "1" : "0"
}; };
var createTask = Task.Run(async () => await gatewayService.CreateGatewayAsync(gateway)); // Use our safe execution method
var createResult = createTask.GetAwaiter().GetResult(); 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}"); WriteVerbose($"Created gateway with UUID {createResult.Uuid}");
// Apply changes if requested // Apply changes if requested
if (Apply.IsPresent) if (Apply.IsPresent)
{ {
var applyTask = Task.Run(async () => await gatewayService.ApplyGatewayChangesAsync()); // Use our safe execution method
var applyResult = applyTask.GetAwaiter().GetResult(); var applyResult = ExecuteAsyncTask(() => gatewayService.ApplyGatewayChangesAsync());
// Only continue if no exception occurred
if (ProcessingException != null || applyResult == null)
{
return;
}
WriteVerbose($"Gateway changes applied: {applyResult.Status}"); WriteVerbose($"Gateway changes applied: {applyResult.Status}");
} }
WriteObject(createResult.Uuid); WriteObject(createResult.Uuid);
} }
catch (Exception ex)
{
HandleException(ex);
}
}
} }
} }
@@ -66,9 +66,7 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary> /// <summary>
/// Processes the cmdlet /// Processes the cmdlet
/// </summary> /// </summary>
protected override void ProcessRecord() protected override void ProcessRecordInternal()
{
try
{ {
var userService = new UserService(ApiClient, Logger); var userService = new UserService(ApiClient, Logger);
@@ -83,16 +81,17 @@ namespace PSOPNSenseAPI.Cmdlets
Authorizations = Authorizations != null ? new List<string>(Authorizations) : new List<string>() Authorizations = Authorizations != null ? new List<string>(Authorizations) : new List<string>()
}; };
var task = Task.Run(async () => await userService.CreateUserAsync(user)); // Use our safe execution method
var result = task.GetAwaiter().GetResult(); var result = ExecuteAsyncTask(() => userService.CreateUserAsync(user));
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
return;
}
WriteVerbose($"Created user with UUID {result.Uuid}"); WriteVerbose($"Created user with UUID {result.Uuid}");
WriteObject(result.Uuid); WriteObject(result.Uuid);
} }
catch (Exception ex)
{
HandleException(ex);
}
}
} }
} }
@@ -47,9 +47,7 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary> /// <summary>
/// Processes the cmdlet /// Processes the cmdlet
/// </summary> /// </summary>
protected override void ProcessRecord() protected override void ProcessRecordInternal()
{
try
{ {
if (!ShouldProcess("OPNSense firewall", "Update firmware")) if (!ShouldProcess("OPNSense firewall", "Update firmware"))
{ {
@@ -58,8 +56,14 @@ namespace PSOPNSenseAPI.Cmdlets
var firmwareService = new FirmwareService(ApiClient, Logger); var firmwareService = new FirmwareService(ApiClient, Logger);
var task = Task.Run(async () => await firmwareService.UpdateAsync()); // Use our safe execution method
var result = task.GetAwaiter().GetResult(); var result = ExecuteAsyncTask(() => firmwareService.UpdateAsync());
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
return;
}
WriteVerbose($"Firmware update initiated: {result.Status}"); WriteVerbose($"Firmware update initiated: {result.Status}");
WriteObject($"Firmware update initiated: {result.Status}"); WriteObject($"Firmware update initiated: {result.Status}");
@@ -74,8 +78,14 @@ namespace PSOPNSenseAPI.Cmdlets
while (DateTime.Now - startTime < TimeSpan.FromSeconds(Timeout)) while (DateTime.Now - startTime < TimeSpan.FromSeconds(Timeout))
{ {
var statusTask = Task.Run(async () => await firmwareService.GetStatusAsync()); // Use our safe execution method
var statusResult = statusTask.GetAwaiter().GetResult(); var statusResult = ExecuteAsyncTask(() => firmwareService.GetStatusAsync());
// Break if an exception occurred
if (ProcessingException != null || statusResult == null)
{
break;
}
if (statusResult.Status == "done") if (statusResult.Status == "done")
{ {
@@ -86,11 +96,8 @@ namespace PSOPNSenseAPI.Cmdlets
} }
else if (statusResult.Status == "error") else if (statusResult.Status == "error")
{ {
WriteError(new ErrorRecord( // Store the exception to be processed in ProcessRecord
new Exception($"Firmware update failed: {statusResult.Log}"), ProcessingException = new Exception($"Firmware update failed: {statusResult.Log}");
"FirmwareUpdateFailed",
ErrorCategory.InvalidOperation,
null));
completed = true; completed = true;
break; break;
} }
@@ -99,16 +106,11 @@ namespace PSOPNSenseAPI.Cmdlets
Thread.Sleep(Interval * 1000); Thread.Sleep(Interval * 1000);
} }
if (!completed) if (!completed && ProcessingException == null)
{ {
WriteWarning($"Timed out waiting for firmware update to complete after {Timeout} seconds"); WriteWarning($"Timed out waiting for firmware update to complete after {Timeout} seconds");
} }
} }
} }
catch (Exception ex)
{
HandleException(ex);
}
}
} }
} }
@@ -54,9 +54,7 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary> /// <summary>
/// Processes the cmdlet /// Processes the cmdlet
/// </summary> /// </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"))
{ {
@@ -65,8 +63,14 @@ namespace PSOPNSenseAPI.Cmdlets
var firmwareService = new FirmwareService(ApiClient, Logger); var firmwareService = new FirmwareService(ApiClient, Logger);
var task = Task.Run(async () => await firmwareService.UpgradeAsync()); // Use our safe execution method
var result = task.GetAwaiter().GetResult(); var result = ExecuteAsyncTask(() => firmwareService.UpgradeAsync());
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
return;
}
WriteVerbose($"Firmware upgrade initiated: {result.Status}"); WriteVerbose($"Firmware upgrade initiated: {result.Status}");
WriteObject($"Firmware upgrade initiated: {result.Status}"); WriteObject($"Firmware upgrade initiated: {result.Status}");
@@ -83,8 +87,18 @@ namespace PSOPNSenseAPI.Cmdlets
{ {
try try
{ {
var statusTask = Task.Run(async () => await firmwareService.GetStatusAsync()); // Use our safe execution method
var statusResult = statusTask.GetAwaiter().GetResult(); 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") if (statusResult.Status == "done")
{ {
@@ -95,11 +109,8 @@ namespace PSOPNSenseAPI.Cmdlets
} }
else if (statusResult.Status == "error") else if (statusResult.Status == "error")
{ {
WriteError(new ErrorRecord( // Store the exception to be processed in ProcessRecord
new Exception($"Firmware upgrade failed: {statusResult.Log}"), ProcessingException = new Exception($"Firmware upgrade failed: {statusResult.Log}");
"FirmwareUpgradeFailed",
ErrorCategory.InvalidOperation,
null));
completed = true; completed = true;
break; break;
} }
@@ -115,16 +126,11 @@ namespace PSOPNSenseAPI.Cmdlets
Thread.Sleep(Interval * 1000); Thread.Sleep(Interval * 1000);
} }
if (!completed) if (!completed && ProcessingException == null)
{ {
WriteWarning($"Timed out waiting for firmware upgrade to complete after {Timeout} seconds"); WriteWarning($"Timed out waiting for firmware upgrade to complete after {Timeout} seconds");
} }
} }
} }
catch (Exception ex)
{
HandleException(ex);
}
}
} }
} }
+1 -1
View File
@@ -3,7 +3,7 @@
RootModule = 'lib\PSOPNSenseAPI.dll' RootModule = 'lib\PSOPNSenseAPI.dll'
# Version number of this module. # Version number of this module.
ModuleVersion = '2025.04.15.1228' ModuleVersion = '2025.04.15.1234'
# Supported PSEditions # Supported PSEditions
CompatiblePSEditions = @('Desktop', 'Core') CompatiblePSEditions = @('Desktop', 'Core')