mirror of
https://github.com/freedbygrace/PSOPNSenseAPI.git
synced 2026-08-20 07:02:33 +00:00
Fixed more threading issues in PowerShell cmdlets to ensure WriteObject and WriteError are only called from the main thread
This commit is contained in:
@@ -27,61 +27,74 @@ 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);
|
||||||
|
|
||||||
|
// Check if the plugin is installed
|
||||||
|
var isInstalled = ExecuteAsyncTask(() => tailscaleService.IsPluginInstalledAsync());
|
||||||
|
|
||||||
|
// Only continue if no exception occurred
|
||||||
|
if (ProcessingException != null)
|
||||||
{
|
{
|
||||||
var tailscaleService = new TailscaleService(ApiClient, Logger);
|
return;
|
||||||
|
|
||||||
// Check if the plugin is installed
|
|
||||||
var isInstalledTask = Task.Run(async () => await tailscaleService.IsPluginInstalledAsync());
|
|
||||||
var isInstalled = isInstalledTask.GetAwaiter().GetResult();
|
|
||||||
|
|
||||||
if (!isInstalled)
|
|
||||||
{
|
|
||||||
WriteWarning("Tailscale plugin is not installed on the OPNSense firewall.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get current status
|
|
||||||
var statusTask = Task.Run(async () => await tailscaleService.GetStatusAsync());
|
|
||||||
var status = statusTask.GetAwaiter().GetResult();
|
|
||||||
|
|
||||||
if (!status.Running)
|
|
||||||
{
|
|
||||||
WriteWarning("Tailscale service is not running.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Force.IsPresent && !ShouldProcess("OPNSense firewall", "Disconnect from Tailscale network"))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disconnect from Tailscale
|
|
||||||
WriteVerbose("Disconnecting from Tailscale network...");
|
|
||||||
var disconnectTask = Task.Run(async () => await tailscaleService.DisconnectAsync());
|
|
||||||
var disconnectResult = disconnectTask.GetAwaiter().GetResult();
|
|
||||||
|
|
||||||
WriteVerbose($"Tailscale disconnection status: {disconnectResult.Status}");
|
|
||||||
|
|
||||||
// Get updated status
|
|
||||||
statusTask = Task.Run(async () => await tailscaleService.GetStatusAsync());
|
|
||||||
status = statusTask.GetAwaiter().GetResult();
|
|
||||||
|
|
||||||
// Create result object
|
|
||||||
var result = new PSObject();
|
|
||||||
result.Properties.Add(new PSNoteProperty("Status", status.Status));
|
|
||||||
result.Properties.Add(new PSNoteProperty("Running", status.Running));
|
|
||||||
result.Properties.Add(new PSNoteProperty("Enabled", status.Enabled));
|
|
||||||
result.Properties.Add(new PSNoteProperty("DisconnectionStatus", disconnectResult.Status));
|
|
||||||
|
|
||||||
WriteObject(result);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
|
if (!isInstalled)
|
||||||
{
|
{
|
||||||
HandleException(ex);
|
WriteWarning("Tailscale plugin is not installed on the OPNSense firewall.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get current status
|
||||||
|
var status = ExecuteAsyncTask(() => tailscaleService.GetStatusAsync());
|
||||||
|
|
||||||
|
// Only continue if no exception occurred
|
||||||
|
if (ProcessingException != null || status == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!status.Running)
|
||||||
|
{
|
||||||
|
WriteWarning("Tailscale service is not running.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Force.IsPresent && !ShouldProcess("OPNSense firewall", "Disconnect from Tailscale network"))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disconnect from Tailscale
|
||||||
|
WriteVerbose("Disconnecting from Tailscale network...");
|
||||||
|
var disconnectResult = ExecuteAsyncTask(() => tailscaleService.DisconnectAsync());
|
||||||
|
|
||||||
|
// Only continue if no exception occurred
|
||||||
|
if (ProcessingException != null || disconnectResult == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteVerbose($"Tailscale disconnection status: {disconnectResult.Status}");
|
||||||
|
|
||||||
|
// Get updated status
|
||||||
|
status = ExecuteAsyncTask(() => tailscaleService.GetStatusAsync());
|
||||||
|
|
||||||
|
// Only continue if no exception occurred
|
||||||
|
if (ProcessingException != null || status == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create result object
|
||||||
|
var result = new PSObject();
|
||||||
|
result.Properties.Add(new PSNoteProperty("Status", status.Status));
|
||||||
|
result.Properties.Add(new PSNoteProperty("Running", status.Running));
|
||||||
|
result.Properties.Add(new PSNoteProperty("Enabled", status.Enabled));
|
||||||
|
result.Properties.Add(new PSNoteProperty("DisconnectionStatus", disconnectResult.Status));
|
||||||
|
|
||||||
|
WriteObject(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,28 +33,35 @@ 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));
|
|
||||||
var result = task.GetAwaiter().GetResult();
|
|
||||||
WriteObject(result.Interface);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var task = Task.Run(async () => await interfaceService.GetInterfacesAsync());
|
|
||||||
var result = task.GetAwaiter().GetResult();
|
|
||||||
WriteObject(result.Interfaces, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
{
|
||||||
HandleException(ex);
|
// Use our safe execution method
|
||||||
|
var result = ExecuteAsyncTask(() => interfaceService.GetInterfaceDetailAsync(Name));
|
||||||
|
|
||||||
|
// Only continue if no exception occurred
|
||||||
|
if (ProcessingException != null || result == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteObject(result.Interface);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use our safe execution method
|
||||||
|
var result = ExecuteAsyncTask(() => interfaceService.GetInterfacesAsync());
|
||||||
|
|
||||||
|
// Only continue if no exception occurred
|
||||||
|
if (ProcessingException != null || result == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteObject(result.Interfaces, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,41 +60,46 @@ 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 dnsOverride = new DNSOverrideConfig
|
||||||
{
|
{
|
||||||
var dnsService = new DNSService(ApiClient, Logger);
|
Hostname = Hostname,
|
||||||
|
Domain = Domain,
|
||||||
|
IpAddress = IpAddress,
|
||||||
|
Description = Description,
|
||||||
|
Enabled = Enabled.IsPresent ? "1" : "0"
|
||||||
|
};
|
||||||
|
|
||||||
var dnsOverride = new DNSOverrideConfig
|
// Use our safe execution method
|
||||||
|
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}");
|
||||||
|
|
||||||
|
// Apply the changes if requested
|
||||||
|
if (Apply.IsPresent)
|
||||||
|
{
|
||||||
|
// Use our safe execution method
|
||||||
|
var applyResult = ExecuteAsyncTask(() => dnsService.ApplyDNSChangesAsync());
|
||||||
|
|
||||||
|
// Only continue if no exception occurred
|
||||||
|
if (ProcessingException != null || applyResult == null)
|
||||||
{
|
{
|
||||||
Hostname = Hostname,
|
return;
|
||||||
Domain = Domain,
|
|
||||||
IpAddress = IpAddress,
|
|
||||||
Description = Description,
|
|
||||||
Enabled = Enabled.IsPresent ? "1" : "0"
|
|
||||||
};
|
|
||||||
|
|
||||||
var createTask = Task.Run(async () => await dnsService.CreateDNSOverrideAsync(dnsOverride));
|
|
||||||
var createResult = createTask.GetAwaiter().GetResult();
|
|
||||||
|
|
||||||
WriteVerbose($"Created DNS override with UUID {createResult.Uuid}");
|
|
||||||
|
|
||||||
// Apply the changes if requested
|
|
||||||
if (Apply.IsPresent)
|
|
||||||
{
|
|
||||||
var applyTask = Task.Run(async () => await dnsService.ApplyDNSChangesAsync());
|
|
||||||
var applyResult = applyTask.GetAwaiter().GetResult();
|
|
||||||
|
|
||||||
WriteVerbose($"DNS changes applied: {applyResult.Status}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteObject(createResult.Uuid);
|
WriteVerbose($"DNS changes applied: {applyResult.Status}");
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
HandleException(ex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WriteObject(createResult.Uuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,40 +53,45 @@ 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 route = new RouteConfig
|
||||||
{
|
{
|
||||||
var routeService = new RouteService(ApiClient, Logger);
|
Network = Network,
|
||||||
|
Gateway = Gateway,
|
||||||
|
Description = Description,
|
||||||
|
Disabled = Disabled.IsPresent ? "1" : "0"
|
||||||
|
};
|
||||||
|
|
||||||
var route = new RouteConfig
|
// Use our safe execution method
|
||||||
|
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}");
|
||||||
|
|
||||||
|
// Apply changes if requested
|
||||||
|
if (Apply.IsPresent)
|
||||||
|
{
|
||||||
|
// Use our safe execution method
|
||||||
|
var applyResult = ExecuteAsyncTask(() => routeService.ApplyRouteChangesAsync());
|
||||||
|
|
||||||
|
// Only continue if no exception occurred
|
||||||
|
if (ProcessingException != null || applyResult == null)
|
||||||
{
|
{
|
||||||
Network = Network,
|
return;
|
||||||
Gateway = Gateway,
|
|
||||||
Description = Description,
|
|
||||||
Disabled = Disabled.IsPresent ? "1" : "0"
|
|
||||||
};
|
|
||||||
|
|
||||||
var createTask = Task.Run(async () => await routeService.CreateRouteAsync(route));
|
|
||||||
var createResult = createTask.GetAwaiter().GetResult();
|
|
||||||
|
|
||||||
WriteVerbose($"Created route with UUID {createResult.Uuid}");
|
|
||||||
|
|
||||||
// Apply changes if requested
|
|
||||||
if (Apply.IsPresent)
|
|
||||||
{
|
|
||||||
var applyTask = Task.Run(async () => await routeService.ApplyRouteChangesAsync());
|
|
||||||
var applyResult = applyTask.GetAwaiter().GetResult();
|
|
||||||
|
|
||||||
WriteVerbose($"Route changes applied: {applyResult.Status}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteObject(createResult.Uuid);
|
WriteVerbose($"Route changes applied: {applyResult.Status}");
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
HandleException(ex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WriteObject(createResult.Uuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,44 +45,56 @@ 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);
|
||||||
|
|
||||||
|
// Get the job details for the confirmation message
|
||||||
|
var jobResult = ExecuteAsyncTask(() => cronService.GetJobAsync(Uuid));
|
||||||
|
|
||||||
|
// Only continue if no exception occurred
|
||||||
|
if (ProcessingException != null || jobResult == null)
|
||||||
{
|
{
|
||||||
var cronService = new CronService(ApiClient, Logger);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the job details for the confirmation message
|
var job = jobResult.Job;
|
||||||
var getTask = Task.Run(async () => await cronService.GetJobAsync(Uuid));
|
|
||||||
var job = getTask.GetAwaiter().GetResult().Job;
|
|
||||||
|
|
||||||
string confirmMessage = $"Cron job: {job.Description}";
|
string confirmMessage = $"Cron job: {job.Description}";
|
||||||
if (!string.IsNullOrEmpty(job.Command))
|
if (!string.IsNullOrEmpty(job.Command))
|
||||||
{
|
{
|
||||||
confirmMessage += $" ({job.Command})";
|
confirmMessage += $" ({job.Command})";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Force.IsPresent && !ShouldProcess(confirmMessage, "Remove"))
|
if (!Force.IsPresent && !ShouldProcess(confirmMessage, "Remove"))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use our safe execution method
|
||||||
|
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}");
|
||||||
|
|
||||||
|
// Apply the changes if requested
|
||||||
|
if (Apply.IsPresent)
|
||||||
|
{
|
||||||
|
// Use our safe execution method
|
||||||
|
var applyResult = ExecuteAsyncTask(() => cronService.ApplyChangesAsync());
|
||||||
|
|
||||||
|
// Only continue if no exception occurred
|
||||||
|
if (ProcessingException != null || applyResult == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var deleteTask = Task.Run(async () => await cronService.DeleteJobAsync(Uuid));
|
WriteVerbose($"Cron changes applied: {applyResult.Status}");
|
||||||
var deleteResult = deleteTask.GetAwaiter().GetResult();
|
|
||||||
|
|
||||||
WriteVerbose($"Cron job {Uuid} removed: {deleteResult.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}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
HandleException(ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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')
|
||||||
|
|||||||
Reference in New Issue
Block a user