mirror of
https://github.com/freedbygrace/PSOPNSenseAPI.git
synced 2026-07-27 12:19:12 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3936e6bb5d | |||
| 7535135bfd | |||
| 68e6819131 | |||
| c423cca25a | |||
| 91dc1a1f17 | |||
| 7476e03319 | |||
| 7a2331bf74 | |||
| 4e137e927e | |||
| 412f46ec8d | |||
| 2916619bf3 | |||
| ad693cedcd | |||
| ab0c75ab85 | |||
| ef21e5d359 | |||
| fa5c666cbd | |||
| d5fe842cb7 | |||
| 52a422d6cc | |||
| ccfb37aaac | |||
| 28546595bd |
+15
-1
@@ -5,7 +5,21 @@ All notable changes to the PSOPNSenseAPI module will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
## [2025.04.15.1143] - 2025-04-15
|
||||
|
||||
### Added
|
||||
- Added `Get-OPNSenseConfig` cmdlet that retrieves the OPNSense configuration as an XML document
|
||||
|
||||
### Changed
|
||||
- Renamed `Upgrade-OPNSenseFirmware` to `Start-OPNSenseFirmwareUpgrade` to resolve cmdlet name conflict
|
||||
- Updated `Restore-OPNSenseConfig` to accept an XML document from the pipeline or as a parameter
|
||||
- Changed `Export-OPNSenseConfig` and `Import-OPNSenseConfig` to use System.IO.FileInfo for the Path parameter
|
||||
- Added unit tests for firmware management cmdlets
|
||||
- Fixed threading issue in cmdlets that was causing "WriteObject and WriteError methods cannot be called from outside the overrides" error
|
||||
- Changed module structure to use DLL as root module instead of nested module
|
||||
|
||||
### Removed
|
||||
- Removed `Backup-OPNSenseConfig` cmdlet (use `Get-OPNSenseConfig` instead)
|
||||
|
||||
## [0.6.0] - 2025-04-14
|
||||
|
||||
|
||||
@@ -1,208 +0,0 @@
|
||||
@{
|
||||
# Script module or binary module file associated with this manifest.
|
||||
RootModule = 'PSOPNSenseAPI.psm1'
|
||||
|
||||
# Version number of this module.
|
||||
ModuleVersion = '2025.04.14.1839'
|
||||
|
||||
# Supported PSEditions
|
||||
CompatiblePSEditions = @('Desktop', 'Core')
|
||||
|
||||
# ID used to uniquely identify this module
|
||||
GUID = '8f7a3d7a-0e5a-4b7c-9b5a-9c5b3a5a8e7a'
|
||||
|
||||
# Author of this module
|
||||
Author = 'PSOPNSenseAPI Contributors'
|
||||
|
||||
# Company or vendor of this module
|
||||
CompanyName = 'PSOPNSenseAPI'
|
||||
|
||||
# Copyright statement for this module
|
||||
Copyright = '(c) 2025 PSOPNSenseAPI Contributors. All rights reserved.'
|
||||
|
||||
# Description of the functionality provided by this module
|
||||
Description = 'PowerShell module for interacting with the OPNSense API to configure firewalls'
|
||||
|
||||
# Minimum version of the PowerShell engine required by this module
|
||||
PowerShellVersion = '5.1'
|
||||
|
||||
# Name of the PowerShell host required by this module
|
||||
# PowerShellHostName = ''
|
||||
|
||||
# Minimum version of the PowerShell host required by this module
|
||||
# PowerShellHostVersion = ''
|
||||
|
||||
# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||
DotNetFrameworkVersion = '4.7.2'
|
||||
|
||||
# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||
# ClrVersion = ''
|
||||
|
||||
# Processor architecture (None, X86, Amd64) required by this module
|
||||
# ProcessorArchitecture = ''
|
||||
|
||||
# Modules that must be imported into the global environment prior to importing this module
|
||||
# RequiredModules = @()
|
||||
|
||||
# Assemblies that must be loaded prior to importing this module
|
||||
RequiredAssemblies = @('bin\PSOPNSenseAPI.dll')
|
||||
|
||||
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
|
||||
# ScriptsToProcess = @()
|
||||
|
||||
# Type files (.ps1xml) to be loaded when importing this module
|
||||
# TypesToProcess = @()
|
||||
|
||||
# Format files (.ps1xml) to be loaded when importing this module
|
||||
# FormatsToProcess = @()
|
||||
|
||||
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
|
||||
NestedModules = @('bin\PSOPNSenseAPI.dll')
|
||||
|
||||
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
|
||||
FunctionsToExport = @()
|
||||
|
||||
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
|
||||
CmdletsToExport = @(
|
||||
# Connection Management
|
||||
'Connect-OPNSense',
|
||||
'Disconnect-OPNSense',
|
||||
'Get-OPNSenseConnection',
|
||||
|
||||
# Firewall Rule Management
|
||||
'Get-OPNSenseFirewallRule',
|
||||
'New-OPNSenseFirewallRule',
|
||||
'Set-OPNSenseFirewallRule',
|
||||
'Remove-OPNSenseFirewallRule',
|
||||
'Enable-OPNSenseFirewallRule',
|
||||
'Disable-OPNSenseFirewallRule',
|
||||
'Apply-OPNSenseFirewallChanges',
|
||||
|
||||
# Alias Management
|
||||
'Get-OPNSenseAlias',
|
||||
'New-OPNSenseAlias',
|
||||
'Set-OPNSenseAlias',
|
||||
'Remove-OPNSenseAlias',
|
||||
|
||||
# NAT Rule Management
|
||||
'Get-OPNSenseNATRule',
|
||||
'New-OPNSenseNATRule',
|
||||
'Set-OPNSenseNATRule',
|
||||
'Remove-OPNSenseNATRule',
|
||||
|
||||
# Interface Management
|
||||
'Get-OPNSenseInterface',
|
||||
'Set-OPNSenseInterface',
|
||||
'Restart-OPNSenseInterface',
|
||||
'Get-OPNSenseInterfaceStatistics',
|
||||
'New-OPNSenseSubnetVLANs',
|
||||
|
||||
# VLAN Management
|
||||
'Get-OPNSenseVLAN',
|
||||
'New-OPNSenseVLAN',
|
||||
'Set-OPNSenseVLAN',
|
||||
'Remove-OPNSenseVLAN',
|
||||
|
||||
# DNS Configuration
|
||||
'Get-OPNSenseDNSServer',
|
||||
'Set-OPNSenseDNSServer',
|
||||
'Get-OPNSenseDNSDomain',
|
||||
'Set-OPNSenseDNSDomain',
|
||||
'Get-OPNSenseDNSOverride',
|
||||
'New-OPNSenseDNSOverride',
|
||||
'Remove-OPNSenseDNSOverride',
|
||||
|
||||
# Configuration Management
|
||||
'Backup-OPNSenseConfig',
|
||||
'Restore-OPNSenseConfig',
|
||||
'Export-OPNSenseConfig',
|
||||
'Import-OPNSenseConfig',
|
||||
'Get-OPNSenseConfigBackup',
|
||||
|
||||
# Plugin Management
|
||||
'Get-OPNSensePlugin',
|
||||
'Install-OPNSensePlugin',
|
||||
'Uninstall-OPNSensePlugin',
|
||||
'Enable-OPNSensePlugin',
|
||||
'Disable-OPNSensePlugin',
|
||||
|
||||
# User Management
|
||||
'Get-OPNSenseUser',
|
||||
'New-OPNSenseUser',
|
||||
'Set-OPNSenseUser',
|
||||
'Remove-OPNSenseUser',
|
||||
|
||||
# Firmware Management
|
||||
'Get-OPNSenseFirmware',
|
||||
'Update-OPNSenseFirmware',
|
||||
'Upgrade-OPNSenseFirmware',
|
||||
|
||||
# System Management
|
||||
'Restart-OPNSenseFirewall'
|
||||
)
|
||||
|
||||
# Variables to export from this module
|
||||
VariablesToExport = '*'
|
||||
|
||||
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
|
||||
AliasesToExport = @()
|
||||
|
||||
# DSC resources to export from this module
|
||||
# DscResourcesToExport = @()
|
||||
|
||||
# List of all modules packaged with this module
|
||||
# ModuleList = @()
|
||||
|
||||
# List of all files packaged with this module
|
||||
# FileList = @()
|
||||
|
||||
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
|
||||
PrivateData = @{
|
||||
|
||||
PSData = @{
|
||||
|
||||
# Tags applied to this module. These help with module discovery in online galleries.
|
||||
Tags = @('OPNSense', 'Firewall', 'API', 'Network', 'Security')
|
||||
|
||||
# A URL to the license for this module.
|
||||
LicenseUri = 'https://github.com/freedbygrace/PSOPNSenseAPI/blob/main/LICENSE'
|
||||
|
||||
# A URL to the main website for this project.
|
||||
ProjectUri = 'https://github.com/freedbygrace/PSOPNSenseAPI'
|
||||
|
||||
# A URL to an icon representing this module.
|
||||
# IconUri = ''
|
||||
|
||||
# ReleaseNotes of this module
|
||||
ReleaseNotes = 'Initial release of the PSOPNSenseAPI module'
|
||||
|
||||
# Prerelease string of this module
|
||||
# Prerelease = ''
|
||||
|
||||
# Flag to indicate whether the module requires explicit user acceptance for install/update/save
|
||||
# RequireLicenseAcceptance = $false
|
||||
|
||||
# External dependent modules of this module
|
||||
# ExternalModuleDependencies = @()
|
||||
|
||||
} # End of PSData hashtable
|
||||
|
||||
} # End of PrivateData hashtable
|
||||
|
||||
# HelpInfoURI = ''
|
||||
|
||||
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
|
||||
# DefaultCommandPrefix = ''
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# This file is intentionally left empty.
|
||||
# The module functionality is provided by the binary module (DLL).
|
||||
# This file exists to allow for future PowerShell script functions if needed.
|
||||
@@ -135,12 +135,17 @@ Invoke-OPNSenseNetworkCalculation -Network "10.0.0.0/24" -Operation SupernetSumm
|
||||
# Firmware management
|
||||
Update-OPNSenseFirmware -Wait
|
||||
|
||||
# Major firmware upgrade
|
||||
Start-OPNSenseFirmwareUpgrade -Wait -Timeout 1200
|
||||
|
||||
# Reboot firewall
|
||||
Restart-OPNSenseFirewall -Wait -Timeout 300
|
||||
|
||||
# Backup and restore configuration
|
||||
Backup-OPNSenseConfig -Filename "pre-upgrade-backup"
|
||||
Export-OPNSenseConfig -Path "C:\Backups\opnsense-config.xml"
|
||||
# Configuration management
|
||||
Get-OPNSenseConfig | Restore-OPNSenseConfig -Force # Get and restore configuration in one line
|
||||
$config = Get-OPNSenseConfig # Get configuration as XML document
|
||||
Export-OPNSenseConfig -Path (New-Object System.IO.FileInfo "C:\Backups\opnsense-config.xml")
|
||||
Import-OPNSenseConfig -Path (New-Object System.IO.FileInfo "C:\Backups\opnsense-config.xml") -Force
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
# Release v2025.04.14.2340
|
||||
|
||||
## What's New
|
||||
|
||||
### Added
|
||||
- Port forwarding management (Get, New, Set, Remove)
|
||||
- Added unit tests for interface management
|
||||
- Improved XML documentation for all classes and methods
|
||||
|
||||
### Changed
|
||||
- Updated IPNetwork2 library from version 2.6.618 to 3.1.764
|
||||
- Updated code to use the new namespace (System.Net) for IPNetwork2
|
||||
- Added support for .NET 8.0 and .NET 9.0
|
||||
- Made OPNSenseApiClient more testable by introducing an interface
|
||||
- Fixed warnings in test project
|
||||
- Updated version format to use datetime (yyyy.MM.dd.HHmm)
|
||||
- Organized DLLs in a subfolder for neatness
|
||||
- Used System.Reflection.Assembly::LoadBytes to avoid file lock issues
|
||||
- Removed GitHub workflow
|
||||
- Updated documentation for Tailscale integration
|
||||
- Updated Visual Studio solution documentation
|
||||
- Updated PSD1 files to include all cmdlets
|
||||
|
||||
## Installation
|
||||
|
||||
1. Download the release from the GitHub releases page: https://github.com/freedbygrace/PSOPNSenseAPI/releases/tag/v2025.04.14.2340
|
||||
2. Extract the zip file to a folder in your PowerShell module path
|
||||
3. Import the module: `Import-Module PSOPNSenseAPI`
|
||||
|
||||
## Usage
|
||||
|
||||
```powershell
|
||||
# Connect to the OPNSense firewall
|
||||
Connect-OPNSense -Server "https://firewall.example.com" -ApiKey "your_api_key" -ApiSecret "your_api_secret" -SkipCertificateCheck
|
||||
|
||||
# Get the interfaces
|
||||
Get-OPNSenseInterface
|
||||
|
||||
# Disconnect from the firewall
|
||||
Disconnect-OPNSense
|
||||
```
|
||||
|
||||
For more examples, see the documentation in the `docs` folder.
|
||||
@@ -6,6 +6,8 @@ This component provides cmdlets for managing Tailscale VPN on OPNSense firewalls
|
||||
|
||||
The Tailscale Integration component allows you to install, configure, and manage Tailscale VPN on OPNSense firewalls. It provides cmdlets for enabling Tailscale, configuring subnet routes, and managing the Tailscale connection.
|
||||
|
||||
The module will automatically install the Tailscale plugin if it doesn't exist, making it easy to set up Tailscale on a new OPNSense firewall.
|
||||
|
||||
## Cmdlets
|
||||
|
||||
### Get-OPNSenseTailscaleStatus
|
||||
@@ -138,6 +140,53 @@ Apply-OPNSenseTailscaleChanges
|
||||
Apply-OPNSenseTailscaleChanges -Force
|
||||
```
|
||||
|
||||
### Connect-OPNSenseTailscale
|
||||
|
||||
Connects to the Tailscale network using an authentication key.
|
||||
|
||||
#### Parameters
|
||||
|
||||
- **AuthKey** - The Tailscale authentication key.
|
||||
- **InstallIfMissing** - Installs the Tailscale plugin if it's not already installed.
|
||||
- **EnableIfDisabled** - Enables Tailscale if it's disabled.
|
||||
- **StartIfStopped** - Starts the Tailscale service if it's stopped.
|
||||
- **SubnetRoutes** - The subnet routes to advertise to Tailscale.
|
||||
- **AdvertiseRoutes** - Whether to advertise routes to Tailscale.
|
||||
- **Force** - Suppresses the confirmation prompt.
|
||||
- **PassThru** - Returns the Tailscale status.
|
||||
|
||||
#### Examples
|
||||
|
||||
```powershell
|
||||
# Connect to Tailscale with an auth key
|
||||
Connect-OPNSenseTailscale -AuthKey "tskey-auth-abcdef123456"
|
||||
|
||||
# Connect to Tailscale with automatic installation and enablement
|
||||
Connect-OPNSenseTailscale -AuthKey "tskey-auth-abcdef123456" -InstallIfMissing -EnableIfDisabled -StartIfStopped
|
||||
|
||||
# Connect to Tailscale and advertise subnet routes
|
||||
Connect-OPNSenseTailscale -AuthKey "tskey-auth-abcdef123456" -SubnetRoutes "192.168.1.0/24","10.0.0.0/8" -AdvertiseRoutes
|
||||
```
|
||||
|
||||
### Disconnect-OPNSenseTailscale
|
||||
|
||||
Disconnects from the Tailscale network.
|
||||
|
||||
#### Parameters
|
||||
|
||||
- **Force** - Suppresses the confirmation prompt.
|
||||
- **PassThru** - Returns the Tailscale status.
|
||||
|
||||
#### Examples
|
||||
|
||||
```powershell
|
||||
# Disconnect from Tailscale
|
||||
Disconnect-OPNSenseTailscale
|
||||
|
||||
# Disconnect from Tailscale without confirmation
|
||||
Disconnect-OPNSenseTailscale -Force
|
||||
```
|
||||
|
||||
## Common Scenarios
|
||||
|
||||
### Installing and Configuring Tailscale
|
||||
@@ -159,6 +208,19 @@ Apply-OPNSenseTailscaleChanges -Force
|
||||
Disconnect-OPNSense
|
||||
```
|
||||
|
||||
### Simplified Installation and Connection
|
||||
|
||||
```powershell
|
||||
# Connect to the OPNSense firewall
|
||||
Connect-OPNSense -Server "https://firewall.example.com" -ApiKey "your_api_key" -ApiSecret "your_api_secret" -SkipCertificateCheck
|
||||
|
||||
# Connect to Tailscale with automatic installation and enablement
|
||||
Connect-OPNSenseTailscale -AuthKey "tskey-auth-abcdef123456" -InstallIfMissing -EnableIfDisabled -StartIfStopped -Force
|
||||
|
||||
# Disconnect from the firewall
|
||||
Disconnect-OPNSense
|
||||
```
|
||||
|
||||
### Configuring Tailscale as a Subnet Router
|
||||
|
||||
```powershell
|
||||
@@ -177,14 +239,8 @@ foreach ($interface in $interfaces) {
|
||||
}
|
||||
}
|
||||
|
||||
# Join the subnets with commas
|
||||
$advertisedRoutes = $subnets -join ","
|
||||
|
||||
# Enable Tailscale with route advertisement
|
||||
Enable-OPNSenseTailscale -AuthKey "tskey-auth-abcdef123456" -AdvertiseRoutes $advertisedRoutes -Force
|
||||
|
||||
# Apply the changes
|
||||
Apply-OPNSenseTailscaleChanges -Force
|
||||
# Connect to Tailscale with subnet route advertisement
|
||||
Connect-OPNSenseTailscale -AuthKey "tskey-auth-abcdef123456" -SubnetRoutes $subnets -AdvertiseRoutes -InstallIfMissing -Force
|
||||
|
||||
# Disconnect from the firewall
|
||||
Disconnect-OPNSense
|
||||
@@ -206,6 +262,26 @@ Apply-OPNSenseTailscaleChanges -Force
|
||||
Disconnect-OPNSense
|
||||
```
|
||||
|
||||
### Connecting and Disconnecting from Tailscale
|
||||
|
||||
```powershell
|
||||
# Connect to the OPNSense firewall
|
||||
Connect-OPNSense -Server "https://firewall.example.com" -ApiKey "your_api_key" -ApiSecret "your_api_secret" -SkipCertificateCheck
|
||||
|
||||
# Connect to Tailscale
|
||||
Connect-OPNSenseTailscale -AuthKey "tskey-auth-abcdef123456" -InstallIfMissing -EnableIfDisabled -StartIfStopped -Force
|
||||
|
||||
# Get Tailscale status
|
||||
$status = Get-OPNSenseTailscaleStatus
|
||||
Write-Output "Tailscale Status: $($status.Status)"
|
||||
|
||||
# Disconnect from Tailscale
|
||||
Disconnect-OPNSenseTailscale -Force
|
||||
|
||||
# Disconnect from the firewall
|
||||
Disconnect-OPNSense
|
||||
```
|
||||
|
||||
### Updating Tailscale Routes
|
||||
|
||||
```powershell
|
||||
@@ -253,6 +329,7 @@ Disconnect-OPNSense
|
||||
|
||||
- Tailscale requires the Tailscale plugin to be installed on the OPNSense firewall.
|
||||
- The `Install-OPNSenseTailscale` cmdlet will install the plugin if it's not already installed.
|
||||
- The `Connect-OPNSenseTailscale` cmdlet can automatically install the plugin, enable Tailscale, and start the service with the `-InstallIfMissing`, `-EnableIfDisabled`, and `-StartIfStopped` parameters.
|
||||
- Tailscale authentication keys can be generated from the Tailscale admin console.
|
||||
- Authentication keys are single-use and expire after a short period.
|
||||
- When advertising routes, ensure that the routes are valid and do not overlap with Tailscale's internal routes.
|
||||
@@ -261,3 +338,5 @@ Disconnect-OPNSense
|
||||
- The `ExitNode` option allows other Tailscale nodes to use the OPNSense firewall as an internet gateway.
|
||||
- Changes to Tailscale settings are not applied until you call `Apply-OPNSenseTailscaleChanges`.
|
||||
- Consider using the `-PassThru` parameter when updating Tailscale settings to verify the changes.
|
||||
- The `Connect-OPNSenseTailscale` cmdlet combines multiple steps (installation, enablement, and connection) into a single command.
|
||||
- The `Disconnect-OPNSenseTailscale` cmdlet disconnects from the Tailscale network but does not disable Tailscale.
|
||||
|
||||
@@ -11,6 +11,7 @@ The PSOPNSenseAPI solution is a Visual Studio solution that contains the source
|
||||
The solution contains the following projects:
|
||||
|
||||
- **PSOPNSenseAPI**: The main project containing the PowerShell module code.
|
||||
- **PSOPNSenseAPI.Tests**: The test project containing unit tests for the PowerShell module.
|
||||
|
||||
## Opening the Solution
|
||||
|
||||
@@ -56,19 +57,19 @@ If you encounter issues with the IPNetwork2 library, here are some common troubl
|
||||
|
||||
1. **Check the reference**: Ensure that the IPNetwork2 package is properly referenced in the project file.
|
||||
```xml
|
||||
<PackageReference Include="IPNetwork2" Version="2.6.618" />
|
||||
<PackageReference Include="IPNetwork2" Version="3.1.764" />
|
||||
```
|
||||
|
||||
2. **Verify the namespace**: The correct namespace for IPNetwork2 is `System.Net.IPNetwork`.
|
||||
2. **Verify the namespace**: The correct namespace for IPNetwork2 is `System.Net`.
|
||||
```csharp
|
||||
using System.Net.IPNetwork;
|
||||
using System.Net;
|
||||
```
|
||||
|
||||
3. **Check the class name**: The main class in IPNetwork2 is `IPNetwork`, not `IPNetwork2`.
|
||||
```csharp
|
||||
// Correct usage
|
||||
System.Net.IPNetwork.IPNetwork network = System.Net.IPNetwork.IPNetwork.Parse("192.168.1.0/24");
|
||||
|
||||
System.Net.IPNetwork network = System.Net.IPNetwork.Parse("192.168.1.0/24");
|
||||
|
||||
// Incorrect usage
|
||||
IPNetwork2 network = IPNetwork2.Parse("192.168.1.0/24");
|
||||
```
|
||||
@@ -100,7 +101,7 @@ When adding new features to the solution:
|
||||
2. Implement service classes in the `Services` directory
|
||||
3. Create PowerShell cmdlets in the `Cmdlets` directory
|
||||
4. Update the module manifest (`PSOPNSenseAPI.psd1`) to export the new cmdlets
|
||||
5. Add tests for the new features
|
||||
5. Add tests for the new features in the `PSOPNSenseAPI.Tests` project
|
||||
6. Update documentation
|
||||
|
||||
## Testing
|
||||
@@ -112,9 +113,24 @@ The solution includes unit tests that can be run from Visual Studio using the Te
|
||||
.\build\test.ps1
|
||||
```
|
||||
|
||||
## Continuous Integration
|
||||
## Release Process
|
||||
|
||||
The project uses GitHub Actions for continuous integration. The CI workflow builds and tests the solution on every push to the main branch.
|
||||
The project includes a script to automate the release process. To create a new release:
|
||||
|
||||
1. Run the `scripts\Create-Release.ps1` script
|
||||
2. Follow the instructions to create a GitHub release
|
||||
|
||||
The script will:
|
||||
|
||||
1. Update the version in the project file and module manifest to the current date and time (yyyy.MM.dd.HHmm)
|
||||
2. Build the solution in Release mode
|
||||
3. Copy the DLLs to the output folder
|
||||
4. Create a zip file of the module
|
||||
5. Clean up old zip files, keeping only the latest one
|
||||
6. Commit and push the changes
|
||||
7. Create a release note file
|
||||
|
||||
After running the script, you'll need to manually create a GitHub release and attach the zip file.
|
||||
|
||||
## Dependencies
|
||||
|
||||
@@ -123,10 +139,29 @@ The solution has the following dependencies:
|
||||
- PowerShellStandard.Library (5.1.1)
|
||||
- Newtonsoft.Json (13.0.3)
|
||||
- System.Net.Http (4.3.4)
|
||||
- IPNetwork2 (2.6.618)
|
||||
- IPNetwork2 (3.1.764)
|
||||
|
||||
## Notes
|
||||
|
||||
- The solution is configured to target both .NET Framework 4.7.2 and .NET Standard 2.0 to support both Windows PowerShell 5.1 and PowerShell 7+.
|
||||
- The module uses a versioning scheme of `yyyy.MM.dd.HHmm` for releases, which is automatically generated during the build process.
|
||||
- The module uses a versioning scheme of `yyyy.MM.dd.HHmm` for releases.
|
||||
- The solution includes XML documentation comments that are used to generate help content for the PowerShell cmdlets.
|
||||
- The module uses System.Reflection.Assembly::LoadBytes to load DLLs to avoid file lock issues.
|
||||
- DLLs are organized in a lib subfolder for neatness.
|
||||
|
||||
## Module Structure
|
||||
|
||||
The module has the following structure:
|
||||
|
||||
```
|
||||
PSOPNSenseAPI/
|
||||
├── lib/ # DLL files
|
||||
│ ├── Newtonsoft.Json.dll
|
||||
│ ├── PSOPNSenseAPI.dll
|
||||
│ ├── System.Net.IPNetwork.dll
|
||||
│ └── ...
|
||||
├── PSOPNSenseAPI.psd1 # Module manifest
|
||||
└── PSOPNSenseAPI.psm1 # Module script that loads DLLs
|
||||
```
|
||||
|
||||
The PSM1 file uses System.Reflection.Assembly::LoadBytes to load the DLLs from the lib folder, which avoids file lock issues that can occur when PowerShell loads DLLs directly.
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
# Export-OPNSenseConfig
|
||||
|
||||
## SYNOPSIS
|
||||
Exports the OPNSense firewall configuration.
|
||||
|
||||
## SYNTAX
|
||||
|
||||
```
|
||||
Export-OPNSenseConfig -Path <FileInfo> [-Force]
|
||||
```
|
||||
|
||||
## DESCRIPTION
|
||||
The Export-OPNSenseConfig cmdlet exports the OPNSense firewall configuration to a file.
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
### Example 1: Export the configuration to a file
|
||||
```powershell
|
||||
$path = New-Object System.IO.FileInfo "C:\Backups\opnsense-config.xml"
|
||||
Export-OPNSenseConfig -Path $path
|
||||
```
|
||||
|
||||
This example exports the OPNSense firewall configuration to a file.
|
||||
|
||||
## PARAMETERS
|
||||
|
||||
### -Path
|
||||
The path to save the configuration file. Must be a FileInfo object with an .xml extension.
|
||||
|
||||
```yaml
|
||||
Type: FileInfo
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: True
|
||||
Position: 0
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Force
|
||||
Overwrites the file if it exists.
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### CommonParameters
|
||||
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
|
||||
|
||||
## INPUTS
|
||||
|
||||
### None
|
||||
|
||||
## OUTPUTS
|
||||
|
||||
### None
|
||||
|
||||
## NOTES
|
||||
This cmdlet requires a connection to an OPNSense firewall. Use Connect-OPNSense to establish a connection.
|
||||
If the directory specified in the Path parameter does not exist, it will be created.
|
||||
|
||||
## RELATED LINKS
|
||||
|
||||
[Get-OPNSenseConfig](Get-OPNSenseConfig.md)
|
||||
[Import-OPNSenseConfig](Import-OPNSenseConfig.md)
|
||||
[Restore-OPNSenseConfig](Restore-OPNSenseConfig.md)
|
||||
@@ -0,0 +1,52 @@
|
||||
# Get-OPNSenseConfig
|
||||
|
||||
## SYNOPSIS
|
||||
Gets the OPNSense firewall configuration as an XML document.
|
||||
|
||||
## SYNTAX
|
||||
|
||||
```
|
||||
Get-OPNSenseConfig
|
||||
```
|
||||
|
||||
## DESCRIPTION
|
||||
The Get-OPNSenseConfig cmdlet retrieves the OPNSense firewall configuration and returns it as an XML document.
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
### Example 1: Get the configuration as an XML document
|
||||
```powershell
|
||||
$config = Get-OPNSenseConfig
|
||||
```
|
||||
|
||||
This example retrieves the OPNSense firewall configuration as an XML document.
|
||||
|
||||
### Example 2: Get the configuration and pipe it to Restore-OPNSenseConfig
|
||||
```powershell
|
||||
Get-OPNSenseConfig | Restore-OPNSenseConfig
|
||||
```
|
||||
|
||||
This example retrieves the OPNSense firewall configuration and restores it.
|
||||
|
||||
## PARAMETERS
|
||||
|
||||
### CommonParameters
|
||||
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
|
||||
|
||||
## INPUTS
|
||||
|
||||
### None
|
||||
|
||||
## OUTPUTS
|
||||
|
||||
### System.Xml.XmlDocument
|
||||
The OPNSense configuration as an XML document.
|
||||
|
||||
## NOTES
|
||||
This cmdlet requires a connection to an OPNSense firewall. Use Connect-OPNSense to establish a connection.
|
||||
|
||||
## RELATED LINKS
|
||||
|
||||
[Restore-OPNSenseConfig](Restore-OPNSenseConfig.md)
|
||||
[Export-OPNSenseConfig](Export-OPNSenseConfig.md)
|
||||
[Import-OPNSenseConfig](Import-OPNSenseConfig.md)
|
||||
@@ -0,0 +1,106 @@
|
||||
# Import-OPNSenseConfig
|
||||
|
||||
## SYNOPSIS
|
||||
Imports an OPNSense firewall configuration.
|
||||
|
||||
## SYNTAX
|
||||
|
||||
```
|
||||
Import-OPNSenseConfig -Path <FileInfo> [-Force] [-WhatIf] [-Confirm]
|
||||
```
|
||||
|
||||
## DESCRIPTION
|
||||
The Import-OPNSenseConfig cmdlet imports an OPNSense firewall configuration from a file.
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
### Example 1: Import a configuration from a file
|
||||
```powershell
|
||||
$path = New-Object System.IO.FileInfo "C:\Backups\opnsense-config.xml"
|
||||
Import-OPNSenseConfig -Path $path
|
||||
```
|
||||
|
||||
This example imports an OPNSense firewall configuration from a file.
|
||||
|
||||
## PARAMETERS
|
||||
|
||||
### -Path
|
||||
The path to the configuration file. Must be a FileInfo object with an .xml extension.
|
||||
|
||||
```yaml
|
||||
Type: FileInfo
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: True
|
||||
Position: 0
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Force
|
||||
Suppresses the confirmation prompt.
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -WhatIf
|
||||
Shows what would happen if the cmdlet runs. The cmdlet is not run.
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases: wi
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Confirm
|
||||
Prompts you for confirmation before running the cmdlet.
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases: cf
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### CommonParameters
|
||||
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
|
||||
|
||||
## INPUTS
|
||||
|
||||
### None
|
||||
|
||||
## OUTPUTS
|
||||
|
||||
### None
|
||||
|
||||
## NOTES
|
||||
This cmdlet requires a connection to an OPNSense firewall. Use Connect-OPNSense to establish a connection.
|
||||
The firewall will restart after the configuration is imported.
|
||||
|
||||
## RELATED LINKS
|
||||
|
||||
[Get-OPNSenseConfig](Get-OPNSenseConfig.md)
|
||||
[Export-OPNSenseConfig](Export-OPNSenseConfig.md)
|
||||
[Restore-OPNSenseConfig](Restore-OPNSenseConfig.md)
|
||||
@@ -0,0 +1,142 @@
|
||||
# Restore-OPNSenseConfig
|
||||
|
||||
## SYNOPSIS
|
||||
Restores an OPNSense firewall configuration.
|
||||
|
||||
## SYNTAX
|
||||
|
||||
### Filename
|
||||
```
|
||||
Restore-OPNSenseConfig -Filename <String> [-Force] [-WhatIf] [-Confirm]
|
||||
```
|
||||
|
||||
### XmlDocument
|
||||
```
|
||||
Restore-OPNSenseConfig -XmlDocument <XmlDocument> [-Force] [-WhatIf] [-Confirm]
|
||||
```
|
||||
|
||||
## DESCRIPTION
|
||||
The Restore-OPNSenseConfig cmdlet restores an OPNSense firewall configuration from a backup or an XML document.
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
### Example 1: Restore a configuration backup
|
||||
```powershell
|
||||
Restore-OPNSenseConfig -Filename "config-backup-20250414-1234.xml"
|
||||
```
|
||||
|
||||
This example restores an OPNSense firewall configuration from a backup file.
|
||||
|
||||
### Example 2: Restore a configuration from an XML document
|
||||
```powershell
|
||||
$config = Get-OPNSenseConfig
|
||||
Restore-OPNSenseConfig -XmlDocument $config
|
||||
```
|
||||
|
||||
This example restores an OPNSense firewall configuration from an XML document.
|
||||
|
||||
### Example 3: Restore a configuration from the pipeline
|
||||
```powershell
|
||||
Get-OPNSenseConfig | Restore-OPNSenseConfig
|
||||
```
|
||||
|
||||
This example restores an OPNSense firewall configuration from the pipeline.
|
||||
|
||||
## PARAMETERS
|
||||
|
||||
### -Filename
|
||||
The filename of the backup to restore.
|
||||
|
||||
```yaml
|
||||
Type: String
|
||||
Parameter Sets: Filename
|
||||
Aliases:
|
||||
|
||||
Required: True
|
||||
Position: 0
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -XmlDocument
|
||||
The XML document containing the configuration to restore.
|
||||
|
||||
```yaml
|
||||
Type: XmlDocument
|
||||
Parameter Sets: XmlDocument
|
||||
Aliases:
|
||||
|
||||
Required: True
|
||||
Position: 0
|
||||
Default value: None
|
||||
Accept pipeline input: True (ByValue)
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Force
|
||||
Suppresses the confirmation prompt.
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -WhatIf
|
||||
Shows what would happen if the cmdlet runs. The cmdlet is not run.
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases: wi
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Confirm
|
||||
Prompts you for confirmation before running the cmdlet.
|
||||
|
||||
```yaml
|
||||
Type: SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases: cf
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### CommonParameters
|
||||
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
|
||||
|
||||
## INPUTS
|
||||
|
||||
### System.Xml.XmlDocument
|
||||
An XML document containing the OPNSense configuration.
|
||||
|
||||
## OUTPUTS
|
||||
|
||||
### None
|
||||
|
||||
## NOTES
|
||||
This cmdlet requires a connection to an OPNSense firewall. Use Connect-OPNSense to establish a connection.
|
||||
The firewall will restart after the configuration is restored.
|
||||
|
||||
## RELATED LINKS
|
||||
|
||||
[Get-OPNSenseConfig](Get-OPNSenseConfig.md)
|
||||
[Export-OPNSenseConfig](Export-OPNSenseConfig.md)
|
||||
[Import-OPNSenseConfig](Import-OPNSenseConfig.md)
|
||||
@@ -8,22 +8,29 @@ Connect-OPNSense -Server "https://firewall.example.com" -ApiKey "your_api_key" -
|
||||
$backups = Get-OPNSenseConfigBackup
|
||||
$backups | Format-Table -Property Filename, Description, FileSize, Date, Version
|
||||
|
||||
# Create a new configuration backup
|
||||
$backupFilename = Backup-OPNSenseConfig -Filename "pre-upgrade-backup"
|
||||
Write-Output "Created backup: $backupFilename"
|
||||
# Get the current configuration as an XML document
|
||||
$config = Get-OPNSenseConfig
|
||||
Write-Output "Retrieved configuration with root element: $($config.DocumentElement.Name)"
|
||||
|
||||
# Export the configuration to a file
|
||||
$exportPath = "C:\Backups\opnsense-config.xml"
|
||||
$exportPath = New-Object System.IO.FileInfo "C:\Backups\opnsense-config.xml"
|
||||
Export-OPNSenseConfig -Path $exportPath -Force
|
||||
Write-Output "Exported configuration to: $exportPath"
|
||||
Write-Output "Exported configuration to: $($exportPath.FullName)"
|
||||
|
||||
# Import a configuration from a file
|
||||
# Note: This will restart the firewall
|
||||
# Import-OPNSenseConfig -Path $exportPath -Confirm
|
||||
# Import-OPNSenseConfig -Path $exportPath -Force
|
||||
|
||||
# Restore a configuration backup
|
||||
# Restore a configuration backup by filename
|
||||
# Note: This will restart the firewall
|
||||
# Restore-OPNSenseConfig -Filename $backupFilename -Confirm
|
||||
# Restore-OPNSenseConfig -Filename "config-backup-20250415-1234.xml" -Force
|
||||
|
||||
# Restore a configuration from an XML document
|
||||
# Note: This will restart the firewall
|
||||
# Restore-OPNSenseConfig -XmlDocument $config -Force
|
||||
|
||||
# Pipeline example: Get and restore configuration in one line
|
||||
# Get-OPNSenseConfig | Restore-OPNSenseConfig -Force
|
||||
|
||||
# Disconnect from the firewall
|
||||
Disconnect-OPNSense
|
||||
|
||||
@@ -27,7 +27,8 @@ Write-Output "Firmware updated successfully"
|
||||
|
||||
# Upgrade firmware (major version upgrade)
|
||||
# Note: This will restart the firewall
|
||||
# Upgrade-OPNSenseFirmware -Wait -Timeout 1200
|
||||
Start-OPNSenseFirmwareUpgrade -Wait -Timeout 1200
|
||||
Write-Output "Firmware upgraded successfully"
|
||||
|
||||
# Restart the firewall
|
||||
Restart-OPNSenseFirewall -Wait -Timeout 300
|
||||
|
||||
@@ -1,85 +1,213 @@
|
||||
@{
|
||||
RootModule = 'PSOPNSenseAPI.psm1'
|
||||
ModuleVersion = '2025.04.14.2306'
|
||||
GUID = '1f0e4b77-cc7c-4a1e-b45a-d7c51a3c562e'
|
||||
Author = 'PSOPNSenseAPI Contributors'
|
||||
CompanyName = 'PSOPNSenseAPI'
|
||||
Copyright = 'Copyright (c) 2025 PSOPNSenseAPI Contributors'
|
||||
Description = 'PowerShell module for interacting with the OPNSense API to configure firewalls'
|
||||
PowerShellVersion = '5.1'
|
||||
# Script module or binary module file associated with this manifest.
|
||||
RootModule = 'lib\PSOPNSenseAPI.dll'
|
||||
|
||||
# Version number of this module.
|
||||
ModuleVersion = '2025.04.15.1143'
|
||||
|
||||
# Supported PSEditions
|
||||
CompatiblePSEditions = @('Desktop', 'Core')
|
||||
DotNetFrameworkVersion = '4.7.2'
|
||||
CLRVersion = '4.0.0'
|
||||
|
||||
# ID used to uniquely identify this module
|
||||
GUID = '9a3b4c55-5f9a-4b8c-87d9-9a7a5cdd5c9f'
|
||||
|
||||
# Author of this module
|
||||
Author = 'PSOPNSenseAPI Contributors'
|
||||
|
||||
# Company or vendor of this module
|
||||
CompanyName = 'PSOPNSenseAPI'
|
||||
|
||||
# Copyright statement for this module
|
||||
Copyright = '(c) 2025 PSOPNSenseAPI Contributors. All rights reserved.'
|
||||
|
||||
# Description of the functionality provided by this module
|
||||
Description = 'PowerShell module for interacting with the OPNSense API to configure firewalls'
|
||||
|
||||
# Minimum version of the PowerShell engine required by this module
|
||||
PowerShellVersion = '5.1'
|
||||
|
||||
# Name of the PowerShell host required by this module
|
||||
# PowerShellHostName = ''
|
||||
|
||||
# Minimum version of the PowerShell host required by this module
|
||||
# PowerShellHostVersion = ''
|
||||
|
||||
# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||
# DotNetFrameworkVersion = '4.7.2'
|
||||
|
||||
# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||
ClrVersion = '4.0'
|
||||
|
||||
# Processor architecture (None, X86, Amd64) required by this module
|
||||
# ProcessorArchitecture = ''
|
||||
|
||||
# Modules that must be imported into the global environment prior to importing this module
|
||||
# RequiredModules = @()
|
||||
|
||||
# Assemblies that must be loaded prior to importing this module
|
||||
# RequiredAssemblies = @()
|
||||
|
||||
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
|
||||
# ScriptsToProcess = @()
|
||||
|
||||
# Type files (.ps1xml) to be loaded when importing this module
|
||||
# TypesToProcess = @()
|
||||
|
||||
# Format files (.ps1xml) to be loaded when importing this module
|
||||
# FormatsToProcess = @()
|
||||
|
||||
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
|
||||
# NestedModules = @()
|
||||
|
||||
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
|
||||
FunctionsToExport = @()
|
||||
|
||||
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
|
||||
CmdletsToExport = @(
|
||||
'Apply-OPNSenseFirewallChanges',
|
||||
'Connect-OPNSense',
|
||||
'Disconnect-OPNSense',
|
||||
'Get-OPNSenseInterface',
|
||||
'Set-OPNSenseInterface',
|
||||
'Restart-OPNSenseInterface',
|
||||
'Get-OPNSenseInterfaceStatistics',
|
||||
'Get-OPNSenseVLAN',
|
||||
'New-OPNSenseVLAN',
|
||||
'Set-OPNSenseVLAN',
|
||||
'Remove-OPNSenseVLAN',
|
||||
'Get-OPNSenseFirewallRule',
|
||||
'New-OPNSenseFirewallRule',
|
||||
'Set-OPNSenseFirewallRule',
|
||||
'Remove-OPNSenseFirewallRule',
|
||||
'Enable-OPNSenseFirewallRule',
|
||||
'Disable-OPNSenseFirewallRule',
|
||||
'Get-OPNSenseAlias',
|
||||
'New-OPNSenseAlias',
|
||||
'Set-OPNSenseAlias',
|
||||
'Remove-OPNSenseAlias',
|
||||
'Get-OPNSenseNATRule',
|
||||
'New-OPNSenseNATRule',
|
||||
'Set-OPNSenseNATRule',
|
||||
'Remove-OPNSenseNATRule',
|
||||
'Get-OPNSensePlugin',
|
||||
'Enable-OPNSensePlugin',
|
||||
'Disable-OPNSensePlugin',
|
||||
'Install-OPNSensePlugin',
|
||||
'Uninstall-OPNSensePlugin',
|
||||
'Get-OPNSenseUser',
|
||||
'New-OPNSenseUser',
|
||||
'Set-OPNSenseUser',
|
||||
'Remove-OPNSenseUser',
|
||||
'Get-OPNSenseFirmware',
|
||||
'Update-OPNSenseFirmware',
|
||||
'Upgrade-OPNSenseFirmware',
|
||||
'Restart-OPNSenseFirewall',
|
||||
'New-OPNSenseSubnetVLANs',
|
||||
'Get-OPNSenseDHCPServer',
|
||||
'Set-OPNSenseDHCPServer',
|
||||
'Get-OPNSenseDHCPStaticMapping',
|
||||
'New-OPNSenseDHCPStaticMapping',
|
||||
'Set-OPNSenseDHCPStaticMapping',
|
||||
'Remove-OPNSenseDHCPStaticMapping',
|
||||
'Get-OPNSenseCronJob',
|
||||
'New-OPNSenseCronJob',
|
||||
'Set-OPNSenseCronJob',
|
||||
'Remove-OPNSenseCronJob',
|
||||
'Enable-OPNSenseCronJob',
|
||||
'Disable-OPNSenseCronJob',
|
||||
'Get-OPNSenseTailscale',
|
||||
'Enable-OPNSenseTailscale',
|
||||
'Disable-OPNSenseTailscale',
|
||||
'Connect-OPNSenseTailscale',
|
||||
'ConvertTo-OPNSenseNetworkNotation',
|
||||
'Disable-OPNSenseCronJob',
|
||||
'Disable-OPNSenseFirewallRule',
|
||||
'Disable-OPNSensePlugin',
|
||||
'Disable-OPNSenseTailscale',
|
||||
'Disconnect-OPNSense',
|
||||
'Disconnect-OPNSenseTailscale',
|
||||
'Enable-OPNSenseCronJob',
|
||||
'Enable-OPNSenseFirewallRule',
|
||||
'Enable-OPNSensePlugin',
|
||||
'Enable-OPNSenseTailscale',
|
||||
'Export-OPNSenseConfig',
|
||||
'Get-OPNSenseAlias',
|
||||
'Get-OPNSenseConfig',
|
||||
'Get-OPNSenseConfigBackup',
|
||||
'Get-OPNSenseConnection',
|
||||
'Get-OPNSenseCronJob',
|
||||
'Get-OPNSenseDHCPLease',
|
||||
'Get-OPNSenseDHCPOption',
|
||||
'Get-OPNSenseDHCPServer',
|
||||
'Get-OPNSenseDHCPStaticMapping',
|
||||
'Get-OPNSenseDNSForwarding',
|
||||
'Get-OPNSenseDNSForwardingHost',
|
||||
'Get-OPNSenseDNSOverride',
|
||||
'Get-OPNSenseDNSServer',
|
||||
'Get-OPNSenseFirewallRule',
|
||||
'Get-OPNSenseFirmware',
|
||||
'Get-OPNSenseGateway',
|
||||
'Get-OPNSenseInterface',
|
||||
'Get-OPNSenseInterfaceStatistics',
|
||||
'Get-OPNSensePlugin',
|
||||
'Get-OPNSensePortForwardingRule',
|
||||
'Get-OPNSenseRoute',
|
||||
'Get-OPNSenseSystemDNS',
|
||||
'Get-OPNSenseTailscaleStatus',
|
||||
'Get-OPNSenseUser',
|
||||
'Get-OPNSenseVLAN',
|
||||
'Import-OPNSenseConfig',
|
||||
'Install-OPNSensePlugin',
|
||||
'Invoke-OPNSenseNetworkCalculation',
|
||||
'New-OPNSenseAlias',
|
||||
'New-OPNSenseCronJob',
|
||||
'New-OPNSenseDHCPOption',
|
||||
'New-OPNSenseDHCPStaticMapping',
|
||||
'New-OPNSenseDNSForwardingHost',
|
||||
'New-OPNSenseDNSOverride',
|
||||
'New-OPNSenseFirewallRule',
|
||||
'New-OPNSenseGateway',
|
||||
'New-OPNSensePortForwardingRule',
|
||||
'New-OPNSenseRoute',
|
||||
'New-OPNSenseSubnetVLANs',
|
||||
'New-OPNSenseUser',
|
||||
'New-OPNSenseVLAN',
|
||||
'Remove-OPNSenseAlias',
|
||||
'Remove-OPNSenseCronJob',
|
||||
'Remove-OPNSenseDHCPLease',
|
||||
'Remove-OPNSenseDHCPOption',
|
||||
'Remove-OPNSenseDHCPStaticMapping',
|
||||
'Remove-OPNSenseDNSForwardingHost',
|
||||
'Remove-OPNSenseDNSOverride',
|
||||
'Remove-OPNSenseFirewallRule',
|
||||
'Remove-OPNSenseGateway',
|
||||
'Remove-OPNSensePortForwardingRule',
|
||||
'Remove-OPNSenseRoute',
|
||||
'Remove-OPNSenseUser',
|
||||
'Remove-OPNSenseVLAN',
|
||||
'Restart-OPNSenseFirewall',
|
||||
'Restart-OPNSenseInterface',
|
||||
'Restore-OPNSenseConfig',
|
||||
'Set-OPNSenseAlias',
|
||||
'Set-OPNSenseCronJob',
|
||||
'Set-OPNSenseDHCPOption',
|
||||
'Set-OPNSenseDHCPServer',
|
||||
'Set-OPNSenseDHCPStaticMapping',
|
||||
'Set-OPNSenseDNSForwarding',
|
||||
'Set-OPNSenseDNSForwardingHost',
|
||||
'Set-OPNSenseDNSServer',
|
||||
'Set-OPNSenseFirewallRule',
|
||||
'Set-OPNSenseGateway',
|
||||
'Set-OPNSenseInterface',
|
||||
'Set-OPNSensePortForwardingRule',
|
||||
'Remove-OPNSensePortForwardingRule'
|
||||
'Set-OPNSenseRoute',
|
||||
'Set-OPNSenseSystemDNS',
|
||||
'Set-OPNSenseUser',
|
||||
'Set-OPNSenseVLAN',
|
||||
'Uninstall-OPNSensePlugin',
|
||||
'Update-OPNSenseFirmware',
|
||||
'Start-OPNSenseFirmwareUpgrade'
|
||||
)
|
||||
|
||||
# Variables to export from this module
|
||||
VariablesToExport = @()
|
||||
|
||||
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
|
||||
AliasesToExport = @()
|
||||
|
||||
# DSC resources to export from this module
|
||||
# DscResourcesToExport = @()
|
||||
|
||||
# List of all modules packaged with this module
|
||||
# ModuleList = @()
|
||||
|
||||
# List of all files packaged with this module
|
||||
# FileList = @()
|
||||
|
||||
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
|
||||
PrivateData = @{
|
||||
|
||||
PSData = @{
|
||||
|
||||
# Tags applied to this module. These help with module discovery in online galleries.
|
||||
Tags = @('PowerShell', 'OPNSense', 'Firewall', 'API')
|
||||
|
||||
# A URL to the license for this module.
|
||||
LicenseUri = 'https://github.com/freedbygrace/PSOPNSenseAPI/blob/main/LICENSE'
|
||||
|
||||
# A URL to the main website for this project.
|
||||
ProjectUri = 'https://github.com/freedbygrace/PSOPNSenseAPI'
|
||||
|
||||
# A URL to an icon representing this module.
|
||||
# IconUri = ''
|
||||
|
||||
# ReleaseNotes of this module
|
||||
ReleaseNotes = 'https://github.com/freedbygrace/PSOPNSenseAPI/blob/main/CHANGELOG.md'
|
||||
}
|
||||
}
|
||||
|
||||
# Prerelease string of this module
|
||||
# Prerelease = ''
|
||||
|
||||
# Flag to indicate whether the module requires explicit user acceptance for install/update/save
|
||||
# RequireLicenseAcceptance = $false
|
||||
|
||||
# External dependent modules of this module
|
||||
# ExternalModuleDependencies = @()
|
||||
|
||||
} # End of PSData hashtable
|
||||
|
||||
} # End of PrivateData hashtable
|
||||
|
||||
# HelpInfoURI of this module
|
||||
# HelpInfoURI = ''
|
||||
|
||||
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
|
||||
# DefaultCommandPrefix = ''
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
# Load assemblies from the lib folder using System.Reflection.Assembly::LoadBytes
|
||||
# This avoids file lock issues when the module is loaded
|
||||
|
||||
$libPath = Join-Path $PSScriptRoot "lib"
|
||||
$dllFiles = Get-ChildItem -Path $libPath -Filter "*.dll"
|
||||
|
||||
foreach ($dll in $dllFiles) {
|
||||
try {
|
||||
$dllBytes = [System.IO.File]::ReadAllBytes($dll.FullName)
|
||||
[System.Reflection.Assembly]::Load($dllBytes) | Out-Null
|
||||
Write-Verbose "Loaded assembly: $($dll.Name)"
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to load assembly $($dll.Name): $_"
|
||||
}
|
||||
}
|
||||
|
||||
# Export all cmdlets
|
||||
$cmdlets = [System.AppDomain]::CurrentDomain.GetAssemblies() |
|
||||
Where-Object { $_.FullName -like "*PSOPNSenseAPI*" } |
|
||||
ForEach-Object { $_.GetTypes() } |
|
||||
Where-Object { $_.IsPublic -and $_.IsClass -and $_.Name -like "*Cmdlet" } |
|
||||
ForEach-Object { $_.Name }
|
||||
|
||||
Export-ModuleMember -Cmdlet $cmdlets
|
||||
Binary file not shown.
@@ -0,0 +1,130 @@
|
||||
# Create-Release.ps1
|
||||
# This script creates a new release of the PSOPNSenseAPI module
|
||||
|
||||
# Get the current date and time in the format yyyy.MM.dd.HHmm
|
||||
$version = Get-Date -Format "yyyy.MM.dd.HHmm"
|
||||
|
||||
# Update the version in the project file
|
||||
$projectFile = "src\PSOPNSenseAPI\PSOPNSenseAPI.csproj"
|
||||
$projectContent = Get-Content $projectFile
|
||||
$projectContent = $projectContent -replace "<Version>.*</Version>", "<Version>$version</Version>"
|
||||
Set-Content $projectFile $projectContent
|
||||
|
||||
# Update the version in the module manifest files
|
||||
$sourcePsd1 = "src\PSOPNSenseAPI\PSOPNSenseAPI.psd1"
|
||||
$sourcePsd1Content = Get-Content $sourcePsd1
|
||||
$sourcePsd1Content = $sourcePsd1Content -replace "ModuleVersion = '.*'", "ModuleVersion = '$version'"
|
||||
Set-Content $sourcePsd1 $sourcePsd1Content
|
||||
|
||||
$outputPsd1 = "output\PSOPNSenseAPI\PSOPNSenseAPI.psd1"
|
||||
$outputPsd1Content = Get-Content $outputPsd1
|
||||
$outputPsd1Content = $outputPsd1Content -replace "ModuleVersion = '.*'", "ModuleVersion = '$version'"
|
||||
Set-Content $outputPsd1 $outputPsd1Content
|
||||
|
||||
# Build the project
|
||||
dotnet build -c Release
|
||||
|
||||
# Copy the DLLs to the output folder
|
||||
$libPath = "output\PSOPNSenseAPI\lib-new"
|
||||
New-Item -Path $libPath -ItemType Directory -Force | Out-Null
|
||||
Copy-Item -Path "src\PSOPNSenseAPI\bin\Release\net472\*.dll" -Destination $libPath
|
||||
Remove-Item -Path "output\PSOPNSenseAPI\lib" -Recurse -Force -ErrorAction SilentlyContinue
|
||||
Rename-Item -Path $libPath -NewName "lib"
|
||||
|
||||
# Create the PSM1 file
|
||||
$psm1Path = "output\PSOPNSenseAPI\PSOPNSenseAPI.psm1"
|
||||
$psm1Content = @"
|
||||
# Load assemblies from the lib folder using System.Reflection.Assembly::LoadBytes
|
||||
# This avoids file lock issues when the module is loaded
|
||||
|
||||
`$libPath = Join-Path `$PSScriptRoot "lib"
|
||||
`$dllFiles = Get-ChildItem -Path `$libPath -Filter "*.dll"
|
||||
|
||||
foreach (`$dll in `$dllFiles) {
|
||||
try {
|
||||
Write-Verbose "Attempting to load assembly: `$(`$dll.FullName)"
|
||||
`$dllBytes = [System.IO.File]::ReadAllBytes(`$dll.FullName)
|
||||
`$Null = [System.Reflection.Assembly]::Load(`$dllBytes)
|
||||
Write-Verbose "Successfully loaded assembly: `$(`$dll.FullName)"
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to load assembly `$(`$dll.Name): `$_"
|
||||
}
|
||||
}
|
||||
|
||||
# PowerShell will automatically export the cmdlets based on the [Cmdlet] attribute
|
||||
"@
|
||||
Set-Content -Path $psm1Path -Value $psm1Content
|
||||
|
||||
# Test the module import
|
||||
Write-Host "Testing module import..."
|
||||
try {
|
||||
Import-Module "$PSScriptRoot\..\output\PSOPNSenseAPI\PSOPNSenseAPI.psd1" -Force -Verbose
|
||||
$cmdlets = Get-Command -Module PSOPNSenseAPI
|
||||
Write-Host "Successfully imported module with $($cmdlets.Count) cmdlets"
|
||||
Remove-Module PSOPNSenseAPI -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
catch {
|
||||
Write-Error "Failed to import module: $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Create a release archive
|
||||
$zipFile = "output\PSOPNSenseAPI-$version.zip"
|
||||
Compress-Archive -Path "output\PSOPNSenseAPI\*" -DestinationPath $zipFile -Force
|
||||
|
||||
# Clean up old zip files
|
||||
Get-ChildItem -Path "output" -Filter "*.zip" |
|
||||
Where-Object { $_.Name -ne "PSOPNSenseAPI-$version.zip" } |
|
||||
Remove-Item -Force
|
||||
|
||||
# Commit the changes
|
||||
git add .
|
||||
git commit -m "Update version to $version"
|
||||
git push origin main
|
||||
|
||||
# Create a GitHub release
|
||||
Write-Host "To create a GitHub release, go to https://github.com/freedbygrace/PSOPNSenseAPI/releases/new"
|
||||
Write-Host "Tag version: v$version"
|
||||
Write-Host "Release title: v$version"
|
||||
Write-Host "Description: See CHANGELOG.md for details"
|
||||
Write-Host "Attach the file: $zipFile"
|
||||
|
||||
# Create a release note file
|
||||
$releaseNotes = @"
|
||||
# Release v$version
|
||||
|
||||
## What's New
|
||||
|
||||
See [CHANGELOG.md](CHANGELOG.md) for details.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Download the release from the GitHub releases page: https://github.com/freedbygrace/PSOPNSenseAPI/releases/tag/v$version
|
||||
2. Extract the zip file to a folder in your PowerShell module path
|
||||
3. Import the module: `Import-Module PSOPNSenseAPI`
|
||||
|
||||
## Usage
|
||||
|
||||
```powershell
|
||||
# Connect to the OPNSense firewall
|
||||
Connect-OPNSense -Server "https://firewall.example.com" -ApiKey "your_api_key" -ApiSecret "your_api_secret" -SkipCertificateCheck
|
||||
|
||||
# Get the interfaces
|
||||
Get-OPNSenseInterface
|
||||
|
||||
# Disconnect from the firewall
|
||||
Disconnect-OPNSense
|
||||
```
|
||||
|
||||
For more examples, see the documentation in the `docs` folder.
|
||||
"@
|
||||
|
||||
Set-Content -Path "RELEASE.md" -Value $releaseNotes
|
||||
|
||||
# Commit the release notes
|
||||
git add RELEASE.md
|
||||
git commit -m "Add release notes for v$version"
|
||||
git push origin main
|
||||
|
||||
Write-Host "Release created successfully!"
|
||||
@@ -1,53 +0,0 @@
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using System.Threading.Tasks;
|
||||
using PSOPNSenseAPI.Services;
|
||||
|
||||
namespace PSOPNSenseAPI.Cmdlets
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="synopsis">Creates a backup of the OPNSense firewall configuration.</para>
|
||||
/// <para type="description">The Backup-OPNSenseConfig cmdlet creates a backup of the OPNSense firewall configuration.</para>
|
||||
/// <example>
|
||||
/// <para>Example 1: Create a backup</para>
|
||||
/// <code>Backup-OPNSenseConfig</code>
|
||||
/// <para>This example creates a backup of the OPNSense firewall configuration with an automatically generated filename.</para>
|
||||
/// </example>
|
||||
/// <example>
|
||||
/// <para>Example 2: Create a backup with a specific filename</para>
|
||||
/// <code>Backup-OPNSenseConfig -Filename "pre-upgrade-backup"</code>
|
||||
/// <para>This example creates a backup of the OPNSense firewall configuration with a specific filename.</para>
|
||||
/// </example>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsData.Backup, "OPNSenseConfig")]
|
||||
[OutputType(typeof(string))]
|
||||
public class BackupOPNSenseConfigCmdlet : OPNSenseBaseCmdlet
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="description">The filename for the backup.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false, Position = 0)]
|
||||
public string Filename { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Processes the cmdlet
|
||||
/// </summary>
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var configService = new ConfigService(ApiClient, Logger);
|
||||
|
||||
var task = Task.Run(async () => await configService.CreateConfigBackupAsync(Filename));
|
||||
var result = task.GetAwaiter().GetResult();
|
||||
|
||||
WriteVerbose($"Created configuration backup: {result.Filename}");
|
||||
WriteObject(result.Filename);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,8 +23,8 @@ namespace PSOPNSenseAPI.Cmdlets
|
||||
/// <para type="description">The path to save the configuration file.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string Path { get; set; }
|
||||
[ValidateNotNull]
|
||||
public FileInfo Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Overwrites the file if it exists.</para>
|
||||
@@ -39,33 +39,35 @@ namespace PSOPNSenseAPI.Cmdlets
|
||||
{
|
||||
try
|
||||
{
|
||||
string fullPath = Path.FullName;
|
||||
|
||||
// Check if the file exists
|
||||
if (File.Exists(Path) && !Force.IsPresent)
|
||||
if (File.Exists(fullPath) && !Force.IsPresent)
|
||||
{
|
||||
WriteError(new ErrorRecord(
|
||||
new IOException($"The file '{Path}' already exists. Use -Force to overwrite."),
|
||||
new IOException($"The file '{fullPath}' already exists. Use -Force to overwrite."),
|
||||
"FileExists",
|
||||
ErrorCategory.ResourceExists,
|
||||
Path));
|
||||
fullPath));
|
||||
return;
|
||||
}
|
||||
|
||||
var configService = new ConfigService(ApiClient, Logger);
|
||||
|
||||
var task = Task.Run(async () => await configService.ExportConfigAsync());
|
||||
var configContent = task.GetAwaiter().GetResult();
|
||||
// Execute the async method synchronously on the main thread
|
||||
var configContent = configService.ExportConfigAsync().GetAwaiter().GetResult();
|
||||
|
||||
// Create the directory if it doesn't exist
|
||||
var directory = System.IO.Path.GetDirectoryName(Path);
|
||||
var directory = System.IO.Path.GetDirectoryName(fullPath);
|
||||
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
// Write the configuration to the file
|
||||
File.WriteAllBytes(Path, configContent);
|
||||
File.WriteAllBytes(fullPath, configContent);
|
||||
|
||||
WriteVerbose($"Exported configuration to {Path}");
|
||||
WriteVerbose($"Exported configuration to {fullPath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Management.Automation;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using PSOPNSenseAPI.Services;
|
||||
|
||||
namespace PSOPNSenseAPI.Cmdlets
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="synopsis">Gets the OPNSense firewall configuration as an XML document.</para>
|
||||
/// <para type="description">The Get-OPNSenseConfig cmdlet retrieves the OPNSense firewall configuration and returns it as an XML document.</para>
|
||||
/// <example>
|
||||
/// <para>Example 1: Get the configuration as an XML document</para>
|
||||
/// <code>$config = Get-OPNSenseConfig</code>
|
||||
/// <para>This example retrieves the OPNSense firewall configuration as an XML document.</para>
|
||||
/// </example>
|
||||
/// <example>
|
||||
/// <para>Example 2: Get the configuration and pipe it to Restore-OPNSenseConfig</para>
|
||||
/// <code>Get-OPNSenseConfig | Restore-OPNSenseConfig</code>
|
||||
/// <para>This example retrieves the OPNSense firewall configuration and restores it.</para>
|
||||
/// </example>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Get, "OPNSenseConfig")]
|
||||
[OutputType(typeof(XmlDocument))]
|
||||
public class GetOPNSenseConfigCmdlet : OPNSenseBaseCmdlet
|
||||
{
|
||||
/// <summary>
|
||||
/// Processes the cmdlet
|
||||
/// </summary>
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var configService = new ConfigService(ApiClient, Logger);
|
||||
|
||||
// Execute the async method synchronously on the main thread
|
||||
var configContent = configService.ExportConfigAsync().GetAwaiter().GetResult();
|
||||
|
||||
// Convert the byte array to an XML document
|
||||
var xmlDoc = new XmlDocument();
|
||||
using (var memoryStream = new MemoryStream(configContent))
|
||||
{
|
||||
xmlDoc.Load(memoryStream);
|
||||
}
|
||||
|
||||
WriteVerbose("Retrieved OPNSense configuration as XML document");
|
||||
WriteObject(xmlDoc);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HandleException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,8 +23,8 @@ namespace PSOPNSenseAPI.Cmdlets
|
||||
/// <para type="description">The path to the configuration file.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string Path { get; set; }
|
||||
[ValidateNotNull]
|
||||
public FileInfo Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Suppresses the confirmation prompt.</para>
|
||||
@@ -39,18 +39,20 @@ namespace PSOPNSenseAPI.Cmdlets
|
||||
{
|
||||
try
|
||||
{
|
||||
string fullPath = Path.FullName;
|
||||
|
||||
// Check if the file exists
|
||||
if (!File.Exists(Path))
|
||||
if (!File.Exists(fullPath))
|
||||
{
|
||||
WriteError(new ErrorRecord(
|
||||
new FileNotFoundException($"The file '{Path}' does not exist."),
|
||||
new FileNotFoundException($"The file '{fullPath}' does not exist."),
|
||||
"FileNotFound",
|
||||
ErrorCategory.ObjectNotFound,
|
||||
Path));
|
||||
fullPath));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Force.IsPresent && !ShouldProcess(Path, "Import configuration"))
|
||||
if (!Force.IsPresent && !ShouldProcess(fullPath, "Import configuration"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -58,12 +60,12 @@ namespace PSOPNSenseAPI.Cmdlets
|
||||
var configService = new ConfigService(ApiClient, Logger);
|
||||
|
||||
// Read the configuration file
|
||||
var configContent = File.ReadAllBytes(Path);
|
||||
var configContent = File.ReadAllBytes(fullPath);
|
||||
|
||||
var task = Task.Run(async () => await configService.ImportConfigAsync(configContent));
|
||||
var result = task.GetAwaiter().GetResult();
|
||||
// Execute the async method synchronously on the main thread
|
||||
var result = configService.ImportConfigAsync(configContent).GetAwaiter().GetResult();
|
||||
|
||||
WriteVerbose($"Imported configuration from {Path}: {result.Status}");
|
||||
WriteVerbose($"Imported configuration from {fullPath}: {result.Status}");
|
||||
WriteWarning("The firewall is restarting. You may need to reconnect after it comes back online.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -1,18 +1,30 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Management.Automation;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using PSOPNSenseAPI.Services;
|
||||
|
||||
namespace PSOPNSenseAPI.Cmdlets
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="synopsis">Restores an OPNSense firewall configuration from a backup.</para>
|
||||
/// <para type="description">The Restore-OPNSenseConfig cmdlet restores an OPNSense firewall configuration from a backup.</para>
|
||||
/// <para type="synopsis">Restores an OPNSense firewall configuration.</para>
|
||||
/// <para type="description">The Restore-OPNSenseConfig cmdlet restores an OPNSense firewall configuration from a backup or an XML document.</para>
|
||||
/// <example>
|
||||
/// <para>Example 1: Restore a configuration backup</para>
|
||||
/// <code>Restore-OPNSenseConfig -Filename "config-backup-20250414-1234.xml"</code>
|
||||
/// <para>This example restores an OPNSense firewall configuration from a backup file.</para>
|
||||
/// </example>
|
||||
/// <example>
|
||||
/// <para>Example 2: Restore a configuration from an XML document</para>
|
||||
/// <code>$config = Get-OPNSenseConfig; Restore-OPNSenseConfig -XmlDocument $config</code>
|
||||
/// <para>This example restores an OPNSense firewall configuration from an XML document.</para>
|
||||
/// </example>
|
||||
/// <example>
|
||||
/// <para>Example 3: Restore a configuration from the pipeline</para>
|
||||
/// <code>Get-OPNSenseConfig | Restore-OPNSenseConfig</code>
|
||||
/// <para>This example restores an OPNSense firewall configuration from the pipeline.</para>
|
||||
/// </example>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsData.Restore, "OPNSenseConfig", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)]
|
||||
[OutputType(typeof(void))]
|
||||
@@ -21,10 +33,17 @@ namespace PSOPNSenseAPI.Cmdlets
|
||||
/// <summary>
|
||||
/// <para type="description">The filename of the backup to restore.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, ParameterSetName = "Filename")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string Filename { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The XML document containing the configuration to restore.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, Position = 0, ParameterSetName = "XmlDocument", ValueFromPipeline = true)]
|
||||
[ValidateNotNull]
|
||||
public XmlDocument XmlDocument { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Suppresses the confirmation prompt.</para>
|
||||
/// </summary>
|
||||
@@ -38,17 +57,36 @@ namespace PSOPNSenseAPI.Cmdlets
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Force.IsPresent && !ShouldProcess(Filename, "Restore configuration backup"))
|
||||
var configService = new ConfigService(ApiClient, Logger);
|
||||
string actionDescription = "Restore configuration";
|
||||
string targetName = ParameterSetName == "Filename" ? Filename : "from XML document";
|
||||
|
||||
if (!Force.IsPresent && !ShouldProcess(targetName, actionDescription))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var configService = new ConfigService(ApiClient, Logger);
|
||||
if (ParameterSetName == "Filename")
|
||||
{
|
||||
// Restore from backup file - execute synchronously on the main thread
|
||||
var result = configService.RestoreConfigBackupAsync(Filename).GetAwaiter().GetResult();
|
||||
WriteVerbose($"Restored configuration from backup: {result.Status}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Restore from XML document
|
||||
byte[] configContent;
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
XmlDocument.Save(memoryStream);
|
||||
configContent = memoryStream.ToArray();
|
||||
}
|
||||
|
||||
var task = Task.Run(async () => await configService.RestoreConfigBackupAsync(Filename));
|
||||
var result = task.GetAwaiter().GetResult();
|
||||
// Execute synchronously on the main thread
|
||||
var result = configService.ImportConfigAsync(configContent).GetAwaiter().GetResult();
|
||||
WriteVerbose($"Restored configuration from XML document: {result.Status}");
|
||||
}
|
||||
|
||||
WriteVerbose($"Restored configuration backup: {result.Status}");
|
||||
WriteWarning("The firewall is restarting. You may need to reconnect after it comes back online.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using PSOPNSenseAPI.Services;
|
||||
@@ -20,7 +21,7 @@ namespace PSOPNSenseAPI.Cmdlets
|
||||
/// <para>This example upgrades the firmware on the OPNSense firewall and waits for the upgrade to complete.</para>
|
||||
/// </example>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsData.Update, "OPNSenseFirmware", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)]
|
||||
[Cmdlet(VerbsLifecycle.Start, "OPNSenseFirmwareUpgrade", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)]
|
||||
[OutputType(typeof(void))]
|
||||
public class UpgradeOPNSenseFirmwareCmdlet : OPNSenseBaseCmdlet
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFrameworks>netstandard2.0;net472</TargetFrameworks>
|
||||
<AssemblyName>PSOPNSenseAPI</AssemblyName>
|
||||
<RootNamespace>PSOPNSenseAPI</RootNamespace>
|
||||
<Version>2025.04.14.2306</Version>
|
||||
<Version>2025.04.14.2340</Version>
|
||||
<Authors>PSOPNSenseAPI Contributors</Authors>
|
||||
<Company>PSOPNSenseAPI</Company>
|
||||
<Description>PowerShell module for interacting with the OPNSense API to configure firewalls</Description>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
@{
|
||||
# Script module or binary module file associated with this manifest.
|
||||
RootModule = 'PSOPNSenseAPI.psm1'
|
||||
RootModule = 'lib\PSOPNSenseAPI.dll'
|
||||
|
||||
# Version number of this module.
|
||||
ModuleVersion = '2025.04.14.2306'
|
||||
ModuleVersion = '2025.04.15.1143'
|
||||
|
||||
# Supported PSEditions
|
||||
CompatiblePSEditions = @('Desktop', 'Core')
|
||||
@@ -33,7 +33,7 @@
|
||||
# PowerShellHostVersion = ''
|
||||
|
||||
# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||
DotNetFrameworkVersion = '4.7.2'
|
||||
# DotNetFrameworkVersion = '4.7.2'
|
||||
|
||||
# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||
ClrVersion = '4.0'
|
||||
@@ -64,127 +64,101 @@
|
||||
|
||||
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
|
||||
CmdletsToExport = @(
|
||||
# Connection
|
||||
'Connect-OPNSense',
|
||||
'Disconnect-OPNSense',
|
||||
|
||||
# Firewall Rules
|
||||
'Get-OPNSenseFirewallRule',
|
||||
'New-OPNSenseFirewallRule',
|
||||
'Set-OPNSenseFirewallRule',
|
||||
'Remove-OPNSenseFirewallRule',
|
||||
'Enable-OPNSenseFirewallRule',
|
||||
'Disable-OPNSenseFirewallRule',
|
||||
'Apply-OPNSenseFirewallChanges',
|
||||
|
||||
# Aliases
|
||||
'Get-OPNSenseAlias',
|
||||
'New-OPNSenseAlias',
|
||||
'Set-OPNSenseAlias',
|
||||
'Remove-OPNSenseAlias',
|
||||
|
||||
# Interfaces
|
||||
'Get-OPNSenseInterface',
|
||||
'Set-OPNSenseInterface',
|
||||
'Get-OPNSenseVLAN',
|
||||
'New-OPNSenseVLAN',
|
||||
'Remove-OPNSenseVLAN',
|
||||
'New-OPNSenseSubnetVLANs',
|
||||
|
||||
# DNS
|
||||
'Get-OPNSenseDNSServer',
|
||||
'Set-OPNSenseDNSServer',
|
||||
'Get-OPNSenseDNSOverride',
|
||||
'New-OPNSenseDNSOverride',
|
||||
'Remove-OPNSenseDNSOverride',
|
||||
'Get-OPNSenseDNSForwarding',
|
||||
'Set-OPNSenseDNSForwarding',
|
||||
'Get-OPNSenseDNSForwardingHost',
|
||||
'New-OPNSenseDNSForwardingHost',
|
||||
'Set-OPNSenseDNSForwardingHost',
|
||||
'Remove-OPNSenseDNSForwardingHost',
|
||||
'Get-OPNSenseSystemDNS',
|
||||
'Set-OPNSenseSystemDNS',
|
||||
|
||||
# Configuration
|
||||
'Backup-OPNSenseConfig',
|
||||
'Restore-OPNSenseConfig',
|
||||
'Export-OPNSenseConfig',
|
||||
'Import-OPNSenseConfig',
|
||||
|
||||
# Plugins
|
||||
'Get-OPNSensePlugin',
|
||||
'Install-OPNSensePlugin',
|
||||
'Uninstall-OPNSensePlugin',
|
||||
'Enable-OPNSensePlugin',
|
||||
'Disable-OPNSensePlugin',
|
||||
|
||||
# Users
|
||||
'Get-OPNSenseUser',
|
||||
'New-OPNSenseUser',
|
||||
'Set-OPNSenseUser',
|
||||
'Remove-OPNSenseUser',
|
||||
|
||||
# Firmware
|
||||
'Get-OPNSenseFirmware',
|
||||
'Update-OPNSenseFirmware',
|
||||
'Upgrade-OPNSenseFirmware',
|
||||
|
||||
# System
|
||||
'Restart-OPNSenseFirewall',
|
||||
|
||||
# DHCP
|
||||
'Get-OPNSenseDHCPServer',
|
||||
'Set-OPNSenseDHCPServer',
|
||||
'Get-OPNSenseDHCPLease',
|
||||
'Remove-OPNSenseDHCPLease',
|
||||
'Get-OPNSenseDHCPStaticMapping',
|
||||
'New-OPNSenseDHCPStaticMapping',
|
||||
'Set-OPNSenseDHCPStaticMapping',
|
||||
'Remove-OPNSenseDHCPStaticMapping',
|
||||
'Get-OPNSenseDHCPOption',
|
||||
'New-OPNSenseDHCPOption',
|
||||
'Set-OPNSenseDHCPOption',
|
||||
'Remove-OPNSenseDHCPOption',
|
||||
|
||||
# Cron
|
||||
'Get-OPNSenseCronJob',
|
||||
'New-OPNSenseCronJob',
|
||||
'Set-OPNSenseCronJob',
|
||||
'Remove-OPNSenseCronJob',
|
||||
'Enable-OPNSenseCronJob',
|
||||
'Disable-OPNSenseCronJob',
|
||||
|
||||
# Tailscale
|
||||
'Get-OPNSenseTailscaleStatus',
|
||||
'Enable-OPNSenseTailscale',
|
||||
'Disable-OPNSenseTailscale',
|
||||
'Connect-OPNSense',
|
||||
'Connect-OPNSenseTailscale',
|
||||
'Disconnect-OPNSenseTailscale',
|
||||
|
||||
# Network Utilities
|
||||
'Invoke-OPNSenseNetworkCalculation',
|
||||
'ConvertTo-OPNSenseNetworkNotation',
|
||||
|
||||
# Gateways and Routes
|
||||
'Disable-OPNSenseCronJob',
|
||||
'Disable-OPNSenseFirewallRule',
|
||||
'Disable-OPNSensePlugin',
|
||||
'Disable-OPNSenseTailscale',
|
||||
'Disconnect-OPNSense',
|
||||
'Disconnect-OPNSenseTailscale',
|
||||
'Enable-OPNSenseCronJob',
|
||||
'Enable-OPNSenseFirewallRule',
|
||||
'Enable-OPNSensePlugin',
|
||||
'Enable-OPNSenseTailscale',
|
||||
'Export-OPNSenseConfig',
|
||||
'Get-OPNSenseAlias',
|
||||
'Get-OPNSenseConfig',
|
||||
'Get-OPNSenseConfigBackup',
|
||||
'Get-OPNSenseConnection',
|
||||
'Get-OPNSenseCronJob',
|
||||
'Get-OPNSenseDHCPLease',
|
||||
'Get-OPNSenseDHCPOption',
|
||||
'Get-OPNSenseDHCPServer',
|
||||
'Get-OPNSenseDHCPStaticMapping',
|
||||
'Get-OPNSenseDNSForwarding',
|
||||
'Get-OPNSenseDNSForwardingHost',
|
||||
'Get-OPNSenseDNSOverride',
|
||||
'Get-OPNSenseDNSServer',
|
||||
'Get-OPNSenseFirewallRule',
|
||||
'Get-OPNSenseFirmware',
|
||||
'Get-OPNSenseGateway',
|
||||
'New-OPNSenseGateway',
|
||||
'Set-OPNSenseGateway',
|
||||
'Remove-OPNSenseGateway',
|
||||
'Get-OPNSenseRoute',
|
||||
'New-OPNSenseRoute',
|
||||
'Set-OPNSenseRoute',
|
||||
'Remove-OPNSenseRoute',
|
||||
|
||||
# Port Forwarding
|
||||
'Get-OPNSenseInterface',
|
||||
'Get-OPNSenseInterfaceStatistics',
|
||||
'Get-OPNSensePlugin',
|
||||
'Get-OPNSensePortForwardingRule',
|
||||
'Get-OPNSenseRoute',
|
||||
'Get-OPNSenseSystemDNS',
|
||||
'Get-OPNSenseTailscaleStatus',
|
||||
'Get-OPNSenseUser',
|
||||
'Get-OPNSenseVLAN',
|
||||
'Import-OPNSenseConfig',
|
||||
'Install-OPNSensePlugin',
|
||||
'Invoke-OPNSenseNetworkCalculation',
|
||||
'New-OPNSenseAlias',
|
||||
'New-OPNSenseCronJob',
|
||||
'New-OPNSenseDHCPOption',
|
||||
'New-OPNSenseDHCPStaticMapping',
|
||||
'New-OPNSenseDNSForwardingHost',
|
||||
'New-OPNSenseDNSOverride',
|
||||
'New-OPNSenseFirewallRule',
|
||||
'New-OPNSenseGateway',
|
||||
'New-OPNSensePortForwardingRule',
|
||||
'New-OPNSenseRoute',
|
||||
'New-OPNSenseSubnetVLANs',
|
||||
'New-OPNSenseUser',
|
||||
'New-OPNSenseVLAN',
|
||||
'Remove-OPNSenseAlias',
|
||||
'Remove-OPNSenseCronJob',
|
||||
'Remove-OPNSenseDHCPLease',
|
||||
'Remove-OPNSenseDHCPOption',
|
||||
'Remove-OPNSenseDHCPStaticMapping',
|
||||
'Remove-OPNSenseDNSForwardingHost',
|
||||
'Remove-OPNSenseDNSOverride',
|
||||
'Remove-OPNSenseFirewallRule',
|
||||
'Remove-OPNSenseGateway',
|
||||
'Remove-OPNSensePortForwardingRule',
|
||||
'Remove-OPNSenseRoute',
|
||||
'Remove-OPNSenseUser',
|
||||
'Remove-OPNSenseVLAN',
|
||||
'Restart-OPNSenseFirewall',
|
||||
'Restart-OPNSenseInterface',
|
||||
'Restore-OPNSenseConfig',
|
||||
'Set-OPNSenseAlias',
|
||||
'Set-OPNSenseCronJob',
|
||||
'Set-OPNSenseDHCPOption',
|
||||
'Set-OPNSenseDHCPServer',
|
||||
'Set-OPNSenseDHCPStaticMapping',
|
||||
'Set-OPNSenseDNSForwarding',
|
||||
'Set-OPNSenseDNSForwardingHost',
|
||||
'Set-OPNSenseDNSServer',
|
||||
'Set-OPNSenseFirewallRule',
|
||||
'Set-OPNSenseGateway',
|
||||
'Set-OPNSenseInterface',
|
||||
'Set-OPNSensePortForwardingRule',
|
||||
'Remove-OPNSensePortForwardingRule'
|
||||
'Set-OPNSenseRoute',
|
||||
'Set-OPNSenseSystemDNS',
|
||||
'Set-OPNSenseUser',
|
||||
'Set-OPNSenseVLAN',
|
||||
'Uninstall-OPNSensePlugin',
|
||||
'Update-OPNSenseFirmware',
|
||||
'Start-OPNSenseFirmwareUpgrade'
|
||||
)
|
||||
|
||||
# Variables to export from this module
|
||||
VariablesToExport = '*'
|
||||
VariablesToExport = @()
|
||||
|
||||
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
|
||||
AliasesToExport = @()
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using PSOPNSenseAPI.Cmdlets;
|
||||
using PSOPNSenseAPI.Services;
|
||||
using PSOPNSenseAPI.Logging;
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace PSOPNSenseAPI.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class FirmwareCmdletTests
|
||||
{
|
||||
private Mock<OPNSenseApiClient> _mockApiClient;
|
||||
private Mock<ILogger> _mockLogger;
|
||||
|
||||
[TestInitialize]
|
||||
public void Setup()
|
||||
{
|
||||
_mockApiClient = new Mock<OPNSenseApiClient>("https://example.com", "key", "secret", false, Mock.Of<ILogger>());
|
||||
_mockLogger = new Mock<ILogger>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void UpdateOPNSenseFirmwareCmdlet_ProcessRecord_CallsUpdateAsync()
|
||||
{
|
||||
// Arrange
|
||||
_mockApiClient.Setup(c => c.PostAsync<dynamic>("core/firmware/update", It.IsAny<object>()))
|
||||
.ReturnsAsync(new { status = "ok" });
|
||||
|
||||
// Create and configure the cmdlet
|
||||
var cmdlet = new UpdateOPNSenseFirmwareCmdlet();
|
||||
|
||||
// Use reflection to set the protected properties
|
||||
SetProtectedProperty(cmdlet, "ApiClient", _mockApiClient.Object);
|
||||
SetProtectedProperty(cmdlet, "Logger", _mockLogger.Object);
|
||||
|
||||
// Act
|
||||
InvokeMethod(cmdlet, "ProcessRecord");
|
||||
|
||||
// Assert
|
||||
_mockApiClient.Verify(c => c.PostAsync<dynamic>("core/firmware/update", It.IsAny<object>()), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void StartOPNSenseFirmwareUpgradeCmdlet_ProcessRecord_CallsUpgradeAsync()
|
||||
{
|
||||
// Arrange
|
||||
_mockApiClient.Setup(c => c.PostAsync<dynamic>("core/firmware/upgrade", It.IsAny<object>()))
|
||||
.ReturnsAsync(new { status = "ok" });
|
||||
|
||||
// Create and configure the cmdlet
|
||||
var cmdlet = new UpgradeOPNSenseFirmwareCmdlet();
|
||||
|
||||
// Use reflection to set the protected properties
|
||||
SetProtectedProperty(cmdlet, "ApiClient", _mockApiClient.Object);
|
||||
SetProtectedProperty(cmdlet, "Logger", _mockLogger.Object);
|
||||
|
||||
// Set Force parameter to skip confirmation
|
||||
typeof(UpgradeOPNSenseFirmwareCmdlet).GetProperty("Force").SetValue(cmdlet, new SwitchParameter(true));
|
||||
|
||||
// Act
|
||||
InvokeMethod(cmdlet, "ProcessRecord");
|
||||
|
||||
// Assert
|
||||
_mockApiClient.Verify(c => c.PostAsync<dynamic>("core/firmware/upgrade", It.IsAny<object>()), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetOPNSenseFirmwareCmdlet_ProcessRecord_CallsGetStatusAsync()
|
||||
{
|
||||
// Arrange
|
||||
_mockApiClient.Setup(c => c.GetAsync<dynamic>("core/firmware/status"))
|
||||
.ReturnsAsync(new { status = "ok" });
|
||||
|
||||
// Create and configure the cmdlet
|
||||
var cmdlet = new GetOPNSenseFirmwareCmdlet();
|
||||
|
||||
// Use reflection to set the protected properties
|
||||
SetProtectedProperty(cmdlet, "ApiClient", _mockApiClient.Object);
|
||||
SetProtectedProperty(cmdlet, "Logger", _mockLogger.Object);
|
||||
|
||||
// Act
|
||||
InvokeMethod(cmdlet, "ProcessRecord");
|
||||
|
||||
// Assert
|
||||
_mockApiClient.Verify(c => c.GetAsync<dynamic>("core/firmware/status"), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetOPNSenseFirmwareCmdlet_WithChangelog_CallsGetChangelogAsync()
|
||||
{
|
||||
// Arrange
|
||||
_mockApiClient.Setup(c => c.GetAsync<dynamic>("core/firmware/changelog"))
|
||||
.ReturnsAsync(new { changelog = "Changes in version X.Y.Z" });
|
||||
|
||||
// Create and configure the cmdlet
|
||||
var cmdlet = new GetOPNSenseFirmwareCmdlet();
|
||||
|
||||
// Use reflection to set the protected properties
|
||||
SetProtectedProperty(cmdlet, "ApiClient", _mockApiClient.Object);
|
||||
SetProtectedProperty(cmdlet, "Logger", _mockLogger.Object);
|
||||
|
||||
// Set Changelog parameter
|
||||
typeof(GetOPNSenseFirmwareCmdlet).GetProperty("Changelog").SetValue(cmdlet, new SwitchParameter(true));
|
||||
|
||||
// Act
|
||||
InvokeMethod(cmdlet, "ProcessRecord");
|
||||
|
||||
// Assert
|
||||
_mockApiClient.Verify(c => c.GetAsync<dynamic>("core/firmware/changelog"), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetOPNSenseFirmwareCmdlet_WithAudit_CallsGetAuditAsync()
|
||||
{
|
||||
// Arrange
|
||||
_mockApiClient.Setup(c => c.GetAsync<dynamic>("core/firmware/audit"))
|
||||
.ReturnsAsync(new { audit = new[] { new { name = "package1", version = "1.0.0" } } });
|
||||
|
||||
// Create and configure the cmdlet
|
||||
var cmdlet = new GetOPNSenseFirmwareCmdlet();
|
||||
|
||||
// Use reflection to set the protected properties
|
||||
SetProtectedProperty(cmdlet, "ApiClient", _mockApiClient.Object);
|
||||
SetProtectedProperty(cmdlet, "Logger", _mockLogger.Object);
|
||||
|
||||
// Set Audit parameter
|
||||
typeof(GetOPNSenseFirmwareCmdlet).GetProperty("Audit").SetValue(cmdlet, new SwitchParameter(true));
|
||||
|
||||
// Act
|
||||
InvokeMethod(cmdlet, "ProcessRecord");
|
||||
|
||||
// Assert
|
||||
_mockApiClient.Verify(c => c.GetAsync<dynamic>("core/firmware/audit"), Times.Once);
|
||||
}
|
||||
|
||||
private void SetProtectedProperty(object obj, string propertyName, object value)
|
||||
{
|
||||
var propertyInfo = obj.GetType().BaseType.GetProperty(
|
||||
propertyName,
|
||||
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
|
||||
if (propertyInfo == null)
|
||||
{
|
||||
throw new ArgumentException($"Property {propertyName} not found on {obj.GetType().FullName}");
|
||||
}
|
||||
|
||||
var backingField = obj.GetType().BaseType.GetField(
|
||||
$"<{propertyName}>k__BackingField",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
if (backingField != null)
|
||||
{
|
||||
backingField.SetValue(obj, value);
|
||||
}
|
||||
else if (propertyInfo.CanWrite)
|
||||
{
|
||||
propertyInfo.SetValue(obj, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Cannot set property {propertyName} on {obj.GetType().FullName}");
|
||||
}
|
||||
}
|
||||
|
||||
private void InvokeMethod(object obj, string methodName)
|
||||
{
|
||||
var methodInfo = obj.GetType().GetMethod(
|
||||
methodName,
|
||||
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
|
||||
if (methodInfo == null)
|
||||
{
|
||||
throw new ArgumentException($"Method {methodName} not found on {obj.GetType().FullName}");
|
||||
}
|
||||
|
||||
methodInfo.Invoke(obj, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using PSOPNSenseAPI.Cmdlets;
|
||||
using PSOPNSenseAPI.Services;
|
||||
using PSOPNSenseAPI.Logging;
|
||||
using System.Threading.Tasks;
|
||||
using System.Management.Automation;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace PSOPNSenseAPI.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class FirmwareServiceTests
|
||||
{
|
||||
private Mock<OPNSenseApiClient> _mockApiClient;
|
||||
private Mock<ILogger> _mockLogger;
|
||||
private FirmwareService _firmwareService;
|
||||
|
||||
[TestInitialize]
|
||||
public void Setup()
|
||||
{
|
||||
_mockApiClient = new Mock<OPNSenseApiClient>("https://example.com", "key", "secret", false, Mock.Of<ILogger>());
|
||||
_mockLogger = new Mock<ILogger>();
|
||||
_firmwareService = new FirmwareService(_mockApiClient.Object, _mockLogger.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task GetStatusAsync_ReturnsStatus()
|
||||
{
|
||||
// Arrange
|
||||
var expectedResponse = new { status = "ok" };
|
||||
_mockApiClient.Setup(c => c.GetAsync<dynamic>("core/firmware/status"))
|
||||
.ReturnsAsync(expectedResponse);
|
||||
|
||||
// Act
|
||||
var result = await _firmwareService.GetStatusAsync();
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual("ok", result.Status);
|
||||
_mockApiClient.Verify(c => c.GetAsync<dynamic>("core/firmware/status"), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task UpdateAsync_CallsCorrectEndpoint()
|
||||
{
|
||||
// Arrange
|
||||
var expectedResponse = new { status = "ok" };
|
||||
_mockApiClient.Setup(c => c.PostAsync<dynamic>("core/firmware/update", It.IsAny<object>()))
|
||||
.ReturnsAsync(expectedResponse);
|
||||
|
||||
// Act
|
||||
var result = await _firmwareService.UpdateAsync();
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual("ok", result.Status);
|
||||
_mockApiClient.Verify(c => c.PostAsync<dynamic>("core/firmware/update", It.IsAny<object>()), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task UpgradeAsync_CallsCorrectEndpoint()
|
||||
{
|
||||
// Arrange
|
||||
var expectedResponse = new { status = "ok" };
|
||||
_mockApiClient.Setup(c => c.PostAsync<dynamic>("core/firmware/upgrade", It.IsAny<object>()))
|
||||
.ReturnsAsync(expectedResponse);
|
||||
|
||||
// Act
|
||||
var result = await _firmwareService.UpgradeAsync();
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual("ok", result.Status);
|
||||
_mockApiClient.Verify(c => c.PostAsync<dynamic>("core/firmware/upgrade", It.IsAny<object>()), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task GetChangelogAsync_ReturnsChangelog()
|
||||
{
|
||||
// Arrange
|
||||
var expectedResponse = new { changelog = "Changes in version X.Y.Z" };
|
||||
_mockApiClient.Setup(c => c.GetAsync<dynamic>("core/firmware/changelog"))
|
||||
.ReturnsAsync(expectedResponse);
|
||||
|
||||
// Act
|
||||
var result = await _firmwareService.GetChangelogAsync();
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual("Changes in version X.Y.Z", result.Changelog);
|
||||
_mockApiClient.Verify(c => c.GetAsync<dynamic>("core/firmware/changelog"), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task GetHealthAsync_ReturnsHealth()
|
||||
{
|
||||
// Arrange
|
||||
var expectedResponse = new { health = "healthy" };
|
||||
_mockApiClient.Setup(c => c.GetAsync<dynamic>("core/firmware/health"))
|
||||
.ReturnsAsync(expectedResponse);
|
||||
|
||||
// Act
|
||||
var result = await _firmwareService.GetHealthAsync();
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual("healthy", result.Health);
|
||||
_mockApiClient.Verify(c => c.GetAsync<dynamic>("core/firmware/health"), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task GetAuditAsync_ReturnsAudit()
|
||||
{
|
||||
// Arrange
|
||||
var expectedResponse = new { audit = new[] { new { name = "package1", version = "1.0.0" } } };
|
||||
_mockApiClient.Setup(c => c.GetAsync<dynamic>("core/firmware/audit"))
|
||||
.ReturnsAsync(expectedResponse);
|
||||
|
||||
// Act
|
||||
var result = await _firmwareService.GetAuditAsync();
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(result.Audit);
|
||||
_mockApiClient.Verify(c => c.GetAsync<dynamic>("core/firmware/audit"), Times.Once);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user