Private/Resolve-UserIdentity.ps1

function Resolve-UserIdentity {
    <#
    .SYNOPSIS
        Resolves any form of user identifier to a consistent user object.
    .DESCRIPTION
        Takes a UPN, SAMAccountName, email address, or display name and resolves it
        to a normalized object containing SAMAccountName, UPN, Mail, ObjectId, and
        DisplayName. Searches Active Directory in the following order:
          1. SAMAccountName
          2. UserPrincipalName
          3. Mail attribute
          4. DisplayName
    .PARAMETER Identity
        The user identifier to resolve. Accepts UPN, SAMAccountName, email, or display name.
    .OUTPUTS
        PSCustomObject with SAMAccountName, UPN, Mail, ObjectId, DisplayName properties.
    .EXAMPLE
        Resolve-UserIdentity -Identity "jsmith"
    .EXAMPLE
        Resolve-UserIdentity -Identity "john.smith@contoso.com"
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$Identity
    )

    $adProperties = @(
        'SamAccountName'
        'UserPrincipalName'
        'Mail'
        'ObjectGUID'
        'DisplayName'
        'Enabled'
    )

    $adUser = $null

    # Strategy 1: Try as SAMAccountName (most common for quick lookups)
    Write-Verbose "Resolve-UserIdentity: Trying SAMAccountName match for '$Identity'"
    try {
        $adUser = Get-ADUser -Identity $Identity -Properties $adProperties -ErrorAction Stop
    }
    catch {
        Write-Verbose " Not found by SAMAccountName: $($_.Exception.Message)"
    }

    # Strategy 2: Try as UserPrincipalName
    if (-not $adUser) {
        Write-Verbose "Resolve-UserIdentity: Trying UPN match for '$Identity'"
        try {
            $adUser = Get-ADUser -Filter "UserPrincipalName -eq '$Identity'" -Properties $adProperties -ErrorAction Stop
        }
        catch {
            Write-Verbose " UPN filter failed: $($_.Exception.Message)"
        }
    }

    # Strategy 3: Try as mail attribute
    if (-not $adUser) {
        Write-Verbose "Resolve-UserIdentity: Trying mail attribute match for '$Identity'"
        try {
            $adUser = Get-ADUser -Filter "Mail -eq '$Identity'" -Properties $adProperties -ErrorAction Stop
        }
        catch {
            Write-Verbose " Mail filter failed: $($_.Exception.Message)"
        }
    }

    # Strategy 4: Try as DisplayName
    if (-not $adUser) {
        Write-Verbose "Resolve-UserIdentity: Trying DisplayName match for '$Identity'"
        try {
            $results = Get-ADUser -Filter "DisplayName -eq '$Identity'" -Properties $adProperties -ErrorAction Stop
            if ($results -is [array] -and $results.Count -gt 1) {
                Write-Warning "Multiple users found with DisplayName '$Identity'. Using the first match: $($results[0].SamAccountName)"
                $adUser = $results[0]
            }
            else {
                $adUser = $results
            }
        }
        catch {
            Write-Verbose " DisplayName filter failed: $($_.Exception.Message)"
        }
    }

    # Strategy 5: Wildcard fallback on DisplayName
    if (-not $adUser) {
        Write-Verbose "Resolve-UserIdentity: Trying wildcard DisplayName match for '$Identity'"
        try {
            $results = Get-ADUser -Filter "DisplayName -like '*$Identity*'" -Properties $adProperties -ErrorAction Stop
            if ($results -is [array] -and $results.Count -gt 1) {
                $names = ($results | ForEach-Object { "$($_.SamAccountName) ($($_.DisplayName))" }) -join ', '
                throw "Multiple users matched wildcard search for '$Identity': $names. Please provide a more specific identifier."
            }
            elseif ($results) {
                Write-Verbose " Found via wildcard: $($results.SamAccountName)"
                $adUser = $results
            }
        }
        catch [Microsoft.ActiveDirectory.Management.ADFilterParsingException] {
            Write-Verbose " Wildcard filter failed: $($_.Exception.Message)"
        }
    }

    if (-not $adUser) {
        throw "Unable to resolve user identity '$Identity'. Tried SAMAccountName, UPN, mail, and DisplayName lookups. Verify the user exists in Active Directory."
    }

    [PSCustomObject]@{
        SAMAccountName = $adUser.SamAccountName
        UPN            = $adUser.UserPrincipalName
        Mail           = $adUser.Mail
        ObjectId       = $adUser.ObjectGUID.ToString()
        DisplayName    = $adUser.DisplayName
        Enabled        = $adUser.Enabled
    }
}