Private/ActiveDirectory/Invoke-ADOperationWithRetry.ps1

function Invoke-ADOperationWithRetry {
    <#
    .SYNOPSIS
        Executes Active Directory operations with retry logic and security logging
 
    .DESCRIPTION
        Orchestrates AD operations by combining retry mechanisms with proper security
        audit logging. Provides enterprise-grade reliability for AD interactions.
 
    .PARAMETER ScriptBlock
        The AD operation to execute
 
    .PARAMETER MaxRetries
        Maximum retry attempts for transient failures
 
    .PARAMETER OperationName
        Descriptive name for the operation
 
    .PARAMETER ObjectContext
        Additional context about the AD object being accessed
 
    .EXAMPLE
        PS> Invoke-ADOperationWithRetry -ScriptBlock { Get-ADUser 'testuser' } -OperationName 'Get User'
 
        DESCRIPTION: Executes AD user lookup with retry and audit logging
        OUTPUT: AD user object with full audit trail
        USE CASE: Production AD operations requiring reliability and auditing
 
    .NOTES
        Author: Jeffrey Stuhr
        Blog: https://www.techbyjeff.net
        LinkedIn: https://www.linkedin.com/in/jeffrey-stuhr-034214aa/
 
        TROUBLESHOOTING:
        - For operation failures: .\Troubleshooting\Common\AD-Operation-Issues.md
        - For retry configuration: .\Troubleshooting\Performance\Retry-Tuning.md
    #>


    [CmdletBinding()]
    [OutputType('ADOperationResult')]
    param(
        [Parameter(Mandatory)]
        [scriptblock]$ScriptBlock,

        [Parameter()]
        [ValidateRange(1, 10)]
        [int]$MaxRetries = 3,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$OperationName = 'AD Operation',

        [Parameter()]
        [string]$ObjectContext = 'Unknown',

        [Parameter()]
        [string]$CorrelationId = [System.Guid]::NewGuid().ToString()
    )

    begin {
        Write-Verbose "Starting AD operation with retry: $OperationName"

        # Build security context
        $securityContext = @{
            ObjectContext = $ObjectContext
            MaxRetries = $MaxRetries
            ADAccessType = 'Sensitive'
            OperationType = 'SingleOperation'
        }
    }

    process {
        # Log operation attempt
        Write-ADOperationSecurityLog -OperationName $OperationName -Outcome 'Attempt' -SecurityContext $securityContext -CorrelationId $CorrelationId

        try {
            # Execute with retry logic
            $result = Invoke-OperationWithRetry -ScriptBlock $ScriptBlock -MaxRetries $MaxRetries -OperationName $OperationName -CorrelationId $CorrelationId

            # Log successful operation
            $successContext = $securityContext.Clone()
            $successContext['ResultType'] = if ($result) { $result.GetType().Name } else { 'NoResult' }

            Write-ADOperationSecurityLog -OperationName $OperationName -Outcome 'Success' -SecurityContext $successContext -CorrelationId $CorrelationId

            return $result
        }
        catch {
            # Log failed operation
            $failureContext = $securityContext.Clone()
            $failureContext['ErrorMessage'] = $_.Exception.Message
            $failureContext['FailureCategory'] = 'OperationFailed'

            Write-ADOperationSecurityLog -OperationName $OperationName -Outcome 'Failure' -SecurityContext $failureContext -CorrelationId $CorrelationId

            throw
        }
    }
}