Last active
June 5, 2025 05:21
-
-
Save Skibisky/204642971da4c69cf5ebdaad828758b4 to your computer and use it in GitHub Desktop.
Win-Acme cPanel plugin script, expanded upon work by tmr-cf found at https://github.com/rmbolger/Posh-ACME/issues/376
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
Add or remove a DNS TXT record to cPanel | |
.DESCRIPTION | |
Note that this script is intended to be run via the install script plugin from win-acme.. | |
This script was copied and modified from the Posh-ACME repository Issue Tracker. | |
Please reference their license terms for use/modification: https://github.com/rmbolger/Posh-ACME/blob/main/LICENSE | |
Credit for the original script goes to tmr-cf, Thanks! | |
https://github.com/rmbolger/Posh-ACME/issues/376 | |
This modified version supports non-internet facing subdomain hosts to validate with the external domain. | |
Eg. cPanel website is at https://example.wa.edu.au/, intranet host wants https://server.internal.example.wa.edu.au/ | |
.PARAMETER RecordName | |
The fully qualified name of the TXT record. | |
.PARAMETER TxtValue | |
The value of the TXT record. | |
.PARAMETER cPanelDomain | |
The cPanel API Host. | |
.PARAMETER cPanelUserName | |
The cPanel API User Name. | |
.PARAMETER cPanelApiKey | |
The cPanel API Token. | |
.PARAMETER ExtraParams | |
This parameter can be ignored and is only used to prevent errors when splatting with more parameters than this function supports. | |
.EXAMPLE | |
cPanel.ps1 create {RecordName} {Token} cPanelDomain cPanelUserName cPanelApiKey | |
cPanel.ps1 delete {RecordName} {Token} cPanelDomain cPanelUserName cPanelApiKey | |
.NOTES | |
Ideally put your api key in the secrets, and replace cPanelApiKey with {vault://json/cPanelToken} | |
#> | |
param( | |
[string]$Task, | |
[string]$RecordName, | |
[string]$TxtValue, | |
[string]$cPanelDomain, | |
[string]$cPanelUserName, | |
[string]$cPanelApiKey | |
) | |
function Get-CurrentPluginType { 'dns-01' } | |
function Add-DnsTxt { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory, Position = 0)] | |
[string]$RecordName, | |
[Parameter(Mandatory, Position = 1)] | |
[string]$TxtValue, | |
[Parameter(Mandatory, Position = 2)] | |
[string]$cPanelDomain, | |
[Parameter(Mandatory, Position = 3)] | |
[string]$cPanelUsername, | |
[Parameter(Mandatory, Position = 4)] | |
[string]$cPanelAPIToken, | |
[Parameter(ValueFromRemainingArguments)] | |
$ExtraParams | |
) | |
# Do work here to add the TXT record. Remember to add @script:UseBasic | |
# to all calls to Invoke-RestMethod or Invoke-WebRequest. | |
# Find Zone serial number | |
if (-not ($ZoneSerial = Find-CPZoneSerial $RecordName $cPanelDomain $cPanelUsername $cPanelAPIToken)) { | |
throw "Unable to find matching zone for $RecordName." | |
} | |
$Header = @{"Authorization" = "cpanel " + $cPanelUsername + ":" + $cPanelAPIToken } | |
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12 | |
# NOTE: cPanel will append `<sitename>.` to the end of dnames that don't end in `.`, so we [put one on the end | |
$JSON = [System.Web.HTTPUtility]::UrlEncode("{""dname"":""$RecordName."", ""ttl"":60, ""record_type"":""TXT"", ""data"":[""$TxtValue""]}") | |
$URI = "https://${cPanelDomain}:2083/execute/DNS/mass_edit_zone?zone=$cPanelDomain&serial=$ZoneSerial&add=$JSON" | |
Invoke-RestMethod -Method POST -headers $Header -uri $URI -DisableKeepAlive | |
<# | |
.SYNOPSIS | |
Add a DNS TXT record to <My DNS Server/Provider> | |
.DESCRIPTION | |
Description for <My DNS Server/Provider> | |
.PARAMETER RecordName | |
The fully qualified name of the TXT record. | |
.PARAMETER TxtValue | |
The value of the TXT record. | |
.PARAMETER cPanelDomain | |
The cPanel host. | |
.PARAMETER cPanelUsername | |
The which user to login. | |
.PARAMETER cPanelAPIToken | |
The API token to gain access. | |
.PARAMETER ExtraParams | |
This parameter can be ignored and is only used to prevent errors when splatting with more parameters than this function supports. | |
.EXAMPLE | |
Add-DnsTxt '_acme-challenge.subsite.example.com' 'txt-value' 'example.com' 'username' 'mytokenvalue' | |
Adds a TXT record for the specified site with the specified value. | |
#> | |
} | |
function Remove-DnsTxt { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory, Position = 0)] | |
[string]$RecordName, | |
[Parameter(Mandatory, Position = 1)] | |
[string]$TxtValue, | |
[Parameter(Mandatory, Position = 2)] | |
[string]$cPanelDomain, | |
[Parameter(Mandatory, Position = 3)] | |
[string]$cPanelUsername, | |
[Parameter(Mandatory, Position = 4)] | |
[string]$cPanelAPIToken, | |
[Parameter(ValueFromRemainingArguments)] | |
$ExtraParams | |
) | |
# Do work here to remove the TXT record. Remember to add @script:UseBasic | |
# to all calls to Invoke-RestMethod or Invoke-WebRequest. | |
# Find Zone serial number | |
if (-not ($ZoneSerial = Find-CPZoneSerial $RecordName $cPanelDomain $cPanelUsername $cPanelAPIToken)) { | |
throw "Unable to find matching zone for $RecordName." | |
} | |
# Find Zone line number | |
if (-not ($ZoneLine = Find-CPZoneLine $RecordName $TxtValue $cPanelDomain $cPanelUsername $cPanelAPIToken)) { | |
throw "Unable to find matching line for $RecordName." | |
} | |
$Header = @{"Authorization" = "cpanel " + $cPanelUsername + ":" + $cPanelAPIToken } | |
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12 | |
$URI = "https://${cPanelDomain}:2083/execute/DNS/mass_edit_zone?zone=$cPanelDomain&serial=$ZoneSerial&remove=$ZoneLine" | |
Invoke-RestMethod -Method POST -headers $Header -uri $URI -DisableKeepAlive | |
<# | |
.SYNOPSIS | |
Remove a DNS TXT record from <My DNS Server/Provider> | |
.DESCRIPTION | |
Description for <My DNS Server/Provider> | |
.PARAMETER RecordName | |
The fully qualified name of the TXT record. | |
.PARAMETER TxtValue | |
The value of the TXT record. | |
.PARAMETER cPanelDomain | |
The cPanel host. | |
.PARAMETER cPanelUsername | |
The which user to login. | |
.PARAMETER cPanelAPIToken | |
The API token to gain access. | |
.PARAMETER ExtraParams | |
This parameter can be ignored and is only used to prevent errors when splatting with more parameters than this function supports. | |
.EXAMPLE | |
Remove-DnsTxt '_acme-challenge.example.com' 'txt-value' | |
Removes a TXT record for the specified site with the specified value. | |
#> | |
} | |
function Save-DnsTxt { | |
[CmdletBinding()] | |
param( | |
[Parameter(ValueFromRemainingArguments)] | |
$ExtraParams | |
) | |
<# | |
.SYNOPSIS | |
Not required. | |
.DESCRIPTION | |
This provider does not require calling this function to commit changes to DNS records. | |
.PARAMETER ExtraParams | |
This parameter can be ignored and is only used to prevent errors when splatting with more parameters than this function supports. | |
#> | |
} | |
############################ | |
# Helper Functions | |
############################ | |
# Add a commented link to API docs if they exist. | |
# Add additional functions here if necessary. | |
# Try to follow verb-noun naming guidelines. | |
# https://msdn.microsoft.com/en-us/library/ms714428 | |
# https://hostname.example.com:2083/cpsess##########/execute/DNS/parse_zone?zone=example.com | |
function Find-CPZoneSerial { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory, Position = 0)] | |
[string]$RecordName, | |
[Parameter(Mandatory, Position = 1)] | |
[string]$cPanelDomain, | |
[Parameter(Mandatory, Position = 2)] | |
[string]$cPanelUsername, | |
[Parameter(Mandatory, Position = 3)] | |
[string]$cPanelAPIToken | |
) | |
$Header = @{"Authorization" = "cpanel " + $cPanelUsername + ":" + $cPanelAPIToken } | |
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12 | |
$URI = "https://${cPanelDomain}:2083/execute/DNS/parse_zone?zone=$cPanelDomain" | |
$Response = Invoke-RestMethod -Method POST -headers $Header -uri $URI -DisableKeepAlive | |
$SOARecord = $Response.data | Where-Object { ($_."record_type" -eq 'SOA') } | |
$SOARecordData = $SOARecord.data_b64 | |
$Array = $SOARecordData.Split("`r`n") | |
return [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($Array[2])) | |
} | |
function Find-CPZoneLine { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory, Position = 0)] | |
[string]$RecordName, | |
[Parameter(Mandatory, Position = 1)] | |
[string]$TxtValue, | |
[Parameter(Mandatory, Position = 2)] | |
[string]$cPanelDomain, | |
[Parameter(Mandatory, Position = 3)] | |
[string]$cPanelUsername, | |
[Parameter(Mandatory, Position = 4)] | |
[string]$cPanelAPIToken | |
) | |
$Header = @{"Authorization" = "cpanel " + $cPanelUsername + ":" + $cPanelAPIToken } | |
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12 | |
$URI = "https://${cPanelDomain}:2083/execute/DNS/parse_zone?zone=$cPanelDomain" | |
$Response = Invoke-RestMethod -Method POST -headers $Header -uri $URI -DisableKeepAlive | |
# cPanel will put `.<site>.` on the end of dnames that don't end in `.` | |
$RecordNameb64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($RecordName + ".")) | |
$TxtValueb64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($TxtValue)) | |
$Record = $Response.data | Where-Object { ($_."record_type" -eq 'TXT') -and ($_."dname_b64" -eq $RecordNameb64) -and ($_."data_b64" -eq $TxtValueb64) } | |
return $Record.line_index | |
} | |
if ($Task -eq 'create') { | |
Add-DnsTxt $RecordName $TxtValue $cPanelDomain $cPanelUserName $cPanelApiKey | |
} | |
if ($Task -eq 'delete') { | |
Remove-DnsTxt $RecordName $TxtValue $cPanelDomain $cPanelUserName $cPanelApiKey | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment