Private/Clear-SecureMemory.ps1

function Clear-SecureMemory {
    <#
    .SYNOPSIS
        Securely clears sensitive data from memory.
 
    .DESCRIPTION
        This security helper function provides centralized memory cleanup for sensitive data
        including tokens, credentials, and other security-sensitive objects. It ensures
        proper disposal of SecureString objects and clears connection parameters.
 
    .PARAMETER SecureStrings
        Array of SecureString objects to clear from memory.
 
    .PARAMETER Variables
        Array of variable names (strings) to clear from the current scope.
 
    .PARAMETER Objects
        Array of objects to clear and set to null.
 
    .PARAMETER Scope
        The scope to clear variables from. Valid values: Local, Script, Global.
        Defaults to Local.
 
    .EXAMPLE
        Clear-SecureMemory -SecureStrings @($SecureToken, $SecureSecret)
 
        Clears SecureString objects from memory.
 
    .EXAMPLE
        Clear-SecureMemory -Variables @('PlainTextToken', 'TempPassword') -Scope Local
 
        Clears specified variables from local scope.
 
    .EXAMPLE
        Clear-SecureMemory -Objects @($TokenObject, $CredentialObject)
 
        Clears object references.
 
    .OUTPUTS
        System.Management.Automation.PSObject
        Returns cleanup result with statistics and any issues encountered.
 
    .NOTES
        Author: Tom de Leeuw
        Website: https://systom.dev
        Module: TenantReports
 
        SECURITY FEATURES:
        - Secure disposal of SecureString objects
        - Variable clearing across different scopes
        - Connection parameter cleanup
 
    .LINK
        https://systom.dev
    #>


    [CmdletBinding()]
    [OutputType([System.Management.Automation.PSObject])]
    param(
        [Parameter()]
        [SecureString[]]$SecureStrings = @(),

        [Parameter()]
        [string[]]$Variables = @(),

        [Parameter()]
        [ValidateSet('Local', 'Script', 'Global')]
        [string]$Scope = 'Local'
    )

    process {
        if ($SecureStrings.Count -gt 0) {
            foreach ($SecureString in $SecureStrings) {
                if ($null -ne $SecureString) {
                    try {
                        $SecureString.Dispose()
                    } catch {
                        Write-Verbose "Failed to dispose SecureString: $($_.Exception.Message)"
                    }
                }
            }
        }

        if ($Variables.Count -gt 0) {
            foreach ($VariableName in $Variables) {
                try {
                    if (Get-Variable -Name $VariableName -Scope $Scope -ErrorAction SilentlyContinue) {
                        $ScopeValue = Get-Variable -Name $VariableName -Scope $Scope -ValueOnly -ErrorAction SilentlyContinue

                        # Handle SecureString variables specifically
                        if ($ScopeValue -is [SecureString]) {
                            $ScopeValue.Dispose()
                        }

                        Remove-Variable -Name $VariableName -Scope $Scope -Force -ErrorAction Stop
                        Write-Verbose "Cleared $Scope variable: $VariableName"
                    }
                } catch {
                    Write-Verbose "Failed to clear variable '$VariableName' from $Scope scope: $($_.Exception.Message)"
                }
            }
        }

        # Clear any lingering connection-related variables from script scope
        $ConnectionVariables = @(
            'AccessToken',
            'GraphHeader',
            'TokenInfo',
            'SecureAccessToken',
            'GetSecureAuthHeader',
            'TokenCache',
            'ConnectionParams',
            'ClientSecret'
        )
        foreach ($ConnVar in $ConnectionVariables) {
            try {
                if (Get-Variable -Name $ConnVar -Scope Script -ErrorAction SilentlyContinue) {
                    $ScriptValue = Get-Variable -Name $ConnVar -Scope Script -ValueOnly -ErrorAction SilentlyContinue

                    # Handle SecureString variables specifically
                    if ($ScriptValue -is [SecureString]) {
                        $ScriptValue.Dispose()
                    }

                    Remove-Variable -Name $ConnVar -Scope Script -Force -ErrorAction Stop
                    Write-Verbose "Cleared script-level connection variable: $ConnVar"
                }
            } catch {
                Write-Verbose "Could not clear script-level variable '$ConnVar': $($_.Exception.Message)"
            }
        }
    }
}