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:49:33 -04:00
parent 04b0fd5550
commit 68fcec516e
6 changed files with 196 additions and 154 deletions
@@ -27,15 +27,18 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary> /// <summary>
/// Processes the cmdlet /// Processes the cmdlet
/// </summary> /// </summary>
protected override void ProcessRecord() protected override void ProcessRecordInternal()
{
try
{ {
var tailscaleService = new TailscaleService(ApiClient, Logger); var tailscaleService = new TailscaleService(ApiClient, Logger);
// Check if the plugin is installed // Check if the plugin is installed
var isInstalledTask = Task.Run(async () => await tailscaleService.IsPluginInstalledAsync()); var isInstalled = ExecuteAsyncTask(() => tailscaleService.IsPluginInstalledAsync());
var isInstalled = isInstalledTask.GetAwaiter().GetResult();
// Only continue if no exception occurred
if (ProcessingException != null)
{
return;
}
if (!isInstalled) if (!isInstalled)
{ {
@@ -44,8 +47,13 @@ namespace PSOPNSenseAPI.Cmdlets
} }
// Get current status // Get current status
var statusTask = Task.Run(async () => await tailscaleService.GetStatusAsync()); var status = ExecuteAsyncTask(() => tailscaleService.GetStatusAsync());
var status = statusTask.GetAwaiter().GetResult();
// Only continue if no exception occurred
if (ProcessingException != null || status == null)
{
return;
}
if (!status.Running) if (!status.Running)
{ {
@@ -60,14 +68,24 @@ namespace PSOPNSenseAPI.Cmdlets
// Disconnect from Tailscale // Disconnect from Tailscale
WriteVerbose("Disconnecting from Tailscale network..."); WriteVerbose("Disconnecting from Tailscale network...");
var disconnectTask = Task.Run(async () => await tailscaleService.DisconnectAsync()); var disconnectResult = ExecuteAsyncTask(() => tailscaleService.DisconnectAsync());
var disconnectResult = disconnectTask.GetAwaiter().GetResult();
// Only continue if no exception occurred
if (ProcessingException != null || disconnectResult == null)
{
return;
}
WriteVerbose($"Tailscale disconnection status: {disconnectResult.Status}"); WriteVerbose($"Tailscale disconnection status: {disconnectResult.Status}");
// Get updated status // Get updated status
statusTask = Task.Run(async () => await tailscaleService.GetStatusAsync()); status = ExecuteAsyncTask(() => tailscaleService.GetStatusAsync());
status = statusTask.GetAwaiter().GetResult();
// Only continue if no exception occurred
if (ProcessingException != null || status == null)
{
return;
}
// Create result object // Create result object
var result = new PSObject(); var result = new PSObject();
@@ -78,10 +96,5 @@ namespace PSOPNSenseAPI.Cmdlets
WriteObject(result); WriteObject(result);
} }
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 interfaceService = new InterfaceService(ApiClient, Logger); var interfaceService = new InterfaceService(ApiClient, Logger);
if (ParameterSetName == "ByName") if (ParameterSetName == "ByName")
{ {
var task = Task.Run(async () => await interfaceService.GetInterfaceDetailAsync(Name)); // Use our safe execution method
var result = task.GetAwaiter().GetResult(); var result = ExecuteAsyncTask(() => interfaceService.GetInterfaceDetailAsync(Name));
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
return;
}
WriteObject(result.Interface); WriteObject(result.Interface);
} }
else else
{ {
var task = Task.Run(async () => await interfaceService.GetInterfacesAsync()); // Use our safe execution method
var result = task.GetAwaiter().GetResult(); var result = ExecuteAsyncTask(() => interfaceService.GetInterfacesAsync());
// Only continue if no exception occurred
if (ProcessingException != null || result == null)
{
return;
}
WriteObject(result.Interfaces, true); WriteObject(result.Interfaces, true);
} }
} }
catch (Exception ex)
{
HandleException(ex);
}
}
} }
} }
@@ -60,9 +60,7 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary> /// <summary>
/// Processes the cmdlet /// Processes the cmdlet
/// </summary> /// </summary>
protected override void ProcessRecord() protected override void ProcessRecordInternal()
{
try
{ {
var dnsService = new DNSService(ApiClient, Logger); var dnsService = new DNSService(ApiClient, Logger);
@@ -75,26 +73,33 @@ namespace PSOPNSenseAPI.Cmdlets
Enabled = Enabled.IsPresent ? "1" : "0" Enabled = Enabled.IsPresent ? "1" : "0"
}; };
var createTask = Task.Run(async () => await dnsService.CreateDNSOverrideAsync(dnsOverride)); // Use our safe execution method
var createResult = createTask.GetAwaiter().GetResult(); var createResult = ExecuteAsyncTask(() => dnsService.CreateDNSOverrideAsync(dnsOverride));
// Only continue if no exception occurred
if (ProcessingException != null || createResult == null)
{
return;
}
WriteVerbose($"Created DNS override with UUID {createResult.Uuid}"); WriteVerbose($"Created DNS override with UUID {createResult.Uuid}");
// Apply the changes if requested // Apply the changes if requested
if (Apply.IsPresent) if (Apply.IsPresent)
{ {
var applyTask = Task.Run(async () => await dnsService.ApplyDNSChangesAsync()); // Use our safe execution method
var applyResult = applyTask.GetAwaiter().GetResult(); var applyResult = ExecuteAsyncTask(() => dnsService.ApplyDNSChangesAsync());
// Only continue if no exception occurred
if (ProcessingException != null || applyResult == null)
{
return;
}
WriteVerbose($"DNS changes applied: {applyResult.Status}"); WriteVerbose($"DNS changes applied: {applyResult.Status}");
} }
WriteObject(createResult.Uuid); WriteObject(createResult.Uuid);
} }
catch (Exception ex)
{
HandleException(ex);
}
}
} }
} }
@@ -53,9 +53,7 @@ namespace PSOPNSenseAPI.Cmdlets
/// <summary> /// <summary>
/// Processes the cmdlet /// Processes the cmdlet
/// </summary> /// </summary>
protected override void ProcessRecord() protected override void ProcessRecordInternal()
{
try
{ {
var routeService = new RouteService(ApiClient, Logger); var routeService = new RouteService(ApiClient, Logger);
@@ -67,26 +65,33 @@ namespace PSOPNSenseAPI.Cmdlets
Disabled = Disabled.IsPresent ? "1" : "0" Disabled = Disabled.IsPresent ? "1" : "0"
}; };
var createTask = Task.Run(async () => await routeService.CreateRouteAsync(route)); // Use our safe execution method
var createResult = createTask.GetAwaiter().GetResult(); var createResult = ExecuteAsyncTask(() => routeService.CreateRouteAsync(route));
// Only continue if no exception occurred
if (ProcessingException != null || createResult == null)
{
return;
}
WriteVerbose($"Created route with UUID {createResult.Uuid}"); WriteVerbose($"Created route with UUID {createResult.Uuid}");
// Apply changes if requested // Apply changes if requested
if (Apply.IsPresent) if (Apply.IsPresent)
{ {
var applyTask = Task.Run(async () => await routeService.ApplyRouteChangesAsync()); // Use our safe execution method
var applyResult = applyTask.GetAwaiter().GetResult(); var applyResult = ExecuteAsyncTask(() => routeService.ApplyRouteChangesAsync());
// Only continue if no exception occurred
if (ProcessingException != null || applyResult == null)
{
return;
}
WriteVerbose($"Route changes applied: {applyResult.Status}"); WriteVerbose($"Route changes applied: {applyResult.Status}");
} }
WriteObject(createResult.Uuid); WriteObject(createResult.Uuid);
} }
catch (Exception ex)
{
HandleException(ex);
}
}
} }
} }
@@ -45,15 +45,20 @@ 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);
// Get the job details for the confirmation message // Get the job details for the confirmation message
var getTask = Task.Run(async () => await cronService.GetJobAsync(Uuid)); var jobResult = ExecuteAsyncTask(() => cronService.GetJobAsync(Uuid));
var job = getTask.GetAwaiter().GetResult().Job;
// Only continue if no exception occurred
if (ProcessingException != null || jobResult == null)
{
return;
}
var job = jobResult.Job;
string confirmMessage = $"Cron job: {job.Description}"; string confirmMessage = $"Cron job: {job.Description}";
if (!string.IsNullOrEmpty(job.Command)) if (!string.IsNullOrEmpty(job.Command))
@@ -66,24 +71,31 @@ namespace PSOPNSenseAPI.Cmdlets
return; return;
} }
var deleteTask = Task.Run(async () => await cronService.DeleteJobAsync(Uuid)); // Use our safe execution method
var deleteResult = deleteTask.GetAwaiter().GetResult(); var deleteResult = ExecuteAsyncTask(() => cronService.DeleteJobAsync(Uuid));
// Only continue if no exception occurred
if (ProcessingException != null || deleteResult == null)
{
return;
}
WriteVerbose($"Cron job {Uuid} removed: {deleteResult.Result}"); WriteVerbose($"Cron job {Uuid} removed: {deleteResult.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);
}
}
} }
} }
+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.1245' ModuleVersion = '2025.04.15.1249'
# Supported PSEditions # Supported PSEditions
CompatiblePSEditions = @('Desktop', 'Core') CompatiblePSEditions = @('Desktop', 'Core')