Public/Get-UKGProEmployeeChange.ps1

function Get-UKGProEmployeeChange {
    <#
    .SYNOPSIS
        Retrieves rows from the UKG Pro Employee Changes feed (change-detection
        snapshots for downstream sync pipelines).

    .DESCRIPTION
        Wraps GET /personnel/v1/employee-changes (list, with an optional
        start/end date range) and GET /personnel/v1/employee-changes/{employeeId}
        (single-employee, fixed 3-hour window). Routing is driven by which
        parameters are supplied.

        IMPORTANT - this is a CHANGE FEED, not a point-in-time query. The API
        returns a flat snapshot of each employee who had any change in the
        window; it does NOT tell you which field(s) changed. To determine what
        changed, you must store your prior snapshot and diff it against this
        call's result. If "who changed recently" is enough and you don't need
        the delta semantics, Get-UKGProEmploymentDetails -ChangedSince is
        simpler.

        UKG rate-limits this endpoint hard: no more than 8 calls/day, and no
        more than one call every 3 hours. Faster polling returns 429. The
        /employeeId variant is explicitly windowed to 3 hours — no date-range
        parameter is accepted.

        Requires the "View" role on the "EmployeeExport" Web Service (NOT the
        "Personnel Integration" role that other Get- cmdlets use). If the
        service account doesn't have that role, calls return 403.

    .PARAMETER EmployeeId
        Single UKG Pro employee ID. Hits the /employee-changes/{employeeId}
        endpoint directly; returns changes for just this employee over the
        last 3 hours. Mutually exclusive with the list filters because the
        single-employee endpoint doesn't accept date-range params.

    .PARAMETER StartDate
        Window start (datetime). Returns employees that changed on or after
        this time. Serialized to ISO 8601 for the UKG API.

    .PARAMETER EndDate
        Window end (datetime). Returns employees that changed on or before
        this time. Serialized to ISO 8601 for the UKG API.

    .PARAMETER MaxResults
        Cap total records across all pages. `0` = no cap. Default: `0`.

    .PARAMETER PageSize
        Rows per page to request. Range 1-200 (UKG hard-caps this endpoint
        at 200, unlike other personnel endpoints). Default: `100`.

    .EXAMPLE
        Get-UKGProEmployeeChange

        Pull everyone who changed in the implicit (most recent) UKG window.
        First call seeds your snapshot; subsequent calls can be diffed to
        determine what changed per employee.

    .EXAMPLE
        Get-UKGProEmployeeChange -StartDate (Get-Date).AddHours(-6)

        Pull every employee that changed in the last 6 hours.

    .EXAMPLE
        Get-UKGProEmployeeChange -EmployeeId '000123'

        Current-snapshot pull for one employee (3-hour window; the API does
        not accept a date range on this path).

    .EXAMPLE
        $current = Get-UKGProEmployeeChange -StartDate (Get-Date).AddHours(-3)
        $byId = @{}; foreach ($r in $current) { $byId[$r.employeeId] = $r }
        # ...compare $byId to a saved prior snapshot to find per-field deltas.

        Minimal sketch of the diff pattern this feed is designed for.

    .LINK
        Get-UKGProEmploymentDetails
    #>

    [CmdletBinding(DefaultParameterSetName = 'List')]
    [OutputType([pscustomobject])]
    param (
        [Parameter(ParameterSetName = 'ByEmployeeId', Mandatory)]
        [string]$EmployeeId,

        [Parameter(ParameterSetName = 'List')]
        [datetime]$StartDate,

        [Parameter(ParameterSetName = 'List')]
        [datetime]$EndDate,

        [Parameter()] [int]$MaxResults = 0,

        [Parameter()]
        [ValidateRange(1, 200)]
        [int]$PageSize = 100
    )

    # --- Single-employee lookup: /employee-changes/{employeeId}, no paging ---
    if ($PSCmdlet.ParameterSetName -eq 'ByEmployeeId') {
        return Invoke-UKGProRequest -Method Get `
            -Path "/personnel/v1/employee-changes/$EmployeeId" `
            -NoPaging |
            Add-UKGProTypeName -TypeName 'UKGPro.EmployeeChange'
    }

    # --- List endpoint with optional start/end window ---
    # ISO 8601 round-trip ("o") matches the swagger's date-time example and
    # avoids locale-dependent formatting pitfalls.
    $q = @{}
    if ($PSBoundParameters.ContainsKey('StartDate')) {
        $q['startDate'] = $StartDate.ToUniversalTime().ToString('o')
    }
    if ($PSBoundParameters.ContainsKey('EndDate')) {
        $q['endDate']   = $EndDate.ToUniversalTime().ToString('o')
    }

    Invoke-UKGProRequest -Method Get -Path '/personnel/v1/employee-changes' `
        -Query $q -PageSize $PageSize -MaxResults $MaxResults |
        Add-UKGProTypeName -TypeName 'UKGPro.EmployeeChange'
}