Public/Network/Set-VergeNetworkRule.ps1
|
function Set-VergeNetworkRule { <# .SYNOPSIS Modifies an existing firewall rule on a VergeOS virtual network. .DESCRIPTION Set-VergeNetworkRule modifies properties of an existing firewall rule. After modifying rules, use Invoke-VergeNetworkApply to apply the changes. .PARAMETER Network The name or key of the network containing the rule. .PARAMETER Name The name of the rule to modify. .PARAMETER Key The unique key (ID) of the rule to modify. .PARAMETER Rule A rule object from Get-VergeNetworkRule. Accepts pipeline input. .PARAMETER NewName A new name for the rule. .PARAMETER Description An updated description for the rule. .PARAMETER Direction The direction of traffic: Incoming or Outgoing. .PARAMETER Action The action to take: Accept, Drop, Reject, Translate, or Route. .PARAMETER Protocol The protocol to match: TCP, UDP, TCPUDP, ICMP, Any. .PARAMETER SourceIP Source IP filter. .PARAMETER SourcePorts Source ports or ranges. .PARAMETER DestinationIP Destination IP filter. .PARAMETER DestinationPorts Destination ports or ranges. .PARAMETER TargetIP Target IP for Translate/Route actions. .PARAMETER TargetPorts Target ports for port translation. .PARAMETER Interface The interface for the rule: Auto, Router, DMZ, WireGuard, Any. .PARAMETER Enabled Enable or disable the rule. .PARAMETER Log Enable or disable logging for this rule. .PARAMETER Statistics Enable or disable statistics tracking. .PARAMETER Apply Automatically apply rules after modification. .PARAMETER PassThru Return the modified rule object. .PARAMETER Server The VergeOS connection to use. .EXAMPLE Set-VergeNetworkRule -Network "External" -Name "Allow HTTPS" -Enabled $false Disables the "Allow HTTPS" rule. .EXAMPLE Set-VergeNetworkRule -Network "External" -Name "NAT to Web" -TargetIP "192.168.0.20" -Apply Updates the target IP and applies the changes immediately. .EXAMPLE Get-VergeNetworkRule -Network "External" -Name "Web*" | Set-VergeNetworkRule -Enabled $false Disables all rules starting with "Web" using pipeline. .OUTPUTS None by default. Verge.NetworkRule when -PassThru is specified. .NOTES Rule changes are not active until Invoke-VergeNetworkApply is called, or use -Apply. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium', DefaultParameterSetName = 'ByName')] [OutputType([PSCustomObject])] param( [Parameter(Mandatory, Position = 0, ParameterSetName = 'ByName')] [Parameter(Mandatory, Position = 0, ParameterSetName = 'ByKey')] [string]$Network, [Parameter(Mandatory, Position = 1, ParameterSetName = 'ByName')] [string]$Name, [Parameter(Mandatory, ParameterSetName = 'ByKey')] [int]$Key, [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'ByRule')] [PSTypeName('Verge.NetworkRule')] [PSCustomObject]$Rule, [Parameter()] [ValidateLength(1, 128)] [string]$NewName, [Parameter()] [string]$Description, [Parameter()] [ValidateSet('Incoming', 'Outgoing')] [string]$Direction, [Parameter()] [ValidateSet('Accept', 'Drop', 'Reject', 'Translate', 'Route')] [string]$Action, [Parameter()] [ValidateSet('TCP', 'UDP', 'TCPUDP', 'ICMP', 'Any')] [string]$Protocol, [Parameter()] [AllowEmptyString()] [string]$SourceIP, [Parameter()] [AllowEmptyString()] [string]$SourcePorts, [Parameter()] [AllowEmptyString()] [string]$DestinationIP, [Parameter()] [AllowEmptyString()] [string]$DestinationPorts, [Parameter()] [AllowEmptyString()] [string]$TargetIP, [Parameter()] [AllowEmptyString()] [string]$TargetPorts, [Parameter()] [ValidateSet('Auto', 'Router', 'DMZ', 'WireGuard', 'Any')] [string]$Interface, [Parameter()] [bool]$Enabled, [Parameter()] [bool]$Log, [Parameter()] [bool]$Statistics, [Parameter()] [switch]$Apply, [Parameter()] [switch]$PassThru, [Parameter()] [object]$Server ) begin { # Resolve connection if (-not $Server) { $Server = $script:DefaultConnection } if (-not $Server) { throw [System.InvalidOperationException]::new( 'Not connected to VergeOS. Use Connect-VergeOS to establish a connection.' ) } # Map friendly names to API values $directionMap = @{ 'Incoming' = 'incoming' 'Outgoing' = 'outgoing' } $actionMap = @{ 'Accept' = 'accept' 'Drop' = 'drop' 'Reject' = 'reject' 'Translate' = 'translate' 'Route' = 'route' } $protocolMap = @{ 'TCP' = 'tcp' 'UDP' = 'udp' 'TCPUDP' = 'tcpudp' 'ICMP' = 'icmp' 'Any' = 'any' } $interfaceMap = @{ 'Auto' = 'auto' 'Router' = 'router' 'DMZ' = 'dmz' 'WireGuard' = 'wireguard' 'Any' = 'any' } } process { # Get the rule to modify $targetRule = switch ($PSCmdlet.ParameterSetName) { 'ByName' { Get-VergeNetworkRule -Network $Network -Name $Name -Server $Server } 'ByKey' { Get-VergeNetworkRule -Network $Network -Key $Key -Server $Server } 'ByRule' { $Rule } } if (-not $targetRule) { Write-Error -Message "Rule not found" -ErrorId 'RuleNotFound' return } # Handle multiple matches if ($targetRule -is [array]) { Write-Error -Message "Multiple rules matched. Please specify a unique name or use -Key." -ErrorId 'MultipleRulesMatched' return } # Check for system rule if ($targetRule.SystemRule) { Write-Error -Message "Cannot modify system rule '$($targetRule.Name)'" -ErrorId 'CannotModifySystemRule' return } # Build the update body with only specified parameters $body = @{} if ($PSBoundParameters.ContainsKey('NewName')) { $body['name'] = $NewName } if ($PSBoundParameters.ContainsKey('Description')) { $body['description'] = $Description } if ($PSBoundParameters.ContainsKey('Direction')) { $body['direction'] = $directionMap[$Direction] } if ($PSBoundParameters.ContainsKey('Action')) { $body['action'] = $actionMap[$Action] } if ($PSBoundParameters.ContainsKey('Protocol')) { $body['protocol'] = $protocolMap[$Protocol] } if ($PSBoundParameters.ContainsKey('SourceIP')) { $body['source_ip'] = $SourceIP } if ($PSBoundParameters.ContainsKey('SourcePorts')) { $body['source_ports'] = $SourcePorts } if ($PSBoundParameters.ContainsKey('DestinationIP')) { $body['destination_ip'] = $DestinationIP } if ($PSBoundParameters.ContainsKey('DestinationPorts')) { $body['destination_ports'] = $DestinationPorts } if ($PSBoundParameters.ContainsKey('TargetIP')) { $body['target_ip'] = $TargetIP } if ($PSBoundParameters.ContainsKey('TargetPorts')) { $body['target_ports'] = $TargetPorts } if ($PSBoundParameters.ContainsKey('Interface')) { $body['interface'] = $interfaceMap[$Interface] } if ($PSBoundParameters.ContainsKey('Enabled')) { $body['enabled'] = $Enabled } if ($PSBoundParameters.ContainsKey('Log')) { $body['log'] = $Log } if ($PSBoundParameters.ContainsKey('Statistics')) { $body['statistics'] = $Statistics } # Validate we have something to update if ($body.Count -eq 0) { Write-Warning "No properties specified to update for rule '$($targetRule.Name)'." return } # Build description of changes for WhatIf $changesDescription = ($body.Keys | ForEach-Object { "$_ = $($body[$_])" }) -join ', ' if ($PSCmdlet.ShouldProcess($targetRule.Name, "Set Rule ($changesDescription)")) { try { Write-Verbose "Updating rule '$($targetRule.Name)' (Key: $($targetRule.Key))" $response = Invoke-VergeAPI -Method PUT -Endpoint "vnet_rules/$($targetRule.Key)" -Body $body -Connection $Server Write-Verbose "Rule '$($targetRule.Name)' updated successfully" # Apply rules if requested if ($Apply) { Write-Verbose "Applying rules on network '$($targetRule.NetworkName)'" Invoke-VergeNetworkApply -Network $targetRule.NetworkKey -Server $Server } if ($PassThru) { # Return refreshed rule object Start-Sleep -Milliseconds 500 Get-VergeNetworkRule -Network $targetRule.NetworkKey -Key $targetRule.Key -Server $Server } } catch { Write-Error -Message "Failed to update rule '$($targetRule.Name)': $($_.Exception.Message)" -ErrorId 'RuleUpdateFailed' } } } } |