Functions/GenXdev.Windows.WireGuard/Reset-WireGuardConfiguration.ps1

################################################################################
<#
.SYNOPSIS
Resets the WireGuard VPN server configuration, removing all peers.
 
.DESCRIPTION
This function resets the WireGuard VPN server configuration running in a Docker
container by removing all peers and generating a fresh server configuration.
This is a destructive operation that cannot be undone and will permanently
remove all peer configurations. The function stops the WireGuard service,
removes all peer directories and configuration files, removes server keys,
restarts the container, and verifies that a new configuration is generated.
 
.PARAMETER ContainerName
The name for the Docker container. Defaults to 'wireguard' if not specified.
Used to identify which container to operate on.
 
.PARAMETER VolumeName
The name for the Docker volume for persistent storage. Defaults to
'wireguard_data' if not specified. Used for data persistence across container
restarts.
 
.PARAMETER ServicePort
The port number for the WireGuard service. Must be between 1 and 65535.
Defaults to 51820. This is the UDP port WireGuard will listen on.
 
.PARAMETER HealthCheckTimeout
Maximum time in seconds to wait for service health check. Must be between 10
and 300 seconds. Defaults to 60 seconds. Used when verifying service health.
 
.PARAMETER HealthCheckInterval
Interval in seconds between health check attempts. Must be between 1 and 10
seconds. Defaults to 3 seconds. Controls how often health checks are performed.
 
.PARAMETER ImageName
Custom Docker image name to use. Defaults to 'linuxserver/wireguard'. This
allows using alternative WireGuard Docker images if needed.
 
.PARAMETER PUID
User ID for permissions in the container. Defaults to '1000'. This controls
file ownership and permissions within the container.
 
.PARAMETER PGID
Group ID for permissions in the container. Defaults to '1000'. This controls
group ownership and permissions within the container.
 
.PARAMETER TimeZone
Timezone to use for the container. Defaults to 'Etc/UTC'. This sets the
container's timezone for logging and scheduling purposes.
 
.PARAMETER NoDockerInitialize
Skip Docker initialization (used when already called by parent function).
When specified, assumes Docker and WireGuard are already initialized.
 
.PARAMETER Force
If specified, bypasses confirmation prompts when removing all peer
configurations. Use with caution as this is a destructive operation.
 
.EXAMPLE
Reset-WireGuardConfiguration
 
Resets the WireGuard configuration with default settings and prompts for
confirmation before proceeding.
 
.EXAMPLE
Reset-WireGuardConfiguration -Force -ContainerName "my-wireguard"
 
Resets the WireGuard configuration for a custom container name without
confirmation prompts.
 
.NOTES
This function interacts with the linuxserver/wireguard Docker container to reset
the WireGuard server configuration. It requires the container to be running
(use EnsureWireGuard first). This operation will remove all peer configurations
and cannot be undone. The function will restart the container to regenerate
a fresh configuration.
#>

