Public/Connect-PowerDMARC.ps1

function Connect-PowerDMARC {
    <#
    .SYNOPSIS
        Establishes a connection to the PowerDMARC API for the current session.

    .DESCRIPTION
        Stores the PowerDMARC API base URI, operating mode and Personal Access Token (PAT) for
        the current session so that other PowerDMARC module cmdlets (e.g. Get-PDDomain,
        Get-PDHostedSPF) can call the API without repeating authentication.

        PowerDMARC does not expose a username/password login endpoint. Tokens are generated
        manually in the PowerDMARC console under API Settings > Personal Access Tokens (or, for
        MSSP administrators, API Settings > Manage API Tokens) and are sent as a Bearer token on
        every subsequent request.

        PowerDMARC exposes two distinct API surfaces on the same host, rooted at different paths:
          - Default (End User API), rooted at /api/v1: operates on the domains that belong to
            the token's own account, e.g. `GET /domains/{domainId}`, `GET /hostedspf/{domainId}`.
          - Reseller (PowerDMARC's MSSP API), rooted at /api/v1/mssp: operates on domains
            belonging to the reseller's customer accounts and requires an AccountId on most
            calls, e.g. `GET /accounts/{accountId}/domains/{domainId}`,
            `GET /hosted/spf/{domainId}` (both relative to the /mssp root).
        -Mode determines which root the stored connection resolves to; other PowerDMARC cmdlets
        in this module build their relative paths off of it accordingly.

    .PARAMETER ApiToken
        The Personal Access Token generated in the PowerDMARC console.

    .PARAMETER Mode
        The API surface to use: Default for the End User API, or Reseller for PowerDMARC's MSSP
        API. Determines which endpoint layout other PowerDMARC cmdlets in this module call. The
        earlier names Consumer and MSSP are still accepted as aliases for Default and Reseller,
        respectively.

        Defaults to Default, unless -BaseUri is also explicitly supplied, in which case it
        defaults to Reseller -- a caller pointing at a specific host is assumed to be an MSSP
        reseller pointing at their branded portal. Pass -Mode explicitly to override this.

    .PARAMETER AccountId
        Reseller mode only. The default MSSP customer account ID to use on calls that don't
        specify one explicitly (e.g. Get-PDDomain -AccountId). Ignored in Default mode.

    .PARAMETER BaseUri
        The PowerDMARC host/root to call. Defaults to https://app.powerdmarc.com. MSSP resellers
        typically have their own branded portal host instead (e.g. reseller.powerdmarc.com) --
        pass that here. Accepts a bare host, a host with scheme, or a full API root; normalized
        as follows: a missing scheme defaults to https://, and a missing /api/vN path defaults to
        /api/v1. In Reseller mode, /mssp is then appended. Do not include /mssp yourself.

        Examples of accepted input, all resolving the same way in Reseller mode:
          reseller.powerdmarc.com -> https://reseller.powerdmarc.com/api/v1/mssp
          https://reseller.powerdmarc.com -> https://reseller.powerdmarc.com/api/v1/mssp
          https://reseller.powerdmarc.com/api/v1 -> https://reseller.powerdmarc.com/api/v1/mssp

    .PARAMETER PassThru
        Return the connection object in addition to storing it for the session.

    .PARAMETER ShowBanner
        Whether to print the connection banner (mode, base URI, and a Reseller account-selection
        hint when applicable) after connecting. Defaults to $true; pass -ShowBanner:$false to
        suppress it, e.g. in unattended scripts.

    .EXAMPLE
        $token = Read-Host -AsSecureString -Prompt 'PowerDMARC API token'
        Connect-PowerDMARC -ApiToken $token

    .EXAMPLE
        Connect-PowerDMARC -ApiToken (ConvertTo-SecureString $env:POWERDMARC_TOKEN -AsPlainText -Force) -Mode Reseller -AccountId 42

    .LINK
        https://api.powerdmarc.com/getting-started

    .LINK
        https://api.powerdmarc.com/authentication
    #>

    [CmdletBinding()]
    [OutputType([pscustomobject])]
    param(
        [Parameter(Mandatory, Position = 0)]
        [Alias('Token', 'PersonalAccessToken', 'PAT')]
        [securestring]$ApiToken,

        [Parameter()]
        [ValidateSet('Default', 'Reseller', 'Consumer', 'MSSP')]
        [string]$Mode = 'Default',

        [Parameter()]
        [int]$AccountId,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$BaseUri = 'app.powerdmarc.com',

        [Parameter()]
        [switch]$PassThru,

        [Parameter()]
        [bool]$ShowBanner = $true
    )

    if (-not $PSBoundParameters.ContainsKey('Mode') -and $PSBoundParameters.ContainsKey('BaseUri')) {
        $Mode = 'Reseller'
    }

    $resolvedMode = switch ($Mode) {
        'Consumer' { 'Default' }
        'MSSP'     { 'Reseller' }
        default    { $Mode }
    }

    $resolvedBaseUri = $BaseUri.Trim().TrimEnd('/')
    if ($resolvedBaseUri -notmatch '^https?://') {
        $resolvedBaseUri = "https://$resolvedBaseUri"
    }
    if ($resolvedBaseUri -notmatch '/api/v\d+$') {
        $resolvedBaseUri = "$resolvedBaseUri/api/v1"
    }
    if ($resolvedMode -eq 'Reseller') {
        $resolvedBaseUri = "$resolvedBaseUri/mssp"
    }

    $script:PDConnection = [pscustomobject]@{
        PSTypeName  = 'PowerDMARC.Connection'
        BaseUri     = $resolvedBaseUri
        Mode        = $resolvedMode
        AccountId   = if ($PSBoundParameters.ContainsKey('AccountId')) { $AccountId } else { $null }
        DomainId    = $null
        ApiToken    = $ApiToken
        ConnectedAt = Get-Date
    }

    Write-Verbose "Connected to PowerDMARC API ($resolvedMode mode) at $($script:PDConnection.BaseUri)"

    if ($ShowBanner) {
        Show-PDConnectionBanner -Connection $script:PDConnection
    }

    if ($PassThru) {
        $script:PDConnection | Select-Object BaseUri, Mode, AccountId, ConnectedAt
    }
}