Public/System/Get-VergeCertificate.ps1
|
function Get-VergeCertificate { <# .SYNOPSIS Retrieves SSL/TLS certificates from VergeOS. .DESCRIPTION Get-VergeCertificate retrieves one or more SSL/TLS certificates from a VergeOS system. Certificates can be manual uploads, Let's Encrypt (ACME), or self-signed. .PARAMETER Domain The primary domain of the certificate to retrieve. Supports wildcards (* and ?). If not specified, all certificates are returned. .PARAMETER Key The unique key (ID) of the certificate to retrieve. .PARAMETER Type Filter certificates by type: Manual, LetsEncrypt, or SelfSigned. .PARAMETER Valid Filter to show only valid (unexpired) certificates. .PARAMETER IncludeKeys Include the public key, private key, and chain in the output. Use with caution as this exposes sensitive key material. .PARAMETER Server The VergeOS connection to use. Defaults to the current default connection. .EXAMPLE Get-VergeCertificate Retrieves all certificates from the connected VergeOS system. .EXAMPLE Get-VergeCertificate -Domain "example.com" Retrieves a specific certificate by domain. .EXAMPLE Get-VergeCertificate -Domain "*.example.com" Retrieves wildcard certificates for example.com. .EXAMPLE Get-VergeCertificate -Type LetsEncrypt -Valid Retrieves all valid Let's Encrypt certificates. .EXAMPLE Get-VergeCertificate -Key 1 -IncludeKeys Retrieves a certificate by key including the key material. .OUTPUTS PSCustomObject with PSTypeName 'Verge.Certificate' .NOTES Certificate types: - Manual: Uploaded certificates with public/private keys - LetsEncrypt: Automatically managed via ACME protocol - SelfSigned: Self-signed certificates generated by VergeOS #> [CmdletBinding(DefaultParameterSetName = 'Filter')] [OutputType([PSCustomObject])] param( [Parameter(Position = 0, ParameterSetName = 'Filter')] [SupportsWildcards()] [string]$Domain, [Parameter(Mandatory, ParameterSetName = 'ByKey', ValueFromPipelineByPropertyName)] [Alias('Id', '$key')] [int]$Key, [Parameter(ParameterSetName = 'Filter')] [ValidateSet('Manual', 'LetsEncrypt', 'SelfSigned')] [string]$Type, [Parameter(ParameterSetName = 'Filter')] [switch]$Valid, [Parameter()] [switch]$IncludeKeys, [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 type names to API values $typeMapping = @{ 'Manual' = 'manual' 'LetsEncrypt' = 'letsencrypt' 'SelfSigned' = 'self_signed' } # Map API type values to friendly names $typeDisplayMapping = @{ 'manual' = 'Manual' 'letsencrypt' = "Let's Encrypt" 'self_signed' = 'Self-Signed' } } process { try { Write-Verbose "Querying certificates from $($Server.Server)" # Build query parameters $queryParams = @{} $filters = [System.Collections.Generic.List[string]]::new() # Filter by key if ($PSCmdlet.ParameterSetName -eq 'ByKey') { $filters.Add("`$key eq $Key") } else { # Filter by domain if ($Domain) { if ($Domain -match '[\*\?]' -and $Domain -notmatch '^\*\.') { # Wildcard search (but not domain wildcards like *.example.com) $searchTerm = $Domain -replace '[\*\?]', '' if ($searchTerm) { $filters.Add("domain ct '$searchTerm'") } } else { $filters.Add("domain eq '$Domain'") } } # Filter by type if ($Type) { $apiType = $typeMapping[$Type] $filters.Add("type eq '$apiType'") } # Filter by valid status if ($Valid) { $filters.Add("valid eq true") } } # Apply filters if ($filters.Count -gt 0) { $queryParams['filter'] = $filters -join ' and ' } # Request fields $fieldList = @( '$key' 'domain' 'domainname' 'domainlist' 'description' 'type' 'acme_server' 'key_type' 'rsa_key_size' 'contact' 'agree_tos' 'valid' 'autocreated' 'expires' 'created' 'modified' ) # Include sensitive key material if requested if ($IncludeKeys) { $fieldList += @('public', 'private', 'chain') Write-Warning "Including sensitive key material in output. Handle with care." } $queryParams['fields'] = $fieldList -join ',' $response = Invoke-VergeAPI -Method GET -Endpoint 'certificates' -Query $queryParams -Connection $Server # Handle both single object and array responses $certificates = if ($response -is [array]) { $response } else { @($response) } foreach ($cert in $certificates) { # Skip null entries - check for $key since domain might be empty for new certs if (-not $cert -or -not $cert.'$key') { continue } # Determine the primary domain - use domainname if domain is empty $primaryDomain = if ($cert.domain) { $cert.domain } else { $cert.domainname } # Apply wildcard filtering for client-side matching (for non-domain wildcards) if ($Domain -and ($Domain -match '[\*\?]') -and ($Domain -notmatch '^\*\.')) { if ($primaryDomain -notlike $Domain) { continue } } # Parse domain list $domainListArray = @() if ($cert.domainlist) { $domainListArray = ($cert.domainlist -split ',').Trim() | Where-Object { $_ } } # Get type display name $typeDisplay = $typeDisplayMapping[$cert.type] if (-not $typeDisplay) { $typeDisplay = $cert.type } # Create output object $output = [PSCustomObject]@{ PSTypeName = 'Verge.Certificate' Key = [int]$cert.'$key' Domain = $primaryDomain DomainName = $cert.domainname DomainList = $domainListArray Description = $cert.description Type = $typeDisplay TypeValue = $cert.type KeyType = if ($cert.key_type) { $cert.key_type.ToUpper() } else { $null } RSAKeySize = $cert.rsa_key_size ACMEServer = $cert.acme_server ContactId = if ($cert.contact) { [int]$cert.contact } else { $null } AgreeTOS = [bool]$cert.agree_tos Valid = [bool]$cert.valid AutoCreated = [bool]$cert.autocreated Expires = if ($cert.expires) { [DateTimeOffset]::FromUnixTimeSeconds($cert.expires).LocalDateTime } else { $null } Created = if ($cert.created) { [DateTimeOffset]::FromUnixTimeSeconds($cert.created).LocalDateTime } else { $null } Modified = if ($cert.modified) { [DateTimeOffset]::FromUnixTimeSeconds($cert.modified).LocalDateTime } else { $null } } # Add key material if requested if ($IncludeKeys) { $output | Add-Member -MemberType NoteProperty -Name 'PublicKey' -Value $cert.public $output | Add-Member -MemberType NoteProperty -Name 'PrivateKey' -Value $cert.private $output | Add-Member -MemberType NoteProperty -Name 'Chain' -Value $cert.chain } # Calculate days until expiration if ($output.Expires) { $daysUntilExpiry = ($output.Expires - (Get-Date)).Days $output | Add-Member -MemberType NoteProperty -Name 'DaysUntilExpiry' -Value $daysUntilExpiry } # Add hidden properties for pipeline support $output | Add-Member -MemberType NoteProperty -Name '_Connection' -Value $Server -Force Write-Output $output } } catch { $PSCmdlet.ThrowTerminatingError($_) } } } |