private/functions/Set-AxisWebServerCertificate.ps1

function Set-AxisWebServerCertificate {
    <#
    .SYNOPSIS
    Binds an installed certificate (by alias/Id) to the HTTPS web server of an Axis device.

    .DESCRIPTION
    There is no JSON API for this; the SOAP operation aweb:SetWebServerTlsConfiguration is used on all firmware.
    The device rejects the call with "InvalidCertificateConfigurationFault" unless the cipher list in the request
    matches what the device currently has in HTTPS.Ciphers, so the list is read with param.cgi first
    (https://github.com/orgs/AxisCommunications/discussions/631). AXIS OS 6.50 expects Admin/Operator/Viewer
    connection policies, 7.10 and later only Admin
    (https://developer.axis.com/vapix/network-video/certificate-management-api/ "Set HTTPS certificate").
    The documented policy value "Https" means the web server only accepts HTTPS for that role.

    .PARAMETER Device
    The IP address or hostname of the Axis device.

    .PARAMETER Alias
    The certificate alias (acert:Id) of a certificate with private key already installed on the device.

    .PARAMETER ConnectionPolicy
    Connection policy sent for the admin (and on OS < 7.10 operator/viewer) role. Default "Https" as documented.
    #>

    [cmdletbinding()]
    Param(
        [Parameter(Mandatory)]
        [String]$Device,

        [Parameter(Mandatory)]
        [String]$Alias,

        [Parameter()]
        [String]$ConnectionPolicy="Https"
    )

    #Cipher list must mirror the device's own HTTPS.Ciphers value
    Try {
        $HttpsParams = Get-AxisParameter -Device $Device -Group "HTTPS"
    }
    Catch {
        Throw "Unable to read HTTPS parameters from $($Device): $_"
    }
    $CipherString = $HttpsParams.'HTTPS.Ciphers'
    if(!$CipherString) {
        Throw "Device $Device did not return HTTPS.Ciphers; cannot build the TLS configuration"
    }
    $Ciphers = @($CipherString.Split(':') | Where-Object { $_ })

    #Firmware decides which connection policies are present
    $Version = (Get-AxisDeviceInfo -Device $Device).Version
    $Legacy = $false
    if($Version -and (Compare-Version -Version $Version -TargetVersion "7.10") -eq 1) {
        $Legacy = $true
    }

    $Policies = " <aweb:Admin>$ConnectionPolicy</aweb:Admin>`n"
    if($Legacy) {
        $Policies += " <aweb:Operator>$ConnectionPolicy</aweb:Operator>`n"
        $Policies += " <aweb:Viewer>$ConnectionPolicy</aweb:Viewer>`n"
    }

    $CipherXml = ""
    ForEach($Cipher in $Ciphers) {
        $CipherXml += " <acert:Cipher>$([System.Security.SecurityElement]::Escape($Cipher))</acert:Cipher>`n"
    }

    $SafeAlias = [System.Security.SecurityElement]::Escape($Alias)

    $Body = @"
<aweb:SetWebServerTlsConfiguration xmlns="http://www.axis.com/vapix/ws/webserver">
            <Configuration>
                <Tls>true</Tls>
                <aweb:ConnectionPolicies>
$Policies </aweb:ConnectionPolicies>
                <aweb:Ciphers>
$CipherXml </aweb:Ciphers>
                <aweb:CertificateSet>
                    <acert:Certificates>
                        <acert:Id>$SafeAlias</acert:Id>
                    </acert:Certificates>
                    <acert:CACertificates />
                    <acert:TrustedCertificates />
                </aweb:CertificateSet>
            </Configuration>
        </aweb:SetWebServerTlsConfiguration>
"@


    Write-Verbose "Assigning certificate '$Alias' to the web server on $Device (firmware $Version, $($Ciphers.Count) ciphers)"
    Try {
        $null = Invoke-AxisSoapRequest -Device $Device -Body $Body
    }
    Catch {
        Throw "Unable to assign certificate '$Alias' to HTTPS on $($Device): $_"
    }

    #Admin now has to use HTTPS; make sure subsequent calls do too
    Initialize-AxisCache -Device $Device
    $Cache.$Device.Type = "https"
}