Public/AzStackHci.PageFileSettings.ps1

# ///////////////////////////////////////////////////////////////////
# Strict Mode v1 (PS 5.1 safe) - surfaces reads of uninitialised variables at runtime.
Set-StrictMode -Version 1.0

# Get-AzStackHciPageFileSettings Function
# Used to get information about the current page file settings
# on the system.
# ///////////////////////////////////////////////////////////////////
Function Get-AzStackHciPageFileSettings {
    <#
    .SYNOPSIS
 
    Gets current page file settings
 
    .DESCRIPTION
 
    Queries the system for current page file settings.
    Use -Scope Cluster to collect settings from all nodes in the failover cluster.
 
    #>


    [CmdletBinding()]
    [OutputType([PSCustomObject[]])]
    param (
        # Scope: 'Node' (default) for local node only, 'Cluster' to collect from all cluster nodes
        [Parameter(Mandatory=$false)]
        [ValidateSet('Node','Cluster')]
        [string]$Scope = 'Node',

        [switch]$NoOutput
    )

    begin {
        # Requires administrator permissions to get page file settings and write to log file to disk
        if (-not (Test-Elevation)) { throw "This script must be run as an Administrator." }

        $DateFormatted = Get-Date -f "yyyyMMdd-HHmm"
        if(-not(Test-Path "C:\ProgramData\AzStackHci.DiagnosticSettings\"))
        {
            try {
                New-Item "C:\ProgramData\AzStackHci.DiagnosticSettings\" -ItemType Directory -ErrorAction Stop | Out-Null
            } catch {
                Throw "Failed to create output directory 'C:\ProgramData\AzStackHci.DiagnosticSettings\': $($_.Exception.Message)"
            }
        }
    }

    process {
        # Reset SilentMode at entry — ensures clean state even if a prior call threw while -NoOutput was active
        $script:SilentMode = $false

        # Handle -NoOutput: suppress all console output
        if ($NoOutput.IsPresent) {
            $script:SilentMode = $true
            $VerbosePreference = 'SilentlyContinue'
            $DebugPreference = 'SilentlyContinue'
        }

        # ---------------------------------------------------------------
        # Cluster scope: fan out to all cluster nodes via Invoke-Command
        # ---------------------------------------------------------------
        if ($Scope -eq 'Cluster') {
            if (-not (Test-CommandExists Get-Cluster)) {
                throw "The Get-Cluster cmdlet is not available. Please run this function on a clustered node."
            }
            try {
                [string]$ClusterName = (Get-Cluster -ErrorAction Stop).Name
                [array]$Nodes = Get-ClusterNode | Select-Object -ExpandProperty Name -ErrorAction Stop
            } catch {
                throw "Failed to enumerate cluster nodes. Error: $($_.Exception.Message)"
            }

            Write-Verbose "Cluster '$ClusterName' detected with $($Nodes.Count) node(s): $($Nodes -join ', ')" -Verbose

            # Self-contained scriptblock — does NOT depend on the module being installed on remote nodes
            $remoteResults = Invoke-Command -ComputerName $Nodes -ScriptBlock {
                $result = [PSCustomObject]@{ Node = $env:COMPUTERNAME; Success = $false; Error = $null }
                try {
                    $DateFormatted = Get-Date -f 'yyyyMMdd-HHmm'
                    $BackupDir = 'C:\ProgramData\AzStackHci.DiagnosticSettings'
                    if (-not (Test-Path $BackupDir)) { New-Item $BackupDir -ItemType Directory -Force | Out-Null }
                    $BackupFile = "$BackupDir\PageFile_Settings_$DateFormatted.json"

                    [bool]$PageFileAutoManaged = (Get-CimInstance Win32_ComputerSystem).AutomaticManagedPagefile

                    $PageFileConfig = $null
                    if ($PageFileAutoManaged -eq $false) {
                        $pfSetting = Get-CimInstance -ClassName Win32_PageFileSetting
                        if ($pfSetting) {
                            $PageFileConfig = @{
                                Name = $pfSetting.Name
                                InitialSize = $pfSetting.InitialSize
                                MaximumSize = $pfSetting.MaximumSize
                                Caption = $pfSetting.Caption
                                Description = $pfSetting.Description
                                SettingID = $pfSetting.SettingID
                            }
                        }
                    }

                    $PageFileUsage = Get-CimInstance Win32_PageFileUsage
                    $backupObject = [PSCustomObject]@{
                        BackupDate = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                        Node = $env:COMPUTERNAME
                        PageFileAutoManaged = $PageFileAutoManaged
                        PageFileConfig = $PageFileConfig
                        PageFileUsage = @{
                            AllocatedBaseSize = $PageFileUsage.AllocatedBaseSize
                            CurrentUsage = $PageFileUsage.CurrentUsage
                            PeakUsage = $PageFileUsage.PeakUsage
                            Name = $PageFileUsage.Name
                        }
                    }
                    [System.IO.File]::WriteAllText($BackupFile, ($backupObject | ConvertTo-Json -Depth 3), (New-Object System.Text.UTF8Encoding($false)))

                    $result.Success = $true
                    $result | Add-Member -NotePropertyName PageFileAutoManaged      -NotePropertyValue $PageFileAutoManaged
                    $result | Add-Member -NotePropertyName PageFileName             -NotePropertyValue $(if ($PageFileConfig) { $PageFileConfig.Name } else { $null })
                    $result | Add-Member -NotePropertyName PageFileInitialSize      -NotePropertyValue $(if ($PageFileConfig) { $PageFileConfig.InitialSize } else { $null })
                    $result | Add-Member -NotePropertyName PageFileMaximumSize      -NotePropertyValue $(if ($PageFileConfig) { $PageFileConfig.MaximumSize } else { $null })
                    $result | Add-Member -NotePropertyName PageFileAllocatedBaseSize -NotePropertyValue $PageFileUsage.AllocatedBaseSize
                    $result | Add-Member -NotePropertyName PageFileCurrentUsage     -NotePropertyValue $PageFileUsage.CurrentUsage
                    $result | Add-Member -NotePropertyName PageFilePeakUsage        -NotePropertyValue $PageFileUsage.PeakUsage
                } catch {
                    $result.Error = $_.Exception.Message
                }
                $result
            } -ErrorAction SilentlyContinue -ErrorVariable remoteErrors

            # Report per-node results
            if ($remoteErrors) {
                foreach ($err in $remoteErrors) {
                    Write-Verbose "REMOTE ERROR: $($err.Exception.Message)" -Verbose
                }
            }
            $successCount = 0
            $failCount = 0
            foreach ($nodeResult in $remoteResults) {
                if ($nodeResult.Success) {
                    Write-Verbose " $($nodeResult.Node): SUCCESS - backup file created" -Verbose
                    $successCount++
                } else {
                    Write-Verbose " $($nodeResult.Node): FAILED - $($nodeResult.Error)" -Verbose
                    $failCount++
                }
            }
            Write-Verbose "Cluster collection complete: $successCount succeeded, $failCount failed out of $($Nodes.Count) nodes." -Verbose
            if ($failCount -gt 0) {
                Write-Warning "$failCount node(s) failed. Review the output above for details."
            }

            # Build PSCustomObject array with settings from all nodes
            $outputObjects = foreach ($nodeResult in $remoteResults) {
                [PSCustomObject]@{
                    Node                      = $nodeResult.Node
                    Success                   = $nodeResult.Success
                    PageFileAutoManaged       = $nodeResult.PageFileAutoManaged
                    PageFileName              = $nodeResult.PageFileName
                    PageFileInitialSize       = $nodeResult.PageFileInitialSize
                    PageFileMaximumSize       = $nodeResult.PageFileMaximumSize
                    PageFileAllocatedBaseSize  = $nodeResult.PageFileAllocatedBaseSize
                    PageFileCurrentUsage      = $nodeResult.PageFileCurrentUsage
                    PageFilePeakUsage         = $nodeResult.PageFilePeakUsage
                    Error                     = $nodeResult.Error
                }
            }
            return $outputObjects
        }

        try {
            # Get current page file settings
            [bool]$script:PageFileAutoManaged = (Get-CimInstance Win32_ComputerSystem).AutomaticManagedPagefile
        } catch {
            Write-Verbose "Failed to get current page file settings. Error: $($_.Exception.Message)" -Verbose
            Throw "Failed to get current page file settings. Error: $($_.Exception.Message)"
        }

        # Collect page file configuration
        $pfConfig = $null
        if (-not $script:PageFileAutoManaged) {
            Write-Verbose "Current Settings: Page File automatic management is Disabled" -Verbose
            try { $script:PageFileConfiguration = Get-CimInstance -ClassName Win32_PageFileSetting } catch { throw "Failed to get page file settings: $($_.Exception.Message)" }
            if ($script:PageFileConfiguration) {
                $pfConfig = @{
                    Name = $script:PageFileConfiguration.Name
                    InitialSize = $script:PageFileConfiguration.InitialSize
                    MaximumSize = $script:PageFileConfiguration.MaximumSize
                    Caption = $script:PageFileConfiguration.Caption
                    Description = $script:PageFileConfiguration.Description
                    SettingID = $script:PageFileConfiguration.SettingID
                }
                Write-Verbose " Name: $($pfConfig.Name), InitialSize: $($pfConfig.InitialSize), MaximumSize: $($pfConfig.MaximumSize)" -Verbose
            }
        } else {
            Write-Verbose "Current Settings: Page File automatic management is Enabled" -Verbose
        }

        # Collect page file usage
        try { $script:PageFileUsage = Get-CimInstance Win32_PageFileUsage } catch { throw "Failed to get page file usage: $($_.Exception.Message)" }
        $script:PageFileAllocatedBaseSize = $PageFileUsage.AllocatedBaseSize
        $script:PageFileCurrentUsage = $PageFileUsage.CurrentUsage
        $script:PageFilePeakUsage = $PageFileUsage.PeakUsage
        Write-Verbose "Page File usage: AllocatedBaseSize=$($script:PageFileAllocatedBaseSize), CurrentUsage=$($script:PageFileCurrentUsage), PeakUsage=$($script:PageFilePeakUsage)" -Verbose

        # Save backup as JSON
        $backupObject = [PSCustomObject]@{
            BackupDate = (Get-Date -Format "yyyy-MM-dd HH:mm:ss")
            Node = $env:COMPUTERNAME
            PageFileAutoManaged = $script:PageFileAutoManaged
            PageFileConfig = $pfConfig
            PageFileUsage = @{
                AllocatedBaseSize = $PageFileUsage.AllocatedBaseSize
                CurrentUsage = $PageFileUsage.CurrentUsage
                PeakUsage = $PageFileUsage.PeakUsage
                Name = $PageFileUsage.Name
            }
        }
        $BackupFile = "C:\ProgramData\AzStackHci.DiagnosticSettings\PageFile_Settings_$DateFormatted.json"
        [System.IO.File]::WriteAllText($BackupFile, ($backupObject | ConvertTo-Json -Depth 3), (New-Object System.Text.UTF8Encoding($false)))
        Write-Verbose "Current Page File settings exported to '$BackupFile'" -Verbose

        Write-HostAzS `n

        # Return a PSCustomObject for easy reporting
        [PSCustomObject]@{
            Node                     = $env:COMPUTERNAME
            Success                  = $true
            PageFileAutoManaged      = $script:PageFileAutoManaged
            PageFileName             = if ($script:PageFileConfiguration) { $script:PageFileConfiguration.Name } else { $null }
            PageFileInitialSize      = if ($script:PageFileConfiguration) { $script:PageFileConfiguration.InitialSize } else { $null }
            PageFileMaximumSize      = if ($script:PageFileConfiguration) { $script:PageFileConfiguration.MaximumSize } else { $null }
            PageFileAllocatedBaseSize = $script:PageFileAllocatedBaseSize
            PageFileCurrentUsage     = $script:PageFileCurrentUsage
            PageFilePeakUsage        = $script:PageFilePeakUsage
            Error                    = $null
        }

    } # End of process block

    end {
        if ($NoOutput.IsPresent) { $script:SilentMode = $false }
        Write-Debug "Completed Get-AzStackHciPageFileSettings function"
    }
} # End of Get-AzStackHciPageFileSettings


# ///////////////////////////////////////////////////////////////////
# Set-AzStackHciPageFileSettings Function
# Used to set a manual page file on the system with a specified size,
# or auto-sized for kernel dump support.
# ///////////////////////////////////////////////////////////////////
Function Set-AzStackHciPageFileSettings {
    <#
    .SYNOPSIS
 
    Sets page file settings to a specified size or auto-sizes for kernel dump support
 
    .DESCRIPTION
 
    Configures a fixed-size manual page file, disabling automatic page file management.
 
    Use -KernelDumpRecommended to auto-size the page file based on system memory, using the same
    calculation as Set-AzStackHciMemoryDumpSettings (64 GiB for <768 GB RAM, 128 GiB for >=768 GB RAM).
    This ensures the page file is large enough to stage a kernel memory dump.
 
    Or specify -InitialSizeMB and -MaximumSizeMB for explicit sizing.
 
    Use -Scope Cluster to apply settings to all nodes in the failover cluster via Invoke-Command.
    The scriptblock is self-contained and does not require the module on remote nodes.
 
    Reference: https://learn.microsoft.com/en-us/windows-server/administration/server-core/server-core-memory-dump
    #>


    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
    [OutputType([PSCustomObject[]])]
    param (
        # Path to drive letter for PageFile
        [Parameter(Mandatory=$true, Position=1)]
        [ValidateScript({Test-Path $_})]
        [String]
        [ValidatePattern('^[C-Zc-z]:\\?$')]$PageFileFileDriveLetter,

        # Auto-size for kernel dump support (uses same calculation as Set-AzStackHciMemoryDumpSettings)
        [Parameter(Mandatory=$true, ParameterSetName='KernelDumpRecommended')]
        [Switch]
        $KernelDumpRecommended,

        # Initial page file size in MB (manual sizing)
        [Parameter(Mandatory=$true, ParameterSetName='ManualSize')]
        [ValidateRange(1024, 262144)]
        [uint32]$InitialSizeMB,

        # Maximum page file size in MB (manual sizing)
        [Parameter(Mandatory=$true, ParameterSetName='ManualSize')]
        [ValidateRange(1024, 262144)]
        [uint32]$MaximumSizeMB,

        # Scope: 'Node' (default) for local node only, 'Cluster' to apply to all cluster nodes
        [Parameter(Mandatory=$false)]
        [ValidateSet('Node','Cluster')]
        [string]$Scope = 'Node',

        [Parameter(Mandatory=$false, HelpMessage="Optional switch to prevent console output from the function.")]
        [switch]$NoOutput
    )

    begin {
        if (-not (Test-Elevation)) { throw "This script must be run as an Administrator." }

        # Backup current page file settings (skip in Cluster mode — each node backs up inline)
        if ($Scope -ne 'Cluster') {
            $null = Get-AzStackHciPageFileSettings
        }
    }

    process {
        # Reset SilentMode at entry — ensures clean state even if a prior call threw while -NoOutput was active
        $script:SilentMode = $false

        if ($NoOutput.IsPresent) {
            $script:SilentMode = $true
            $VerbosePreference = 'SilentlyContinue'
            $DebugPreference = 'SilentlyContinue'
        }

        # Determine target page file size
        if ($PSCmdlet.ParameterSetName -eq 'KernelDumpRecommended') {
            # Use same calculation as Set-AzStackHciMemoryDumpSettings / SetDedicatedDumpFileSize
            [uint32]$TargetSizeMB = SetDedicatedDumpFileSize
            if (-not $TargetSizeMB) { throw "Failed to calculate recommended page file size based on system memory." }
            $InitialSizeMB = $TargetSizeMB
            $MaximumSizeMB = $TargetSizeMB
        }

        if ($MaximumSizeMB -lt $InitialSizeMB) {
            throw "-MaximumSizeMB ($MaximumSizeMB) must be greater than or equal to -InitialSizeMB ($InitialSizeMB)."
        }

        $targetSizeGiB = [math]::Round($MaximumSizeMB / 1024, 1)

        # ---------------------------------------------------------------
        # Cluster scope: fan out to all cluster nodes via Invoke-Command
        # ---------------------------------------------------------------
        if ($Scope -eq 'Cluster') {
            if (-not (Test-CommandExists Get-Cluster)) {
                throw "The Get-Cluster cmdlet is not available. Please run this function on a clustered node."
            }
            try {
                [string]$ClusterName = (Get-Cluster -ErrorAction Stop).Name
                [array]$Nodes = Get-ClusterNode | Select-Object -ExpandProperty Name -ErrorAction Stop
            } catch {
                throw "Failed to enumerate cluster nodes. Error: $($_.Exception.Message)"
            }

            Write-Verbose "Cluster '$ClusterName' detected with $($Nodes.Count) node(s): $($Nodes -join ', ')" -Verbose

            $sizeDescription = if ($PSCmdlet.ParameterSetName -eq 'KernelDumpRecommended') {
                "Set kernel-dump-recommended page file (${targetSizeGiB} GiB) on $($Nodes.Count) cluster nodes"
            } else {
                "Set manual page file (Initial: ${InitialSizeMB} MB, Max: ${MaximumSizeMB} MB) on $($Nodes.Count) cluster nodes"
            }
            if (-not $PSCmdlet.ShouldProcess("Cluster '$ClusterName' ($($Nodes -join ', '))", $sizeDescription)) {
                return
            }

            $remoteArgs = @{
                DriveLetter    = $PageFileFileDriveLetter
                InitialSizeMB  = if ($PSCmdlet.ParameterSetName -eq 'KernelDumpRecommended') { 0 } else { $InitialSizeMB }
                MaximumSizeMB  = if ($PSCmdlet.ParameterSetName -eq 'KernelDumpRecommended') { 0 } else { $MaximumSizeMB }
                AutoSize       = ($PSCmdlet.ParameterSetName -eq 'KernelDumpRecommended')
            }

            $remoteResults = Invoke-Command -ComputerName $Nodes -ScriptBlock {
                param($Params)
                $result = [PSCustomObject]@{ Node = $env:COMPUTERNAME; Success = $false; Action = $null; PageFileSizeMB = 0; Error = $null }
                try {
                    $DriveLetter = $Params.DriveLetter
                    if ($DriveLetter.Length -eq 2) { $DriveLetter = "$DriveLetter\" }

                    # Calculate size if auto-sizing
                    # Tiers: <=128 GiB → 32 GiB, 129-767 GiB → 64 GiB, >=768 GiB → 128 GiB
                    if ($Params.AutoSize) {
                        $totalPhysicalMemory = (Get-CimInstance -ClassName Win32_PhysicalMemory -ErrorAction Stop | Measure-Object -Property Capacity -Sum).Sum
                        [uint32]$InitSize = if ($totalPhysicalMemory -ge 768GB) { 131072 } elseif ($totalPhysicalMemory -le 128GB) { 32768 } else { 65536 }
                        [uint32]$MaxSize = $InitSize
                    } else {
                        [uint32]$InitSize = $Params.InitialSizeMB
                        [uint32]$MaxSize = $Params.MaximumSizeMB
                    }

                    # Get auto-managed state BEFORE the "already configured" check
                    $PageFileAutoManaged = (Get-CimInstance Win32_ComputerSystem -ErrorAction Stop).AutomaticManagedPagefile

                    # Check if current settings already match the target
                    $pfConfig = Get-CimInstance -ClassName Win32_PageFileSetting -ErrorAction SilentlyContinue
                    if (-not $PageFileAutoManaged -and
                        $pfConfig -and
                        ($pfConfig | Measure-Object).Count -eq 1 -and
                        $pfConfig.Name -eq "${DriveLetter}pagefile.sys" -and
                        $pfConfig.InitialSize -eq $InitSize -and
                        $pfConfig.MaximumSize -eq $MaxSize) {
                        $result.Success = $true
                        $result.Action = 'NoChangeRequired'
                        $result.PageFileSizeMB = $MaxSize
                        return $result
                    }

                    # Backup current settings (PageFileAutoManaged already queried above)
                    $BackupDir = 'C:\ProgramData\AzStackHci.DiagnosticSettings'
                    if (-not (Test-Path $BackupDir)) { New-Item $BackupDir -ItemType Directory -Force | Out-Null }
                    $DateFormatted = Get-Date -f 'yyyyMMdd-HHmm'
                    $BackupFile = "$BackupDir\PageFile_Settings_$DateFormatted.json"
                    $pfConfig = $null
                    if (-not $PageFileAutoManaged) {
                        $pfSetting = Get-CimInstance -ClassName Win32_PageFileSetting -ErrorAction SilentlyContinue
                        if ($pfSetting) {
                            $pfConfig = @{
                                Name = $pfSetting.Name
                                InitialSize = $pfSetting.InitialSize
                                MaximumSize = $pfSetting.MaximumSize
                                Caption = $pfSetting.Caption
                                Description = $pfSetting.Description
                                SettingID = $pfSetting.SettingID
                            }
                        }
                    }
                    $pfUsage = Get-CimInstance Win32_PageFileUsage -ErrorAction SilentlyContinue
                    $backupObject = [PSCustomObject]@{
                        BackupDate = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                        Node = $env:COMPUTERNAME
                        PageFileAutoManaged = $PageFileAutoManaged
                        PageFileConfig = $pfConfig
                        PageFileUsage = @{
                            AllocatedBaseSize = if ($pfUsage) { $pfUsage.AllocatedBaseSize } else { $null }
                            CurrentUsage = if ($pfUsage) { $pfUsage.CurrentUsage } else { $null }
                            PeakUsage = if ($pfUsage) { $pfUsage.PeakUsage } else { $null }
                            Name = if ($pfUsage) { $pfUsage.Name } else { $null }
                        }
                    }
                    [System.IO.File]::WriteAllText($BackupFile, ($backupObject | ConvertTo-Json -Depth 3), (New-Object System.Text.UTF8Encoding($false)))

                    # Check disk space: page file needs InitSize MB on the drive
                    $Disk = Get-PSDrive -ErrorAction Stop | Where-Object { $_.Root -eq $DriveLetter }
                    if (-not $Disk) { throw "Drive '$DriveLetter' not found on $env:COMPUTERNAME." }
                    $currentPfUsage = Get-CimInstance Win32_PageFileUsage -ErrorAction SilentlyContinue | Where-Object { $_.Name -like "$($DriveLetter.TrimEnd('\'))\*" }
                    $currentPfSizeMB = if ($currentPfUsage) { $currentPfUsage.AllocatedBaseSize } else { 0 }
                    # Net new space = target size - current page file size (if on same drive)
                    $netNewMB = [math]::Max(0, $MaxSize - $currentPfSizeMB)
                    $freeGiB = [math]::Round($Disk.Free / 1GB, 2)
                    $neededGiB = [math]::Round($netNewMB / 1024 + 10, 1)  # +10 GiB OS margin
                    if ($freeGiB -lt $neededGiB) {
                        throw "Insufficient disk space on $DriveLetter for ${MaxSize} MB page file. Free: ${freeGiB} GiB, Needed: ${neededGiB} GiB."
                    }

                    # Disable auto-management if enabled
                    if ($PageFileAutoManaged) {
                        $cs = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction Stop
                        $cs | Set-CimInstance -Property @{ AutomaticManagedPagefile = $false } -ErrorAction Stop
                    }

                    # Remove existing page file config
                    $pfConfig = Get-CimInstance -ClassName Win32_PageFileSetting -ErrorAction SilentlyContinue
                    if ($pfConfig) { $pfConfig | Remove-CimInstance -ErrorAction Stop }

                    # Create new page file
                    $newPf = New-CimInstance -ClassName Win32_PageFileSetting -Property @{ Name = "${DriveLetter}pagefile.sys" } -ErrorAction Stop
                    $newPf | Set-CimInstance -Property @{ InitialSize = $InitSize; MaximumSize = $MaxSize } -ErrorAction Stop

                    $result.PageFileSizeMB = $MaxSize
                    $result.Success = $true
                } catch {
                    $result.Error = $_.Exception.Message
                }
                $result
            } -ArgumentList (,$remoteArgs) -ErrorAction SilentlyContinue -ErrorVariable remoteErrors

            if ($remoteErrors) { foreach ($err in $remoteErrors) { Write-Verbose "REMOTE ERROR: $($err.Exception.Message)" -Verbose } }
            $successCount = 0; $failCount = 0; $noChangeCount = 0
            foreach ($nodeResult in $remoteResults) {
                if ($nodeResult.Success -and $nodeResult.Action -eq 'NoChangeRequired') {
                    Write-Verbose " $($nodeResult.Node): Already configured ($($nodeResult.PageFileSizeMB) MB) — no changes needed" -Verbose
                    $noChangeCount++; $successCount++
                } elseif ($nodeResult.Success) { Write-Verbose " $($nodeResult.Node): SUCCESS ($($nodeResult.PageFileSizeMB) MB)" -Verbose; $successCount++ }
                else { Write-Verbose " $($nodeResult.Node): FAILED - $($nodeResult.Error)" -Verbose; $failCount++ }
            }
            Write-Verbose "Cluster operation complete: $successCount succeeded, $failCount failed out of $($Nodes.Count) nodes." -Verbose
            if ($failCount -gt 0) { Write-Warning "$failCount node(s) failed. Review the output above for details." }
            return $remoteResults
        }

        # ---------------------------------------------------------------
        # Node scope: set manual page file on local node
        # ---------------------------------------------------------------

        # Normalize drive letter
        if ($PageFileFileDriveLetter.Length -eq 2) { $PageFileFileDriveLetter = "$PageFileFileDriveLetter\" }

        # Check if current settings already match the target
        $dumpDrive = $PageFileFileDriveLetter.TrimEnd('\')
        [bool]$PageFileAutoManaged = (Get-CimInstance Win32_ComputerSystem -ErrorAction Stop).AutomaticManagedPagefile
        $currentPfConfig = Get-CimInstance -ClassName Win32_PageFileSetting -ErrorAction SilentlyContinue
        $currentPfUsage = Get-CimInstance Win32_PageFileUsage -ErrorAction SilentlyContinue | Where-Object { $_.Name -like "${dumpDrive}\*" }
        $currentPfSizeMB = if ($currentPfUsage) { $currentPfUsage.AllocatedBaseSize } else { 0 }

        if (-not $PageFileAutoManaged -and
            $currentPfConfig -and
            ($currentPfConfig | Measure-Object).Count -eq 1 -and
            $currentPfConfig.Name -eq "${PageFileFileDriveLetter}pagefile.sys" -and
            $currentPfConfig.InitialSize -eq $InitialSizeMB -and
            $currentPfConfig.MaximumSize -eq $MaximumSizeMB) {
            Write-Verbose "Page file is already configured as requested: ${PageFileFileDriveLetter}pagefile.sys (Initial: ${InitialSizeMB} MB, Max: ${MaximumSizeMB} MB). No changes needed." -Verbose
            return [PSCustomObject]@{
                Node = $env:COMPUTERNAME
                Success = $true
                Action = 'NoChangeRequired'
                InitialSizeMB = $InitialSizeMB
                MaximumSizeMB = $MaximumSizeMB
                PreviousAutoManaged = $false
                Error = $null
            }
        }

        # Check disk space
        $Disk = Get-PSDrive -ErrorAction Stop | Where-Object { $_.Root -eq $PageFileFileDriveLetter }
        if (-not $Disk) { throw "Drive '$PageFileFileDriveLetter' not found." }
        $netNewMB = [math]::Max(0, $MaximumSizeMB - $currentPfSizeMB)
        $freeGiB = [math]::Round($Disk.Free / 1GB, 2)
        $neededGiB = [math]::Round($netNewMB / 1024 + 10, 1)
        if ($freeGiB -lt $neededGiB) {
            throw "Insufficient disk space on '$PageFileFileDriveLetter' for ${MaximumSizeMB} MB page file. Free: ${freeGiB} GiB, Needed: ~${neededGiB} GiB (${netNewMB} MB net new + 10 GiB OS margin). Current page file on this drive: ${currentPfSizeMB} MB."
        }

        # ShouldProcess gate
        $actionDescription = if ($PSCmdlet.ParameterSetName -eq 'KernelDumpRecommended') {
            "Set kernel-dump-recommended manual page file (${InitialSizeMB} MB / ${targetSizeGiB} GiB) on ${PageFileFileDriveLetter}"
        } else {
            "Set manual page file (Initial: ${InitialSizeMB} MB, Max: ${MaximumSizeMB} MB) on ${PageFileFileDriveLetter}"
        }
        if (-not $PSCmdlet.ShouldProcess("Page file on $PageFileFileDriveLetter", $actionDescription)) {
            return
        }

        # Disable auto-management if enabled (already queried above)
        if ($PageFileAutoManaged) {
            Write-Verbose "Disabling automatic page file management..." -Verbose
            $cs = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction Stop
            $cs | Set-CimInstance -Property @{ AutomaticManagedPagefile = $false } -ErrorAction Stop
            Write-Verbose "Automatic page file management disabled." -Verbose
        }

        # Remove existing page file config
        $pfConfig = Get-CimInstance -ClassName Win32_PageFileSetting -ErrorAction SilentlyContinue
        if ($pfConfig) {
            if (($pfConfig | Measure-Object).Count -eq 1) {
                $pfConfig | Remove-CimInstance -ErrorAction Stop
                Write-Verbose "Existing page file settings removed." -Verbose
            } else {
                throw "Unexpected: more than one page file configured (found $(($pfConfig | Measure-Object).Count)). Remove extra page files manually first."
            }
        }

        # Create new page file with specified size
        try {
            $PageFile = New-CimInstance -ClassName Win32_PageFileSetting -Property @{ Name = "${PageFileFileDriveLetter}pagefile.sys" } -ErrorAction Stop
            $PageFile | Set-CimInstance -Property @{ InitialSize = $InitialSizeMB; MaximumSize = $MaximumSizeMB } -ErrorAction Stop
        } catch {
            throw "Failed to create page file with InitialSize=${InitialSizeMB} MB, MaximumSize=${MaximumSizeMB} MB. Error: $($_.Exception.Message)"
        }

        if (-not $PageFile) { throw "Failed to configure page file." }

        Write-Verbose "Page file configured: ${PageFileFileDriveLetter}pagefile.sys (InitialSize: ${InitialSizeMB} MB, MaximumSize: ${MaximumSizeMB} MB / ${targetSizeGiB} GiB)" -Verbose
        Write-Verbose "Automatic page file management has been disabled." -Verbose
        Write-Verbose "A system restart is required for page file changes to take effect." -Verbose

        [PSCustomObject]@{
            Node = $env:COMPUTERNAME
            Success = $true
            Action = if ($PSCmdlet.ParameterSetName -eq 'KernelDumpRecommended') { 'SetPageFileKernelDumpRecommended' } else { 'SetPageFileManual' }
            InitialSizeMB = $InitialSizeMB
            MaximumSizeMB = $MaximumSizeMB
            PreviousAutoManaged = $PageFileAutoManaged
            Error = $null
        }

    } # End of process block

    end {
        if ($NoOutput.IsPresent) { $script:SilentMode = $false }
        Write-Debug "Completed Set-AzStackHciPageFileSettings function"
    }

} # End of Set-AzStackHciPageFileSettings


# ///////////////////////////////////////////////////////////////////
# Set-AzStackHciPageFileSettingsMinimal Function
# Used to set a static 4GB page file on the system, target drive is
# the only parameter.
# ///////////////////////////////////////////////////////////////////
Function Set-AzStackHciPageFileSettingsMinimal {
    <#
    .SYNOPSIS
 
    Sets page file settings to minimum 4GB fixed size
 
    .DESCRIPTION
 
    Queries the system for current page file settings and sets a fixed 4GB page file.
 
    Use -Scope Cluster to apply settings to all nodes in the failover cluster via Invoke-Command.
    The scriptblock is self-contained and does not require the module on remote nodes.
 
    #>


    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
    [OutputType([PSCustomObject[]])]
    param (
        # Path to drive letter for PageFile
        [Parameter(Mandatory=$true,Position=1)]
        [ValidateScript({Test-Path $_})]
        [String]
        [ValidatePattern('^[C-Zc-z]:\\?$')]$PageFileFileDriveLetter, # Drive letter for the page file, must be a valid drive letter (C: through Z:)

        # Scope: 'Node' (default) for local node only, 'Cluster' to apply to all cluster nodes
        [Parameter(Mandatory=$false)]
        [ValidateSet('Node','Cluster')]
        [string]$Scope = 'Node',

        [Parameter(Mandatory=$false, HelpMessage="Optional switch to prevent console output from the function.")]
        [switch]$NoOutput
    )

    begin {
        # Requires administrator permissions to set page file settings
        if (-not (Test-Elevation)) { throw "This script must be run as an Administrator." }

        # Call function to get current Page File settings and save to backup log file (skip in Cluster mode — each node backs up inline)
        if ($Scope -ne 'Cluster') {
            $null = Get-AzStackHciPageFileSettings
        }
    }

    process {
        # Reset SilentMode at entry — ensures clean state even if a prior call threw while -NoOutput was active
        $script:SilentMode = $false

        # Handle -NoOutput: suppress all console output
        if ($NoOutput.IsPresent) {
            $script:SilentMode = $true
            $VerbosePreference = 'SilentlyContinue'
            $DebugPreference = 'SilentlyContinue'
        }

        # ---------------------------------------------------------------
        # Cluster scope: fan out to all cluster nodes via Invoke-Command
        # ---------------------------------------------------------------
        if ($Scope -eq 'Cluster') {
            if (-not (Test-CommandExists Get-Cluster)) {
                throw "The Get-Cluster cmdlet is not available. Please run this function on a clustered node."
            }
            try {
                [string]$ClusterName = (Get-Cluster -ErrorAction Stop).Name
                [array]$Nodes = Get-ClusterNode | Select-Object -ExpandProperty Name -ErrorAction Stop
            } catch {
                throw "Failed to enumerate cluster nodes. Error: $($_.Exception.Message)"
            }

            Write-Verbose "Cluster '$ClusterName' detected with $($Nodes.Count) node(s): $($Nodes -join ', ')" -Verbose

            if (-not $PSCmdlet.ShouldProcess("Cluster '$ClusterName' ($($Nodes -join ', '))", "Set fixed 4GB page file on $($Nodes.Count) cluster nodes")) {
                return
            }

            $remoteDriveLetter = $PageFileFileDriveLetter

            # Self-contained scriptblock — does NOT depend on the module being installed on remote nodes
            $remoteResults = Invoke-Command -ComputerName $Nodes -ScriptBlock {
                param($DriveLetter)
                $result = [PSCustomObject]@{ Node = $env:COMPUTERNAME; Success = $false; Error = $null }
                try {
                    # Normalize drive letter
                    if ($DriveLetter.Length -eq 2) { $DriveLetter = "$DriveLetter\" }

                    # ── Inline backup of current page file settings ──
                    $BackupDir = 'C:\ProgramData\AzStackHci.DiagnosticSettings'
                    if (-not (Test-Path $BackupDir)) { New-Item $BackupDir -ItemType Directory -Force | Out-Null }
                    $DateFormatted = Get-Date -f 'yyyyMMdd-HHmm'
                    $BackupFile = "$BackupDir\PageFile_Settings_$DateFormatted.json"
                    $PageFileAutoManaged = (Get-CimInstance Win32_ComputerSystem -ErrorAction Stop).AutomaticManagedPagefile

                    $pfConfigBackup = $null
                    if (-not $PageFileAutoManaged) {
                        $pfSetting = Get-CimInstance -ClassName Win32_PageFileSetting -ErrorAction SilentlyContinue
                        if ($pfSetting) {
                            $pfConfigBackup = @{
                                Name = $pfSetting.Name
                                InitialSize = $pfSetting.InitialSize
                                MaximumSize = $pfSetting.MaximumSize
                                Caption = $pfSetting.Caption
                                Description = $pfSetting.Description
                                SettingID = $pfSetting.SettingID
                            }
                        }
                    }
                    $pfUsage = Get-CimInstance Win32_PageFileUsage -ErrorAction SilentlyContinue
                    $backupObject = [PSCustomObject]@{
                        BackupDate = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
                        Node = $env:COMPUTERNAME
                        PageFileAutoManaged = $PageFileAutoManaged
                        PageFileConfig = $pfConfigBackup
                        PageFileUsage = @{
                            AllocatedBaseSize = if ($pfUsage) { $pfUsage.AllocatedBaseSize } else { $null }
                            CurrentUsage = if ($pfUsage) { $pfUsage.CurrentUsage } else { $null }
                            PeakUsage = if ($pfUsage) { $pfUsage.PeakUsage } else { $null }
                            Name = if ($pfUsage) { $pfUsage.Name } else { $null }
                        }
                    }
                    [System.IO.File]::WriteAllText($BackupFile, ($backupObject | ConvertTo-Json -Depth 3), (New-Object System.Text.UTF8Encoding($false)))

                    # ── Set 4GB fixed page file ──
                    if (-not $PageFileAutoManaged) {
                        # Manual: remove existing page file config, create 4GB fixed
                        $pfConfig = Get-CimInstance -ClassName Win32_PageFileSetting -ErrorAction SilentlyContinue
                        if ($pfConfig) {
                            if (($pfConfig | Measure-Object).Count -eq 1) {
                                $pfConfig | Remove-CimInstance -ErrorAction Stop
                            } else {
                                throw "Unexpected: more than one page file configured (found $(($pfConfig | Measure-Object).Count))"
                            }
                        }
                        $newPf = New-CimInstance -ClassName Win32_PageFileSetting -Property @{ Name = "${DriveLetter}pagefile.sys" } -ErrorAction Stop
                        $newPf | Set-CimInstance -Property @{ InitialSize = 4096; MaximumSize = 4096 } -ErrorAction Stop
                    } else {
                        # Auto-managed: disable auto management, then create 4GB fixed
                        $cs = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction Stop
                        $cs | Set-CimInstance -Property @{ AutomaticManagedPagefile = $false } -ErrorAction Stop

                        $pfConfig = Get-CimInstance -ClassName Win32_PageFileSetting -ErrorAction SilentlyContinue
                        if ($pfConfig) {
                            if (($pfConfig | Measure-Object).Count -eq 1) {
                                $pfConfig | Remove-CimInstance -ErrorAction Stop
                            } else {
                                throw "Unexpected: more than one page file configured (found $(($pfConfig | Measure-Object).Count))"
                            }
                        }
                        $newPf = New-CimInstance -ClassName Win32_PageFileSetting -Property @{ Name = "${DriveLetter}pagefile.sys" } -ErrorAction Stop
                        $newPf | Set-CimInstance -Property @{ InitialSize = 4096; MaximumSize = 4096 } -ErrorAction Stop
                    }

                    if (-not $newPf) { throw 'Failed to configure page file' }
                    $result.Success = $true
                } catch {
                    $result.Error = $_.Exception.Message
                }
                $result
            } -ArgumentList $remoteDriveLetter -ErrorAction SilentlyContinue -ErrorVariable remoteErrors

            # Report per-node results
            if ($remoteErrors) {
                foreach ($err in $remoteErrors) {
                    Write-Verbose "REMOTE ERROR: $($err.Exception.Message)" -Verbose
                }
            }
            $successCount = 0
            $failCount = 0
            foreach ($nodeResult in $remoteResults) {
                if ($nodeResult.Success) {
                    Write-Verbose " $($nodeResult.Node): SUCCESS" -Verbose
                    $successCount++
                } else {
                    Write-Verbose " $($nodeResult.Node): FAILED - $($nodeResult.Error)" -Verbose
                    $failCount++
                }
            }
            Write-Verbose "Cluster operation complete: $successCount succeeded, $failCount failed out of $($Nodes.Count) nodes." -Verbose
            if ($failCount -gt 0) {
                Write-Warning "$failCount node(s) failed. Review the output above for details."
            }
            return $remoteResults
        }

        # if the drive letter is only 2 characters (C:), add a backslash to the end (C:\)
        if($PageFileFileDriveLetter.Length -eq 2){
            $PageFileFileDriveLetter = $($PageFileFileDriveLetter + "\")
        }

        # ShouldProcess gate: prompt user before modifying page file settings
        if (-not $PSCmdlet.ShouldProcess("Page file on $PageFileFileDriveLetter", "Set fixed 4GB page file")) {
            return
        }

        try {
            # Get current page file settings
            [bool]$script:PageFileAutoManaged = (Get-CimInstance Win32_ComputerSystem).AutomaticManagedPagefile
        } catch {
            Write-Verbose "Failed to get current page file settings. Error: $($_.Exception.Message)" -Verbose
            Throw "Failed to get current page file settings. Error: $($_.Exception.Message)"
        }
        
        # If page file is NOT automatically managed
        if($script:PageFileAutoManaged -eq $False){
            # Page File manual settings
            Write-HostAzS "Automatic management of page file already disabled"
            Write-HostAzS "Configuring a fixed page file of 4GB size using file: $($PageFileFileDriveLetter)pagefile.sys`n"
            try {
                $script:PageFileConfiguration = Get-CimInstance -ClassName Win32_PageFileSetting
            } catch {
                Write-Verbose "Failed to get existing page file settings. Error: $($_.Exception.Message)" -Verbose
                Throw "Error: Failed to get existing page file settings. Error: $($_.Exception.Message)"
            }
            # Remove existing manual page file settings
            if($PageFileConfiguration){
                if(($PageFileConfiguration | Measure-Object).Count -eq 1){
                    try {
                        # Delete existing page file settings
                        $PageFileConfiguration | Remove-CimInstance
                    } catch {
                        Write-Verbose "Failed to delete existing page file settings. Error: $($_.Exception.Message)" -Verbose
                        Throw "Error: Failed to delete existing page file settings. Error: $($_.Exception.Message)"
                    }
                    Write-Verbose "Existing page file settings removed." -Verbose
                } else {
                    Write-Verbose "Unexpected configuration, more than one page file is currently configured! Expected 1, but found $(($PageFileConfiguration | Measure-Object).Count) x page files." -Verbose
                    Throw "Error: Unexpected configuration, more than one page file currently configured! Expected 1, but found $(($PageFileConfiguration | Measure-Object).Count) x page files."
                }
            } else {
                Write-Verbose "Existing page file settings not found." -Verbose
            }
            # Set a New page file, and set the size to 4GB fixed
            try 
            {
                # Use New-CimInstance to create a new page file setting, due to "Set-WmiInstance : Generic failure" error, if no existing page file settings are configured (as deleted).
                $PageFile = New-CimInstance -ClassName Win32_PageFileSetting -Property @{ Name= "$($PageFileFileDriveLetter)pagefile.sys" }
                $PageFile | Set-CimInstance -Property @{ InitialSize = 4096; MaximumSize = 4096 }
            } catch {
                Write-Verbose "Failed to set minimum page file settings. Error: $($_.Exception.Message)" -Verbose
                Throw "Failed to set minimum page file settings. Error: $($_.Exception.Message)"
            }
            if($PageFile){
                Write-Verbose "Page File settings updated successfully to a fixed size of 4GB" -Verbose
                Write-Verbose "Page File: = '$($pagefile.Description)'" -Verbose
            } else {
                Write-Verbose "Failed to configure minimum page file settings." -Verbose
                Throw "Error: Failed to configure minimum page file settings."
            }

            [PSCustomObject]@{ Node = $env:COMPUTERNAME; Success = $true; Action = 'SetMinimumPageFile'; PreviousAutoManaged = $false; Error = $null }

        } elseif($script:PageFileAutoManaged -eq $True){
            # If the page file is currently automatically managed
            Write-HostAzS "Disabling automatic management of page file"
            # Remove System Managed:
            try {
                $ComputerSystem = Get-CimInstance -ClassName Win32_ComputerSystem
            }
            catch {
                Write-Verbose "Failed to get existing automatic management settings. Error: $($_.Exception.Message)" -Verbose
                Throw "Error: Failed to get existing automatic management settings. Error: $($_.Exception.Message)"
            }
            try {
                $ComputerSystem | Set-CimInstance -Property @{ AutomaticManagedPagefile = $false }
            }
            catch {
                Write-Verbose "Failed to disable automatic management of page file. Error: $($_.Exception.Message)" -Verbose
                Throw "Error: Failed to disable automatic management of page file. Error: $($_.Exception.Message)"
            }
            Write-Verbose "Automatic management of page file disabled" -Verbose

            try {
                $script:PageFileConfiguration = Get-CimInstance -ClassName Win32_PageFileSetting
            } catch {
                Write-Verbose "Failed to get existing page file settings. Error: $($_.Exception.Message)" -Verbose
                Throw "Error: Failed to get existing page file settings. Error: $($_.Exception.Message)"
            }

            Write-HostAzS "Configuring a fixed page file of 4GB size using file: $($PageFileFileDriveLetter)pagefile.sys`n"
            # Remove existing page file setting and set a new page file, and set the size to 4GB fixed
            if($PageFileConfiguration){
                if(($PageFileConfiguration | Measure-Object).Count -eq 1){
                    try {
                        # Delete existing page file settings
                        $PageFileConfiguration | Remove-CimInstance
                    } catch {
                        Write-Verbose "Failed to delete existing page file settings. Error: $($_.Exception.Message)" -Verbose
                        Throw "Error: Failed to delete existing page file settings. Error: $($_.Exception.Message)"
                    }
                    Write-Verbose "Existing page file settings removed." -Verbose
                } else {
                    Write-Verbose "Unexpected configuration, more than one page file is currently configured! Expected 1, but found $(($PageFileConfiguration | Measure-Object).Count) x page files." -Verbose
                    Throw "Error: Unexpected configuration, more than one page file currently configured! Expected 1, but found $(($PageFileConfiguration | Measure-Object).Count) x page files."
                }

                # Set a New page file, and set the size to 4GB fixed
                try 
                {
                    # Use New-CimInstance to create a new page file setting, due to "Set-WmiInstance : Generic failure" error, if no existing page file settings are configured (as deleted).
                    $PageFile = New-CimInstance -ClassName Win32_PageFileSetting -Property @{ Name= "$($PageFileFileDriveLetter)pagefile.sys" }
                    $PageFile | Set-CimInstance -Property @{ InitialSize = 4096; MaximumSize = 4096 }
                } catch {
                    Write-Verbose "Failed to set new page file settings. Error: $($_.Exception.Message)" -Verbose
                    Throw "Failed to set new page file settings. Error: $($_.Exception.Message)"
                }
                if($PageFile){
                    Write-Verbose "Page File settings updated successfully to a fixed size of 4GB" -Verbose
                    Write-Verbose "Page File: = '$($pagefile.Description)'" -Verbose
                } else {
                    Write-Verbose "Failed to configure minimum page file settings." -Verbose
                    Throw "Error: Failed to configure minimum page file settings."
                }
                Write-Verbose "Page File settings updated to minimum recommended configuration, (static size of 4GB)." -Verbose

            } # End of If PageFileConfiguration
            
            Write-Verbose "A system restart is required for Page File changes to take effect.`n`n" -Verbose

            [PSCustomObject]@{ Node = $env:COMPUTERNAME; Success = $true; Action = 'SetMinimumPageFile'; PreviousAutoManaged = $true; Error = $null }

        } else {
            Write-Error "Current Settings: Page File automatic management is Unknown (not enabled or disabled)." -Verbose
            Throw "Error: Current Settings: Page File automatic management is Unknown (not enabled or disabled)."
        } # End of If PageFileAutoManaged

    } # End of process block

    end {
        if ($NoOutput.IsPresent) { $script:SilentMode = $false }
        Write-Debug "Completed Set-AzStackHciPageFileSettingsMinimal function"
    }

} # End of Set-AzStackHciPageFileSettingsMinimal


# ///////////////////////////////////////////////////////////////////
# Restore-AzStackHciPageFileSettings function
# Used to restore or roll back page file settings
# ///////////////////////////////////////////////////////////////////
Function Restore-AzStackHciPageFileSettings
{
    <#
    .SYNOPSIS
 
    Restores page file settings from a backup file
 
    .DESCRIPTION
 
    Restores the page file settings from a backup file, using the 'PageFile_Settings_YYYYMMDD.json' file.
    Requires administrator permissions to restore page file settings.
 
    Use -Scope Cluster to restore settings on all nodes in the failover cluster via Invoke-Command.
    In Cluster mode, each node auto-discovers its most recent backup file if no path is specified.
    The scriptblock is self-contained and does not require the module on remote nodes.
     
    #>


    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
    [OutputType([PSCustomObject[]])]
    param (
        # File path to backup file (required for Node scope; optional for Cluster scope where auto-discovery is used)
        [Parameter(Mandatory=$false,Position=0)]
        [ValidateScript({Test-Path $_})]
        [String]$PageFileSettingsFilePath, # File used to restore settings from, must be a valid path

        # Scope: 'Node' (default) for local node only, 'Cluster' to restore on all cluster nodes
        [Parameter(Mandatory=$false)]
        [ValidateSet('Node','Cluster')]
        [string]$Scope = 'Node',

        [Parameter(Mandatory=$false, HelpMessage="Optional switch to prevent console output from the function.")]
        [switch]$NoOutput
    )

    begin {
        # Requires administrator permissions to set page file settings
        if (-not (Test-Elevation)) { throw "This script must be run as an Administrator." }
    }

    process {
        # Reset SilentMode at entry — ensures clean state even if a prior call threw while -NoOutput was active
        $script:SilentMode = $false

        # Handle -NoOutput: suppress all console output
        if ($NoOutput.IsPresent) {
            $script:SilentMode = $true
            $VerbosePreference = 'SilentlyContinue'
            $DebugPreference = 'SilentlyContinue'
        }

        # ---------------------------------------------------------------
        # Cluster scope: fan out to all cluster nodes via Invoke-Command
        # ---------------------------------------------------------------
        if ($Scope -eq 'Cluster') {
            if (-not (Test-CommandExists Get-Cluster)) {
                throw "The Get-Cluster cmdlet is not available. Please run this function on a clustered node."
            }
            try {
                [string]$ClusterName = (Get-Cluster -ErrorAction Stop).Name
                [array]$Nodes = Get-ClusterNode | Select-Object -ExpandProperty Name -ErrorAction Stop
            } catch {
                throw "Failed to enumerate cluster nodes. Error: $($_.Exception.Message)"
            }

            Write-Verbose "Cluster '$ClusterName' detected with $($Nodes.Count) node(s): $($Nodes -join ', ')" -Verbose

            if (-not $PSCmdlet.ShouldProcess("Cluster '$ClusterName' ($($Nodes -join ', '))", "Restore page file settings from backup on $($Nodes.Count) cluster nodes")) {
                return
            }

            # Pass the file path if provided; otherwise each node auto-discovers its latest backup
            $remoteFilePath = if ($PSBoundParameters.ContainsKey('PageFileSettingsFilePath')) { $PageFileSettingsFilePath } else { $null }

            # Self-contained scriptblock — does NOT depend on the module being installed on remote nodes
            $remoteResults = Invoke-Command -ComputerName $Nodes -ScriptBlock {
                param($FilePath)
                $result = [PSCustomObject]@{ Node = $env:COMPUTERNAME; Success = $false; Action = $null; BackupFile = $null; Error = $null }
                try {
                    $BackupDir = 'C:\ProgramData\AzStackHci.DiagnosticSettings'

                    # Auto-discover the most recent backup file if no path was provided
                    if ([string]::IsNullOrEmpty($FilePath)) {
                        $LatestFile = Get-ChildItem "$BackupDir\PageFile_Settings_*.json" -ErrorAction SilentlyContinue |
                            Sort-Object LastWriteTime -Descending | Select-Object -First 1
                        if (-not $LatestFile) { throw "WARNING: No PageFile backup files found in '$BackupDir' on $env:COMPUTERNAME. Run Get-AzStackHciPageFileSettings first." }
                        $FilePath = $LatestFile.FullName
                    }
                    $result.BackupFile = $FilePath

                    # Validate file path
                    if ($FilePath -notlike 'C:\ProgramData\AzStackHci.DiagnosticSettings\PageFile_Settings_*') {
                        throw "Backup file path must match 'C:\ProgramData\AzStackHci.DiagnosticSettings\PageFile_Settings_*'. Got: '$FilePath'"
                    }
                    if (-not (Test-Path $FilePath)) { throw "Backup file not found: '$FilePath'" }

                    $backup = Get-Content $FilePath -Raw -ErrorAction Stop | ConvertFrom-Json
                    $wasAutoManaged = $backup.PageFileAutoManaged
                    $currentPageFileAutoManaged = (Get-CimInstance Win32_ComputerSystem).AutomaticManagedPagefile

                    if ($wasAutoManaged) {
                        # Backup had auto-managed: restore to auto-managed
                        $nameValue = $backup.PageFileUsage.Name
                        if (-not $nameValue) { throw 'Could not find page file Name in backup file' }

                        if ($currentPageFileAutoManaged) {
                            throw 'Page File is already automatically managed, no action required.'
                        }

                        # Remove current manual page file
                        $currentPf = Get-CimInstance -ClassName Win32_PageFileSetting -ErrorAction SilentlyContinue
                        if ($currentPf -and ($currentPf | Measure-Object).Count -eq 1) {
                            $currentPf | Remove-CimInstance -ErrorAction Stop
                        } elseif ($currentPf -and ($currentPf | Measure-Object).Count -gt 1) {
                            throw "Unexpected: $(($currentPf | Measure-Object).Count) page files configured"
                        }

                        # Create with size 0 (system-managed)
                        $pf = New-CimInstance -ClassName Win32_PageFileSetting -Property @{ Name = $nameValue }
                        $pf | Set-CimInstance -Property @{ InitialSize = 0; MaximumSize = 0 }

                        # Enable automatic management
                        $cs = Get-CimInstance -ClassName Win32_ComputerSystem
                        $cs | Set-CimInstance -Property @{ AutomaticManagedPagefile = $true }
                    } else {
                        # Backup had manual config: restore with backup's settings
                        $restoreName = $backup.PageFileConfig.Name
                        $restoreInitial = [int]$backup.PageFileConfig.InitialSize
                        $restoreMax = [int]$backup.PageFileConfig.MaximumSize
                        if (-not $restoreName -or $null -eq $restoreInitial -or $null -eq $restoreMax) {
                            throw 'Could not parse page file Name, InitialSize, or MaximumSize from backup file'
                        }

                        # Remove current config
                        $currentPf = Get-CimInstance -ClassName Win32_PageFileSetting -ErrorAction SilentlyContinue
                        if ($currentPf -and ($currentPf | Measure-Object).Count -eq 1) {
                            $currentPf | Remove-CimInstance -ErrorAction Stop
                        } elseif ($currentPf -and ($currentPf | Measure-Object).Count -gt 1) {
                            throw "Unexpected: $(($currentPf | Measure-Object).Count) page files configured"
                        }

                        # Restore with backup settings
                        $pf = New-CimInstance -ClassName Win32_PageFileSetting -Property @{ Name = $restoreName }
                        $pf | Set-CimInstance -Property @{ InitialSize = $restoreInitial; MaximumSize = $restoreMax }
                    }

                    $result.Action = if ($wasAutoManaged) { 'RestoreAutoManaged' } else { 'RestoreManual' }
                    $result.Success = $true
                } catch {
                    $result.Error = $_.Exception.Message
                }
                $result
            } -ArgumentList $remoteFilePath -ErrorAction SilentlyContinue -ErrorVariable remoteErrors

            # Report per-node results
            if ($remoteErrors) {
                foreach ($err in $remoteErrors) {
                    Write-Verbose "REMOTE ERROR: $($err.Exception.Message)" -Verbose
                }
            }
            $successCount = 0
            $failCount = 0
            foreach ($nodeResult in $remoteResults) {
                $backupInfo = if ($nodeResult.BackupFile) { " (from $($nodeResult.BackupFile))" } else { '' }
                if ($nodeResult.Success) {
                    Write-Verbose " $($nodeResult.Node): SUCCESS$backupInfo" -Verbose
                    $successCount++
                } else {
                    Write-Verbose " $($nodeResult.Node): FAILED - $($nodeResult.Error)$backupInfo" -Verbose
                    $failCount++
                }
            }
            Write-Verbose "Cluster restore complete: $successCount succeeded, $failCount failed out of $($Nodes.Count) nodes." -Verbose
            if ($failCount -gt 0) {
                Write-Warning "$failCount node(s) failed. Review the output above for details."
            }
            return $remoteResults
        }

        # ---------------------------------------------------------------
        # Node scope: auto-discover latest backup if no path provided
        # ---------------------------------------------------------------
        if ([string]::IsNullOrEmpty($PageFileSettingsFilePath)) {
            $BackupDir = 'C:\ProgramData\AzStackHci.DiagnosticSettings'
            $LatestFile = Get-ChildItem "$BackupDir\PageFile_Settings_*.json" -ErrorAction SilentlyContinue |
                Sort-Object LastWriteTime -Descending | Select-Object -First 1
            if (-not $LatestFile) {
                Write-Warning "No PageFile backup files found in '$BackupDir' on $env:COMPUTERNAME."
                throw "No PageFile backup files found in '$BackupDir'. Run Get-AzStackHciPageFileSettings first to create a backup."
            }
            $PageFileSettingsFilePath = $LatestFile.FullName
            Write-Verbose "Auto-discovered latest backup file: $PageFileSettingsFilePath (Last modified: $($LatestFile.LastWriteTime))" -Verbose
        }

        # Validate backup file path
        if ($PageFileSettingsFilePath -notlike "C:\ProgramData\AzStackHci.DiagnosticSettings\PageFile_Settings_*") {
            throw "Error: Page File settings backup file path must start with 'C:\ProgramData\AzStackHci.DiagnosticSettings\PageFile_Settings_'"
        }

        # Read and parse the JSON backup file
        Write-Verbose "Reading Page File settings from backup file: $PageFileSettingsFilePath" -Verbose
        $backup = Get-Content $PageFileSettingsFilePath -Raw -ErrorAction Stop | ConvertFrom-Json

        try {
            # Get current page file settings
            [bool]$script:PageFileAutoManaged = (Get-CimInstance Win32_ComputerSystem).AutomaticManagedPagefile
        } catch {
            throw "Failed to get current page file settings. Error: $($_.Exception.Message)"
        }

        # ShouldProcess confirmation before restoring
        if (-not $PSCmdlet.ShouldProcess("Page file settings on $env:COMPUTERNAME", "Restore page file settings from '$PageFileSettingsFilePath' (saved on $($backup.BackupDate))")) {
            return
        }

        [bool]$RestorePageFileAutoManaged = $backup.PageFileAutoManaged

        if ($RestorePageFileAutoManaged) {
            # Backup had auto-managed: restore to auto-managed
            $nameValue = $backup.PageFileUsage.Name
            if (-not $nameValue) { throw 'Could not find page file Name in backup file' }

            if ($script:PageFileAutoManaged) {
                throw "Restore Page File settings: Page File is already automatically managed, no action required."
            }

            try {
                # Remove existing manual page file
                $script:PageFileConfiguration = Get-CimInstance -ClassName Win32_PageFileSetting
                if (($script:PageFileConfiguration | Measure-Object).Count -eq 1) {
                    $script:PageFileConfiguration | Remove-CimInstance -ErrorAction Stop
                    Write-Verbose "Existing manual page file settings removed." -Verbose
                } elseif (($script:PageFileConfiguration | Measure-Object).Count -gt 1) {
                    throw "Unexpected: $(($script:PageFileConfiguration | Measure-Object).Count) page files configured"
                }

                # Create system-managed page file
                $RestorePageFile = New-CimInstance -ClassName Win32_PageFileSetting -Property @{ Name = $nameValue } -ErrorAction Stop
                $RestorePageFile | Set-CimInstance -Property @{ InitialSize = 0; MaximumSize = 0 } -ErrorAction Stop

                # Enable automatic management
                $ComputerSystem = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction Stop
                $ComputerSystem | Set-CimInstance -Property @{ AutomaticManagedPagefile = $true } -ErrorAction Stop
            } catch {
                throw "Failed to restore auto-managed page file settings. Error: $($_.Exception.Message)"
            }

            Write-Verbose "Page File settings reverted to automatically managed." -Verbose
            Write-Verbose "A system restart is required for the Page File changes to take effect." -Verbose
            return [PSCustomObject]@{ Node = $env:COMPUTERNAME; Success = $true; Action = 'RestoreAutoManaged'; BackupFile = $PageFileSettingsFilePath; Error = $null }

        } else {
            # Backup had manual config: restore with backup's settings
            $restoreName = $backup.PageFileConfig.Name
            $restoreInitial = [int]$backup.PageFileConfig.InitialSize
            $restoreMax = [int]$backup.PageFileConfig.MaximumSize
            if (-not $restoreName -or $null -eq $restoreInitial -or $null -eq $restoreMax) {
                throw 'Could not parse page file Name, InitialSize, or MaximumSize from backup file'
            }

            try {
                # Remove existing page file
                $script:PageFileConfiguration = Get-CimInstance -ClassName Win32_PageFileSetting
                if (($script:PageFileConfiguration | Measure-Object).Count -eq 1) {
                    $script:PageFileConfiguration | Remove-CimInstance -ErrorAction Stop
                    Write-Verbose "Existing page file settings removed." -Verbose
                } elseif (($script:PageFileConfiguration | Measure-Object).Count -gt 1) {
                    throw "Unexpected: $(($script:PageFileConfiguration | Measure-Object).Count) page files configured"
                }

                # Restore with backup settings
                $RestorePageFile = New-CimInstance -ClassName Win32_PageFileSetting -Property @{ Name = $restoreName } -ErrorAction Stop
                $RestorePageFile | Set-CimInstance -Property @{ InitialSize = $restoreInitial; MaximumSize = $restoreMax } -ErrorAction Stop
            } catch {
                throw "Failed to restore manual page file settings. Error: $($_.Exception.Message)"
            }

            Write-Verbose "Page File configured with InitialSize = $restoreInitial and MaximumSize = $restoreMax" -Verbose
            Write-Verbose "A system restart is required for the Page File changes to take effect." -Verbose
            return [PSCustomObject]@{ Node = $env:COMPUTERNAME; Success = $true; Action = 'RestoreManual'; BackupFile = $PageFileSettingsFilePath; Error = $null }
        }

    } # End of process block

    end {
        if ($NoOutput.IsPresent) { $script:SilentMode = $false }
        Write-Debug "Completed Restore-AzStackHciPageFileSettings function"
    }

} # End of Restore-AzStackHciPageFileSettings function

# SIG # Begin signature block
# MIInSQYJKoZIhvcNAQcCoIInOjCCJzYCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCB9tbyCRMkXzT1y
# jVAKvdb+ZVMgucYJzBWrueLXsnxdW6CCDLowggX1MIID3aADAgECAhMzAAACHU0Z
# yE7XD1dIAAAAAAIdMA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNVBAYTAlVTMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBD
# b2RlIFNpZ25pbmcgUENBIDIwMjQwHhcNMjYwNDE2MTg1OTQzWhcNMjcwNDE1MTg1
# OTQzWjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYD
# VQQDExVNaWNyb3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IB
# DwAwggEKAoIBAQDQvewXxx9gZZFC6Ys1WBay8BJ8kGA4JQnH5CMafqOASlTpK9H8
# o5ZXTXt0caVQTNMUPt445wXYD+dFtaKWTwDn1I52oUSrC9vJin1Gsqt+zyKJL5Dg
# 3eQXbQNR61DmMy20GLTIO3SFed9Rfi/ophgCLGFLDR3r0KvHjwMb/jYWS0celV/4
# Lz27LfAekm8v9E5IXaeiXbAUYZKK090n4CVl3JBtbN+9DtI9SNu/yjvozW52/u7R
# X/Ttpa/KDlpuokZ+Zcbvmtd9ur9gFLvZzh41o9MsE/clQtdaFWGvuo6Jua/ntpgk
# ey3E5/vBFe+MJPG6phdnuo6r57ZudCudiI1bAgMBAAGjggGbMIIBlzAOBgNVHQ8B
# Af8EBAMCB4AwHwYDVR0lBBgwFgYKKwYBBAGCN0wIAQYIKwYBBQUHAwMwHQYDVR0O
# BBYEFH6QuMwqcPG0hQlQ6c5jCtTTLrVeMEUGA1UdEQQ+MDykOjA4MR4wHAYDVQQL
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xFjAUBgNVBAUTDTIzMDAxMis1MDc1NTkw
# HwYDVR0jBBgwFoAUf1k/VCHarU/vBeXmo9ctBpQSCDEwYAYDVR0fBFkwVzBVoFOg
# UYZPaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0
# JTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDI0LmNybDBtBggrBgEFBQcBAQRh
# MF8wXQYIKwYBBQUHMAKGUWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMv
# Y2VydHMvTWljcm9zb2Z0JTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDI0LmNy
# dDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQBKTbYOjzwTG/DXGaz9
# s6+fQeaTtDcFmMY+5UyVFCyj7Pv+5i37qfX8lSL/tBIfYQfWsMuBQlfZurJD6r4H
# VJ2CeH+1fgiq8dcHdVKoZ3Sa2qXoX3cq9iS8cVb06B7+5/XJ7I0OxHH9fDsvJ3T3
# w5V/ZtAIFmLrl+P0CtG+92uzRsn0nTbdFjOkLMLWPLAU3THohKRlSEMgFJpPkm5n
# 5UAZ35xX6FWCrDLsSKb555bTifwa8mJBwdlof0bmfYidH+dxZ1FdDxvLnNl9zeKs
# A4kejaaIqqIPguhwAti5Ql7BlTNoJNwxCvBmqW2MQLnCkYN/VVUsR3V2x/rcTNzo
# Bf/Z/SpROvdaA2ZOOd1uioXJt3tdLQ7vHpqpib0KfWr/FWXW10q38VxfCnRQBqzb
# SuztR7nEMuzX7Ck+B/XaPDXd1qh72+QYyB0Z2VzWmO9zsnb9Uq/dwu8LGeQqnyu6
# 7SDGACvnXii2fb9+US492VTnXSnFKyqwgzUyFMtZK1/sHYTv6bG4TtQUygQxTN+Z
# V+aJIlKO2MqZ7bKrAnOzS9m6NgoTdWOq11bTOZwKlIEV/EhV9SWkDmdpR/hPPT2v
# 6TEj4F8PT/zHjRezIU5c/DGlt/VhY/pK0XkJtEyMmmS1BMtjU/rqBZVMIm3dnxQs
# /TBByr+Cf8Z1r7aifQVQ+WSqzjCCBr0wggSloAMCAQICEzMAAAA5O7Y3Gb8GHWcA
# AAAAADkwDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX
# YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg
# Q29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRl
# IEF1dGhvcml0eSAyMDExMB4XDTI0MDgwODIwNTQxOFoXDTM2MDMyMjIyMTMwNFow
# VzELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEo
# MCYGA1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAyNDCCAiIwDQYJ
# KoZIhvcNAQEBBQADggIPADCCAgoCggIBANgBnB7jOMeqlRYHNa265v4IY9fH8TKh
# emHfPINe1gpLaV3dhg324WwH06LcHbpnsBukCDNitryo0dtS/EW6I/yEL/bLSY8h
# KpbfQuWusBPr9qazYcDxCW/qnjb5JsI1s8bNOg3bVATvQVL4tcf03aTycsz8QeCd
# M0l/yHRObJ9QqazM1r6VPEOJ7LL+uEEb73w6QCuhs89a1uv1zerOYMnsneRRwCbp
# yW11IcggU0cRKDDq1pjVJzIbIF6+oiXXbReOsgeI8zu1FyQfK0fVkaya8SmVHQ/t
# Of23mZ4W9k0Ri22QW9p3UgSC5OUDktKxxcCmGL6tXLfOGSWHIIV4YrTJTT6PNty5
# REojHJuZHArkF9VnHTERWoTjAzfI3kP+5b4alUdhgAZ7ttOu1bVnXfHaqPYl2rPs
# 20ji03LOVWsh/radgE17es5hL+t6lV0eVHrVhsssROWJuz2MXMCt7iw7lFPG9LXK
# Gjsmonn2gotGdHIuEg5JnJMJVmixd5LRlkmgYRZKzhxSCwyoGIq0PhaA7Y+VPct5
# pCHkijcIIDm0nlkK+0KyepolcqGm0T/GYQRMhHJlGOOmVQop36wUVUYklUy++vDW
# eEgEo4s7hxN6mIbf2MSIQ/iIfMZgJxC69oukMUXCrOC3SkE/xIkgpfl22MM1itkZ
# 35nNXkMolU1lAgMBAAGjggFOMIIBSjAOBgNVHQ8BAf8EBAMCAYYwEAYJKwYBBAGC
# NxUBBAMCAQAwHQYDVR0OBBYEFH9ZP1Qh2q1P7wXl5qPXLQaUEggxMBkGCSsGAQQB
# gjcUAgQMHgoAUwB1AGIAQwBBMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU
# ci06AjGQQ7kUBU7h6qfHMdEjiTQwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDovL2Ny
# bC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0MjAx
# MV8yMDExXzAzXzIyLmNybDBeBggrBgEFBQcBAQRSMFAwTgYIKwYBBQUHMAKGQmh0
# dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0MjAx
# MV8yMDExXzAzXzIyLmNydDANBgkqhkiG9w0BAQwFAAOCAgEAFJQfOChP7onn6fLI
# MKrSlN1WYKwDFgAddymOUO3FrM8d7B/W/iQ6DxXsDn7D5W4wMwYeLystcEqfkjz4
# NURRgazyMu5yRzQh4LqjA4tStTcJh1opExo7nn5PuPBYnbu0+THSuVHTe0VTTPVh
# ily/piFrDo3axQ9P4C+Ol5yet+2gTfekICS5xS+cYfSIvgn0JksVBVMYVI5QFu/q
# hnLhsEFEUzG8fvv0hjgkO+lkpV9ty6GkN4vdnd7ya6Q6aR9y34aiM1qmxaxBi6OU
# nyNl6fkuun/diTFnYDLTppOkr/mg5WSfCiDVMNCxtj4wPKC5OmHm1DQIt/MNokbb
# H3UGsFP1QbzsLocuSqLCvH09Io3fDPTmscR9Y75G4qX7RTX8AdBPo0I6OEojf39z
# uFZt0qOHm65YWQE69cZM2ueE1MB05dNNgHK9gTE7zKvK/fg8B2qjW88MT/WF5V5u
# vZGtqa9FSL2RazArA+rDPuf6JGYz4HpgMZHB4S6szWSKYBv0VisCzfxgeU+dquXW
# 9bd0auYlOB58DPcOYKdc3Se94g+xL4pcEhbB54JOgAkwYTu/9dLeH2pDqeJZAABV
# DWRQCaXfO5LgyKwKCLYXpigrZYCjUSBcr+Ve8PFWMhVTQl0v4q8J/AUmQN5W4n10
# 1cY2L4A7GTQG1h32HHAvfQESWP0xghnlMIIZ4QIBATBuMFcxCzAJBgNVBAYTAlVT
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jv
# c29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMjQCEzMAAAIdTRnITtcPV0gAAAAAAh0w
# DQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYK
# KwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIEQ9ghRW
# oS1bqbKpK7STbJcqqAIptC9CGXc7YxHBfR/xMEIGCisGAQQBgjcCAQwxNDAyoBSA
# EgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20w
# DQYJKoZIhvcNAQEBBQAEggEAMenmWO+Lp8lVNCtStdQllqBdcQwlauP4Ba5VRww2
# T64ASUArMbvETmyM2zjYBGRjMdPsOqSic0PZihTXnk3lW6Eo4le4qQWUrK6/+O0R
# VLdicfqLCF/kCzEwzR1h7v89q8DKH0cGco+sQK9i5P/CshTKAaXoTSqC1uJ3RIJH
# SAg7oea7t2BavFm10v6gMk4aoeSoncxaMgJ4ySUK3UAkfg+TCz9RjXRBp5JkhRT0
# o9bld0WILJ08fO+kMkTXCkcxq1nCKLJmBxOseqgchCy/acvXBv9QtAZ2vpfLjfWA
# h00b6lnUzye3K/M3gqpc2Mh42BvCpNk7Wj+k3SSCF76P56GCF5cwgheTBgorBgEE
# AYI3AwMBMYIXgzCCF38GCSqGSIb3DQEHAqCCF3AwghdsAgEDMQ8wDQYJYIZIAWUD
# BAIBBQAwggFSBgsqhkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoD
# ATAxMA0GCWCGSAFlAwQCAQUABCDsWQE+n33tTuUgNi5DnCRcdtzEThHpwoNUaPuZ
# 0+lRLAIGajH/ArXHGBMyMDI2MDcwNzE2NTYzMC45MTNaMASAAgH0oIHRpIHOMIHL
# MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk
# bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxN
# aWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRT
# UyBFU046MzMwMy0wNUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0
# YW1wIFNlcnZpY2WgghHtMIIHIDCCBQigAwIBAgITMwAAAiEzwDX70g8hpAABAAAC
# ITANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu
# Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv
# cmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAe
# Fw0yNjAyMTkxOTM5NTRaFw0yNzA1MTcxOTM5NTRaMIHLMQswCQYDVQQGEwJVUzET
# MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV
# TWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmlj
# YSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046MzMwMy0wNUUw
# LUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIi
# MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDbcTACqU1YvRocyWL2PL9fyf/+
# ULs2qK7U1aZsRnDZSnlCr7K7jgA3eFCEJL5BZ7dUTC0DeZepf+ZC+7HEbB4IdzmJ
# fQAUDFFerqY5VTHmQvP2XA3lWSFj740idcGUHglP5H/PbCJU7GAHWP2HdcCjdx1l
# YAo0A+zLI7xwnTQeMyOXX212Eg4UmDPPJgxdTMw6WFVWsBPWRBi5gDixy2s+7R8A
# Dk5lbBBFDB5h0CjrNWIN7uCAzF5g7trrL8nXIKp10mj9RxhcGQ+tlht6VIvdygRV
# TUGdzFB2/nBvJqQ9kxxFltQST70fEdx4TyaKow/f5+BSh4z4/9f7NXIVVTLn/8kc
# JAfRqFmRrrFt3IKby7VrzmYuoQWD0lmNFtGQ57BrJkPrPFAPek1ALtcbb7FH3nQp
# vi8ngz/MFX/+cnmNFWFU29VVLmzB9XvLZxbYvkeett0mh5lfteeN2rEwUyrdrKuf
# z9h2S6pbate+C2h02CrXwSka0x6ezpTmGkIJLFt25ub/UYXNLdHdsxGD6EfckOIo
# JYsm4MS9F/vSqLNHK89I0vTLBngQEp6LIFkINanRT3PtNx3pNKRKJRALc6L6mhW4
# hL4aHL749qPfQ72t5qAMm5xiKYMgJ2WanidRLNuI251JIN7raaeA/2vb0XFkZcIb
# TR1pfQGsco4U0g5tjwIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFOYjIs5qa6pfuquP
# yyK1FTr5QDCnMB8GA1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1Ud
# HwRYMFYwVKBSoFCGTmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3Js
# L01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggr
# BgEFBQcBAQRgMF4wXAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNv
# bS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIw
# MTAoMSkuY3J0MAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgw
# DgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBCwUAA4ICAQA4I/3bkdnTxD2rFum3
# MF8xVKdEkohAObbePrQ+0fr5bRimjz9sVkKT/7gcj4OMcClSYG+IdX6Mp3EYsLHW
# fjvwfzFoeZE+yTbdBj/1VHZQRuCmw6QqeVCTbw2nnS7nBxnWd9oZXbPUpqEawH5D
# qXQaWFgR9A4KWVK/IvXVDMj1PlPCES1P3JonNbdhkkkz49rJuKOm5b7e/BH8loqA
# mXOXRc22yxWVTMWrEp4pslmv8eT7VoY8X/jdKYTPVEXsfmLbVFcqzMuB8vFGfUyW
# sWROS8wgq7lQYfWcYqh7NymoATX+wWYK3zWG7aRciPGUAzznXdf+aHtIWnQLNa5H
# FmSXkiak3fSuprWYZiHhuYjE16hroApcBHpm+8S/kNqhm9WjQX+2BxnYv+Jejy6l
# qTi8fLBLS069WXVw/ptf5IV+FtYl34GvVoeg31UoUmVVZe1SDUJkm9dDXc8l/qBD
# YiAIT2CCsPTyt9XA9JVuHxdP63n7ChvWAO/47QRuCDsUlFJoWwyBwl7jeYpaRVMt
# Qt0iuJMGGjgEaJX1Q/2j8sXURvTceLHDD9ipWt092ZDWMQciDRmhHNFOX1dnjBvk
# /k1UMcg997j5oYznAnSpJvlg/4BP3aVE0h/YH2KgsKbU4NXZHAjJXj2Slqo1C115
# CG6qBZaFkM8W6vPZCm5qnSezOjCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkA
# AAAAABUwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX
# YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg
# Q29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRl
# IEF1dGhvcml0eSAyMDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVow
# fDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl
# ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMd
# TWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX
# 9gF/bErg4r25PhdgM/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1q
# UoNEt6aORmsHFPPFdvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8d
# q6z2Nr41JmTamDu6GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byN
# pOORj7I5LFGc6XBpDco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2k
# rnopN6zL64NF50ZuyjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4d
# Pf0gz3N9QZpGdc3EXzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgS
# Uei/BQOj0XOmTTd0lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8
# QmguEOqEUUbi0b1qGFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6Cm
# gyFdXzB0kZSU2LlQ+QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzF
# ER1y7435UsSFF5PAPBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQID
# AQABo4IB3TCCAdkwEgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQU
# KqdS/mTEmr6CkTxGNSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1
# GelyMFwGA1UdIARVMFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0
# dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0
# bTATBgNVHSUEDDAKBggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMA
# QTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbL
# j+iiXGJo0T2UkFvXzpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1p
# Y3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0w
# Ni0yMy5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3
# Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIz
# LmNydDANBgkqhkiG9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwU
# tj5OR2R4sQaTlz0xM7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN
# 3Zi6th542DYunKmCVgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU
# 5HhTdSRXud2f8449xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5
# KYnDvBewVIVCs/wMnosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGy
# qVvfSaN0DLzskYDSPeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB6
# 2FD+CljdQDzHVG2dY3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltE
# AY5aGZFrDZ+kKNxnGSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFp
# AUR+fKFhbHP+CrvsQWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcd
# FYmNcP7ntdAoGokLjzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRb
# atGePu1+oDEzfbzL6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQd
# VTNYs6FwZvKhggNQMIICOAIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzAR
# BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p
# Y3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2Eg
# T3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjMzMDMtMDVFMC1E
# OTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEw
# BwYFKw4DAhoDFQALbEgZZnyYHXJ1DGb5fGjplXptuaCBgzCBgKR+MHwxCzAJBgNV
# BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29m
# dCBUaW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA7feBgTAiGA8y
# MDI2MDcwNzEzNDUzN1oYDzIwMjYwNzA4MTM0NTM3WjB3MD0GCisGAQQBhFkKBAEx
# LzAtMAoCBQDt94GBAgEAMAoCAQACAkIuAgH/MAcCAQACAhK6MAoCBQDt+NMBAgEA
# MDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAI
# AgEAAgMBhqAwDQYJKoZIhvcNAQELBQADggEBAAJLMf1Gitylnq+rQvzTg6hNgec8
# EZ5qCPzxlK/fdK+FQQ6cOTculLroDlCmkExB3u5b4MPQFBymJlvi5iUnuj6zUmbX
# Wb340CJFuejGnKGBFAd/3+jEnK590sJuju7bYkWMjRQ4XV9S3MVKatDM0mrFLGMn
# ZQEYAWvi08Xp0/EL/qjyQV+cN0US+eIRZaV4I/0Qg2sVc0tt885C6excF/AhZnqp
# m8bheMKReJmN7m6AhcBnpF9P6eJ61PnseWTN8drxc6K0evYacIIa6ryVOCPYRzgk
# 36gNQWZRXgGBN2/5tcelk1tVpys2cNpYYJVbB+aKCNPdW2ZHA7kKMQcuTX0xggQN
# MIIECQIBATCBkzB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ
# MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u
# MSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAiEz
# wDX70g8hpAABAAACITANBglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0G
# CyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJBDEiBCDHOUIH0SBtd3bjPxGgtdVXsfiS
# WmhWJ0CPBmL1OeEFOTCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EIADvIQef
# FVUa4BJy8IZywMAvmGSKdUVqEmy9A++PCj1EMIGYMIGApH4wfDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgUENBIDIwMTACEzMAAAIhM8A1+9IPIaQAAQAAAiEwIgQgEmOeFgFi
# 09JxkvKaz7592StVlrmW85SDR5R/mxsTzsMwDQYJKoZIhvcNAQELBQAEggIAlwZJ
# OiORFG2sglp4xhnK9xSQXV3RrZUG2m6S2r2jwPSHY2O+iVCgbJXaqpdLB//gT+hC
# CVMgIijX3FuE02Mq7b1nFD70WF226djJJTTRQmIlcyII0FaymYwcN3UcjC8vYJl9
# cmWxlHX4wKCXOH+Hu8M8bwDggixGzVXy56htPNOIqebtUBK38jjnEZsABiX4ul5w
# zCYHI7xOQ+rvarM9MLhTxeSBMk2GjnIFXm395R1NHsjfJuHENryH6yJlE6NZvq2Q
# DtkuXSDrc8KLfAz14HBPcCQz7kvWTulhn8M3Wunlht3tkKAZl6KSm7+80nmZjd0W
# mz2stiiH4bB/4x09VzekawmfTX+rjXkfB1sWFyRsDygJjAD2HyZqSHKII6veEbXZ
# 8an+Y/n+eVKend0UAJnaHQXVKs53a0pDLl52KcwXOyhT3SwxUnTZPG1Wq3v+9MEy
# sObFlmEAHa6kgjlGY/Tsv2V2dG810w1ye95IjQqTJYd9TS3HeNp+RFLbqVU2sDWX
# SvjUzepom+BSlmgFYSLcMNQfWXSpbVN3WvDbuoCqoTGh3j8BgzFOnwSk5OCEZaA4
# ByPo/Gznn6quGsRdsdvy1DKu8RfTlFjsnxx82dNnqERYxZNg1aumL1jO2D3I7cIJ
# PWAZm/thNhkpqlyu0+FXi/zjthMkbdDY2rUgdLU=
# SIG # End signature block