Private/Invoke-UnifiRequest.ps1

function Invoke-UnifiRequest {
    [CmdletBinding()]
    param(
        [ValidateSet('GET', 'POST', 'PUT', 'DELETE')]
        [string]$Method = 'GET',

        # For site-scoped endpoints pass just the path after /api/s/{site}, e.g. '/rest/wlanconf'
        # For global endpoints pass the full path, e.g. '/api/self/sites'
        [Parameter(Mandatory)]
        [string]$Endpoint,

        [string]$Site,

        [object]$Body
    )

    if (-not $script:UnifiSession -or -not $script:UnifiConfig) {
        throw "Not connected. Run Connect-UnifiController first."
    }

    $baseUrl = $script:UnifiConfig.ControllerUrl

    $uri = if ($Site) {
        "$baseUrl/api/s/$Site$Endpoint"
    } else {
        "$baseUrl$Endpoint"
    }

    $params = @{
        Method     = $Method
        Uri        = $uri
        WebSession = $script:UnifiSession
    }

    if ($script:UnifiConfig.SkipCertificateCheck) {
        $params.SkipCertificateCheck = $true
    }

    if ($Method -ne 'GET' -and $script:UnifiConfig.CsrfToken) {
        $params.Headers = @{ 'X-Csrf-Token' = $script:UnifiConfig.CsrfToken }
    }

    if ($Body) {
        $params.Body        = ($Body | ConvertTo-Json -Depth 10 -Compress)
        $params.ContentType = 'application/json'
    }

    try {
        Invoke-RestMethod @params
    }
    catch [Microsoft.PowerShell.Commands.HttpResponseException] {
        $code = $_.Exception.Response.StatusCode.value__
        if ($code -eq 401) {
            throw "Session expired or unauthorized. Run Connect-UnifiController to re-authenticate."
        }
        throw "HTTP $code`: $_"
    }
}