###############################################################################
function Reset-WireGuardConfiguration {

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "")]

    param(
        ###########################################################################
        [Parameter(
            Position = 0,
            Mandatory = $false,
            HelpMessage = "The name for the Docker container"
        )]
        [ValidateNotNullOrEmpty()]
        [string] $ContainerName = "wireguard",
        ###########################################################################
        [Parameter(
            Position = 1,
            Mandatory = $false,
            HelpMessage = "The name for the Docker volume for persistent storage"
        )]
        [ValidateNotNullOrEmpty()]
        [string] $VolumeName = "wireguard_data",
        ###########################################################################
        [Parameter(
            Position = 2,
            Mandatory = $false,
            HelpMessage = "The port number for the WireGuard service"
        )]
        [ValidateRange(1, 65535)]
        [int] $ServicePort = 51820,
        ###########################################################################
        [Parameter(
            Position = 3,
            Mandatory = $false,
            HelpMessage = "Maximum time in seconds to wait for service health check"
        )]
        [ValidateRange(10, 300)]
        [int] $HealthCheckTimeout = 60,
        ###########################################################################
        [Parameter(
            Position = 4,
            Mandatory = $false,
            HelpMessage = "Interval in seconds between health check attempts"
        )]
        [ValidateRange(1, 10)]
        [int] $HealthCheckInterval = 3,
        ###########################################################################
        [Parameter(
            Position = 5,
            Mandatory = $false,
            HelpMessage = "Custom Docker image name to use"
        )]
        [ValidateNotNullOrEmpty()]
        [string] $ImageName = "linuxserver/wireguard",
        ###########################################################################
        [Parameter(
            Position = 6,
            Mandatory = $false,
            HelpMessage = "User ID for permissions in the container"
        )]
        [ValidateNotNullOrEmpty()]
        [string] $PUID = "1000",
        ###########################################################################
        [Parameter(
            Position = 7,
            Mandatory = $false,
            HelpMessage = "Group ID for permissions in the container"
        )]
        [ValidateNotNullOrEmpty()]
        [string] $PGID = "1000",
        ###########################################################################
        [Parameter(
            Position = 8,
            Mandatory = $false,
            HelpMessage = "Timezone to use for the container"
        )]
        [ValidateNotNullOrEmpty()]
        [string] $TimeZone = "Etc/UTC",
        ###########################################################################
        [Parameter(
            Mandatory = $false,
            HelpMessage = "Skip Docker initialization (used when already called by parent function)"
        )]
        [switch] $NoDockerInitialize,
        ###########################################################################
        [Parameter(
            Mandatory = $false,
            HelpMessage = "Force reset without confirmation"
        )]
        [switch] $Force
        ###########################################################################
    )

    begin {

        # check if docker initialization should be skipped
        if (-not $NoDockerInitialize) {

            # output verbose message about ensuring wireguard service
            Microsoft.PowerShell.Utility\Write-Verbose `
                "Ensuring WireGuard service is available"

            # copy matching parameters to pass to EnsureWireGuard function
            $ensureParams = GenXdev.Helpers\Copy-IdenticalParamValues `
                -BoundParameters $PSBoundParameters `
                -FunctionName 'EnsureWireGuard' `
                -DefaultValues (Microsoft.PowerShell.Utility\Get-Variable `
                    -Scope Local `
                    -ErrorAction SilentlyContinue)

            # initialize wireguard service with specified parameters
            $null = GenXdev.Windows\EnsureWireGuard @ensureParams

        } else {

            # output verbose message about skipping docker initialization
            Microsoft.PowerShell.Utility\Write-Verbose `
                "Skipping Docker initialization as requested"
        }
    }

    process {

        try {

            # count existing peers to show in warning message
            $peerFolders = docker exec $ContainerName sh -c `
                "ls -1d /config/peer_* 2>/dev/null | wc -l"

            # initialize peer count variable
            $peerCount = 0

            # check if peer count command was successful
            if ($LASTEXITCODE -eq 0) {

                # convert peer folders output to integer count
                $peerCount = [int]$peerFolders
            }

            # check if server configuration file exists for reporting
            $serverConfigExists = docker exec $ContainerName sh -c `
                "[ -f /config/wg0.conf ] && echo 'exists' || echo 'not exists'"

            # determine if server configuration is present
            $hasServerConfig = ($serverConfigExists -eq 'exists')

            # build confirmation message with peer count information
            $confirmMessage = ("WARNING: You are about to reset the WireGuard " +
                              "configuration. This will remove all $peerCount " +
                              "peer configurations and cannot be undone. Are " +
                              "you sure you want to proceed?")

            # define operation name for shouldprocess
            $operationName = "Resetting WireGuard configuration"

            # check if user confirmed the operation or force flag is set
            if ($Force -or $PSCmdlet.ShouldProcess($confirmMessage,
                                                   $operationName)) {

                # output verbose message about starting reset process
                Microsoft.PowerShell.Utility\Write-Verbose `
                    "Resetting WireGuard configuration, removing all peers..."

                # stop wireguard service in the container gracefully
                $null = docker exec $ContainerName sh -c `
                    "wg-quick down wg0 2>/dev/null || true"

                # wait for service to stop completely
                Microsoft.PowerShell.Utility\Start-Sleep -Seconds 2

                # remove all peer directories from configuration
                $null = docker exec $ContainerName sh -c `
                    "rm -rf /config/peer_* 2>/dev/null || true"

                # check if peer removal was successful
                $peersRemoved = ($LASTEXITCODE -eq 0)

                # remove wireguard configuration file
                $null = docker exec $ContainerName sh -c `
                    "rm -f /config/wg0.conf 2>/dev/null || true"

                # check if configuration removal was successful
                $configRemoved = ($LASTEXITCODE -eq 0)

                # remove server private and public keys
                $null = docker exec $ContainerName sh -c `
                    "rm -f /config/server_* 2>/dev/null || true"

                # check if key removal was successful
                $keysRemoved = ($LASTEXITCODE -eq 0)

                # output verbose message about restarting container
                Microsoft.PowerShell.Utility\Write-Verbose `
                    "Restarting WireGuard container to regenerate configuration..."

                # restart the container to regenerate fresh configuration
                docker restart $ContainerName

                # check if container restart was successful
                if ($LASTEXITCODE -ne 0) {

                    # throw error if container restart failed
                    throw "Failed to restart WireGuard container"
                }

                # wait for container to fully initialize after restart
                Microsoft.PowerShell.Utility\Start-Sleep -Seconds 10

                # verify container is running after restart
                $containerStatus = docker ps -q -f name=$ContainerName

                # check if container is actually running
                if (-not $containerStatus) {

                    # throw error if container failed to restart
                    throw "WireGuard container failed to restart"
                }

                # check if new configuration was generated successfully
                $newConfigExists = docker exec $ContainerName sh -c `
                    "[ -f /config/wg0.conf ] && echo 'exists' || echo 'not exists'"

                # verify new configuration file was created
                if ($newConfigExists -ne "exists") {

                    # throw error if configuration generation failed
                    throw "Failed to generate new WireGuard configuration"
                }

                # display success message to user
                Microsoft.PowerShell.Utility\Write-Host -ForegroundColor Green `
                    ("WireGuard configuration reset successfully. All peers " +
                     "have been removed.")

                # provide guidance for next steps
                Microsoft.PowerShell.Utility\Write-Host `
                    "Use Add-WireGuardPeer to create new peer configurations."

                # return success information object
                return [PSCustomObject]@{
                    Success = $true
                    Message = "WireGuard configuration reset successfully"
                    PeersRemoved = $peerCount
                    InitialConfig = $hasServerConfig
                    PeersRemoveSuccess = $peersRemoved
                    ConfigRemoveSuccess = $configRemoved
                    KeysRemoveSuccess = $keysRemoved
                }
            }

            # return cancellation information if user declined
            return [PSCustomObject]@{
                Success = $false
                Message = "WireGuard configuration reset was canceled by user"
                PeersRemoved = 0
            }

        } catch {

            # output error message for any failures during reset
            Microsoft.PowerShell.Utility\Write-Error `
                "Failed to reset WireGuard configuration: $_"

            # re-throw the exception to caller
            throw
        }
    }

    end {
    }
}
################################################################################