packages/AzStackHci.DiagnosticSettings.0.6.8/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
# MIInUAYJKoZIhvcNAQcCoIInQTCCJz0CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCB9tbyCRMkXzT1y
# jVAKvdb+ZVMgucYJzBWrueLXsnxdW6CCDMkwggYEMIID7KADAgECAhMzAAACHPrN
# xZvoL37EAAAAAAIcMA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNVBAYTAlVTMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBD
# b2RlIFNpZ25pbmcgUENBIDIwMjQwHhcNMjYwNDE2MTg1OTQxWhcNMjcwNDE1MTg1
# OTQxWjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYD
# VQQDExVNaWNyb3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IB
# DwAwggEKAoIBAQDVsZfgOKmM31HPfoWOoNEiw0SlCiIxUMC0I9NMWbucKOw/e9lP
# oAoehQVu6SG65V4EPzrYsnBnFPNoi4/HoOdjhz1qkrEt4I6tEcxXU6oOeY9zGveC
# /3iBeuhLYxM3M/PkcUoebF+Nednm8OkdSPoDu8imViHPQq/8CQUu0WRR4rE+dMRf
# rpVqfmNi2qWCX94T4MsepijGVkwE//tJg0ryAiYdHT34LSnlG/RSBZmQRGWZ5g8j
# qnKjRParSqMft1gvjuUTVgtWNZfgcLFSK5Wa0myrq8OPcgTGGsRgun+tnSS+IxDT
# xVsAPH1OzvPjwomguByhUe/OcvUN0D5Wmp7xAgMBAAGjggGqMIIBpjAOBgNVHQ8B
# Af8EBAMCB4AwHwYDVR0lBBgwFgYKKwYBBAGCN0wIAQYIKwYBBQUHAwMwHQYDVR0O
# BBYEFNoH7a2YDjOSwpkp6DHcmUS7J+0yMFQGA1UdEQRNMEukSTBHMS0wKwYDVQQL
# EyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxFjAUBgNVBAUT
# DTIzMDAxMis1MDc1NjkwHwYDVR0jBBgwFoAUf1k/VCHarU/vBeXmo9ctBpQSCDEw
# YAYDVR0fBFkwVzBVoFOgUYZPaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9w
# cy9jcmwvTWljcm9zb2Z0JTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDI0LmNy
# bDBtBggrBgEFBQcBAQRhMF8wXQYIKwYBBQUHMAKGUWh0dHA6Ly93d3cubWljcm9z
# b2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwQ29kZSUyMFNpZ25pbmcl
# MjBQQ0ElMjAyMDI0LmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IC
# AQAUnEqhaRXe0T3hIJjvdQErEkrA/7bByjn6t5IArODkkRjzkYwtKMc2yYj2quaN
# rLutWw2YZcngKPy1b71YyDJQTy4NDRwaSh9Tw5thrk3NmcPrAHia5vtcBJ1CgtKK
# 7mQbIcQ22d/N3813ayCDDFewu1+jsZmX+r/aTEqaOM4TVxVtRSkuCy8nAXKuChOK
# Li/zA4XuH8iEYqIsj2YoNaeSxVmeGiERXpKdo3dDmYi0kO5w2D8VS4c3+9h6gElY
# BaAAg/dYErBg27qT3vv0zRDJhJufvCNylA8S7/+8H5E/PV5cng6na9VV/w9OV3qu
# uND6zdGa2EX38Glp50F9AIQk3p2xXmcvorDeM4XJ7UlWYBi6g80J1SSOQnInCYFE
# msfUNn3+1AaTJKSJL83quKArTac2pKhu0Yzzzrzo6HrsRiQKzpnRBb1/dMa6P3hz
# 75XbMRBctNsFhZC07WCmjExdLg2eHW5uV0TY8D5+6wozJf7vF3+WHkYPO85Z+BC6
# U4FkNbYNycZ9cE4j1tXRdyDCfml6c0HWPHjNVDObrv9lKt3qUqFpX38VCqVCyNOO
# 1UcXfQiVjJw32U2WUKZjt/neJKHEBsm9kFsLuWzkQ53+qcaSaytmsCnk2gOglrlD
# 5d3kKyvvAw+rzm0lT8K38P6PLxfZQHhu4W8dV7Av8N2ZmDCCBr0wggSloAMCAQIC
# EzMAAAA5O7Y3Gb8GHWcAAAAAADkwDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNVBAYT
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBS
# b290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDExMB4XDTI0MDgwODIwNTQxOFoX
# DTM2MDMyMjIyMTMwNFowVzELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQ
# Q0EgMjAyNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANgBnB7jOMeq
# lRYHNa265v4IY9fH8TKhemHfPINe1gpLaV3dhg324WwH06LcHbpnsBukCDNitryo
# 0dtS/EW6I/yEL/bLSY8hKpbfQuWusBPr9qazYcDxCW/qnjb5JsI1s8bNOg3bVATv
# QVL4tcf03aTycsz8QeCdM0l/yHRObJ9QqazM1r6VPEOJ7LL+uEEb73w6QCuhs89a
# 1uv1zerOYMnsneRRwCbpyW11IcggU0cRKDDq1pjVJzIbIF6+oiXXbReOsgeI8zu1
# FyQfK0fVkaya8SmVHQ/tOf23mZ4W9k0Ri22QW9p3UgSC5OUDktKxxcCmGL6tXLfO
# GSWHIIV4YrTJTT6PNty5REojHJuZHArkF9VnHTERWoTjAzfI3kP+5b4alUdhgAZ7
# ttOu1bVnXfHaqPYl2rPs20ji03LOVWsh/radgE17es5hL+t6lV0eVHrVhsssROWJ
# uz2MXMCt7iw7lFPG9LXKGjsmonn2gotGdHIuEg5JnJMJVmixd5LRlkmgYRZKzhxS
# CwyoGIq0PhaA7Y+VPct5pCHkijcIIDm0nlkK+0KyepolcqGm0T/GYQRMhHJlGOOm
# VQop36wUVUYklUy++vDWeEgEo4s7hxN6mIbf2MSIQ/iIfMZgJxC69oukMUXCrOC3
# SkE/xIkgpfl22MM1itkZ35nNXkMolU1lAgMBAAGjggFOMIIBSjAOBgNVHQ8BAf8E
# BAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFH9ZP1Qh2q1P7wXl5qPX
# LQaUEggxMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMA8GA1UdEwEB/wQFMAMB
# Af8wHwYDVR0jBBgwFoAUci06AjGQQ7kUBU7h6qfHMdEjiTQwWgYDVR0fBFMwUTBP
# oE2gS4ZJaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMv
# TWljUm9vQ2VyQXV0MjAxMV8yMDExXzAzXzIyLmNybDBeBggrBgEFBQcBAQRSMFAw
# TgYIKwYBBQUHMAKGQmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMv
# TWljUm9vQ2VyQXV0MjAxMV8yMDExXzAzXzIyLmNydDANBgkqhkiG9w0BAQwFAAOC
# AgEAFJQfOChP7onn6fLIMKrSlN1WYKwDFgAddymOUO3FrM8d7B/W/iQ6DxXsDn7D
# 5W4wMwYeLystcEqfkjz4NURRgazyMu5yRzQh4LqjA4tStTcJh1opExo7nn5PuPBY
# nbu0+THSuVHTe0VTTPVhily/piFrDo3axQ9P4C+Ol5yet+2gTfekICS5xS+cYfSI
# vgn0JksVBVMYVI5QFu/qhnLhsEFEUzG8fvv0hjgkO+lkpV9ty6GkN4vdnd7ya6Q6
# aR9y34aiM1qmxaxBi6OUnyNl6fkuun/diTFnYDLTppOkr/mg5WSfCiDVMNCxtj4w
# PKC5OmHm1DQIt/MNokbbH3UGsFP1QbzsLocuSqLCvH09Io3fDPTmscR9Y75G4qX7
# RTX8AdBPo0I6OEojf39zuFZt0qOHm65YWQE69cZM2ueE1MB05dNNgHK9gTE7zKvK
# /fg8B2qjW88MT/WF5V5uvZGtqa9FSL2RazArA+rDPuf6JGYz4HpgMZHB4S6szWSK
# YBv0VisCzfxgeU+dquXW9bd0auYlOB58DPcOYKdc3Se94g+xL4pcEhbB54JOgAkw
# YTu/9dLeH2pDqeJZAABVDWRQCaXfO5LgyKwKCLYXpigrZYCjUSBcr+Ve8PFWMhVT
# Ql0v4q8J/AUmQN5W4n101cY2L4A7GTQG1h32HHAvfQESWP0xghndMIIZ2QIBATBu
# MFcxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# KDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMjQCEzMAAAIc
# +s3Fm+gvfsQAAAAAAhwwDQYJYIZIAWUDBAIBBQCggZAwGQYJKoZIhvcNAQkDMQwG
# CisGAQQBgjcCAQQwLwYJKoZIhvcNAQkEMSIEIEQ9ghRWoS1bqbKpK7STbJcqqAIp
# tC9CGXc7YxHBfR/xMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8AcwBv
# AGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEBBQAE
# ggEAYqYKXq5R3zbA4rFGh7ltWWSBRNWkvS/Ciku26UPweEA8f8sezYe+ilyHnvoo
# 9inDa0YvpnJS1cjx2t6+17w1gojd0OpdIuN4Xp+wFUfDsT+k8aszPddKCAv7NtRX
# LjoSaBzJ4D/LqRGoulNqkEb3fo0SIYqpng+eDs7AIKG3zIYHomQ9WEA0sdbpeV6B
# XJrw+2acHUDpaHSyhCi1+Y48FYH3AlKKn+RpAqVzEmvxWmg7QIh4TkBnR8e6x4ba
# b/Of32m0JAXwqXUiup11FCWE3FFPN7CYmmjSrSmGH4WoO0CprdSMr3coU5ambg6w
# 2/lYsMa3d9w3C8Tvuem2QgsJv6GCF60wghepBgorBgEEAYI3AwMBMYIXmTCCF5UG
# CSqGSIb3DQEHAqCCF4YwgheCAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFaBgsqhkiG
# 9w0BCRABBKCCAUkEggFFMIIBQQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFlAwQC
# AQUABCClcz9KRl6LPwUgivNIJpvuqshJH4cp4BWmHF9qtVDEpwIGamQr1NKRGBMy
# MDI2MDcyOTEzMTcyOS44MTJaMASAAgH0oIHZpIHWMIHTMQswCQYDVQQGEwJVUzET
# MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV
# TWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFu
# ZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjo2
# NTFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy
# dmljZaCCEfswggcoMIIFEKADAgECAhMzAAACFRgD04EHJnxTAAEAAAIVMA0GCSqG
# SIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# JjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTI1MDgx
# NDE4NDgyMFoXDTI2MTExMzE4NDgyMFowgdMxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
# EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
# ZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh
# dGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjY1MUEtMDVF
# MC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIC
# IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAw3HV3hVxL0lEYPV03XeNKZ51
# 7VIbgexhlDPdpXwDS0BYtxPwi4XYpZR1ld0u6cr2Xjuugdg50DUx5WHL0QhY2d9v
# kJSk02rE/75hcKt91m2Ih287QRxRMmFu3BF6466k8qp5uXtfe6uciq49YaS8p+dz
# v3uTarD4hQ8UT7La95pOJiRqxxd0qOGLECvHLEXPXioNSx9pyhzhm6lt7ezLxJeF
# VYtxShkavPoZN0dOCiYeh4KgoKoyagzMuSiLCiMUW4Ue4Qsm658FJNGTNh7V5qXY
# VA6k5xjw5WeWdKOz0i9A5jBcbY9fVOo/cA8i1bytzcDTxb3nctcly8/OYeNstkab
# /Isq3Cxe1vq96fIHE1+ZGmJjka1sodwqPycVp/2tb+BjulPL5D6rgUXTPF84U82R
# LKHV57bB8fHRpgnjcWBQuXPgVeSXpERWimt0NF2lCOLzqgrvS/vYqde5Ln9YlKKh
# AZ/xDE0TLIIr6+I/2JTtXP34nfjTENVqMBISWcakIxAwGb3RB5yHCxynIFNVLcfK
# AsEdC5U2em0fAvmVv0sonqnv17cuaYi2eCLWhoK1Ic85Dw7s/lhcXrBpY4n/Rl5l
# 3wHzs4vOIhu87DIy5QUaEupEsyY0NWqgI4BWl6v1wgse+l8DWFeUXofhUuCgVTuT
# HN3K8idoMbn8Q3edUIECAwEAAaOCAUkwggFFMB0GA1UdDgQWBBSJIXfxcqAwFqGj
# 9jdwQtdSqadj1zAfBgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBfBgNV
# HR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2Ny
# bC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYI
# KwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAy
# MDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMI
# MA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEAd42HtV+kGbvxzLBT
# C5O7vkCIBPy/BwpjCzeL53hAiEOebp+VdNnwm9GVCfYq3KMfrj4UvKQTUAaS5Zkw
# e1gvZ3ljSSnCOyS5OwNu9dpg3ww+QW2eOcSLkyVAWFrLn6Iig3TC/zWMvVhqXtdF
# hG2KJ1lSbN222csY3E3/BrGluAlvET9gmxVyyxNy59/7JF5zIGcJibydxs94JL1B
# tPgXJOfZzQ+/3iTc6eDtmaWT6DKdnJocp8wkXKWPIsBEfkD6k1Qitwvt0mHrORah
# 75SjecOKt4oWayVLkPTho12e0ongEg1cje5fxSZGthrMrWKvI4R7HEC7k8maH9eP
# A3ViH0CVSSOefaPTGMzIhHCo5p3jG5SMcyO3eA9uEaYQJITJlLG3BwwGmypY7C/8
# /nj1SOhgx1HgJ0ywOJL9xfP4AOcWmCfbsqgGbCaC7WH5sINdzfMar8V7YNFqkbCG
# UKhc8GpIyE+MKnyVn33jsuaGAlNRg7dVRUSoYLJxvUsw9GOwyBpBwbE9sqOLm+Hs
# O00oF23PMio7WFXcFTZAjp3ujihBAfLrXICgGOHPdkZ042u1LZqOcnlr3XzvgMe+
# mPPyasW8f0rtzJj3V5E/EKiyQlPxj9Mfq2x9himnlXWGZCVPeEBROrNbDYBfazTy
# LNCOTsRtksOSV3FBtPnpQtLN754wggdxMIIFWaADAgECAhMzAAAAFcXna54Cm0mZ
# AAAAAAAVMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK
# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0
# ZSBBdXRob3JpdHkgMjAxMDAeFw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMyMjVa
# MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMT
# HU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0BAQEF
# AAOCAg8AMIICCgKCAgEA5OGmTOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51yMo1
# V/YBf2xK4OK9uT4XYDP/XE/HZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY6GB9
# alKDRLemjkZrBxTzxXb1hlDcwUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9cmmv
# Haus9ja+NSZk2pg7uhp7M62AW36MEBydUv626GIl3GoPz130/o5Tz9bshVZN7928
# jaTjkY+yOSxRnOlwaQ3KNi1wjjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDuaRr3t
# pK56KTesy+uDRedGbsoy1cCGMFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74kpEe
# HT39IM9zfUGaRnXNxF803RKJ1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2K26o
# ElHovwUDo9Fzpk03dJQcNIIP8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5TI4C
# vEJoLhDqhFFG4tG9ahhaYQFzymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZki1ug
# poMhXV8wdJGUlNi5UPkLiWHzNgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9QBXps
# xREdcu+N+VLEhReTwDwV2xo3xwgVGD94q0W29R6HXtqPnhZyacaue7e3PmriLq0C
# AwEAAaOCAd0wggHZMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUCBBYE
# FCqnUv5kxJq+gpE8RjUpzxD/LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJlpxtT
# NRnpcjBcBgNVHSAEVTBTMFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIBFjNo
# dHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5o
# dG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBD
# AEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZW
# y4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5t
# aWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAt
# MDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0y
# My5jcnQwDQYJKoZIhvcNAQELBQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/ypb+pc
# FLY+TkdkeLEGk5c9MTO1OdfCcTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulmZzpT
# Td2YurYeeNg2LpypglYAA7AFvonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM9W0j
# VOR4U3UkV7ndn/OOPcbzaN9l9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECWOKz3
# +SmJw7wXsFSFQrP8DJ6LGYnn8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4FOmR
# sqlb30mjdAy87JGA0j3mSj5mO0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3UwxTSw
# ethQ/gpY3UA8x1RtnWN0SCyxTkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPXfx5b
# RAGOWhmRaw2fpCjcZxkoJLo4S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVXVAmx
# aQFEfnyhYWxz/gq77EFmPWn9y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGConsX
# HRWJjXD+57XQKBqJC4822rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU5nR0
# W2rRnj7tfqAxM328y+l7vzhwRNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEGahC0
# HVUzWLOhcGbyoYIDVjCCAj4CAQEwggEBoYHZpIHWMIHTMQswCQYDVQQGEwJVUzET
# MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV
# TWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFu
# ZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjo2
# NTFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy
# dmljZaIjCgEBMAcGBSsOAwIaAxUAj6eTejbuYE1Ifjbfrt6tXevCUSCggYMwgYCk
# fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD
# Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsFAAIF
# AO4T7/0wIhgPMjAyNjA3MjkwMzIwMjlaGA8yMDI2MDczMDAzMjAyOVowdDA6Bgor
# BgEEAYRZCgQBMSwwKjAKAgUA7hPv/QIBADAHAgEAAgIaSTAHAgEAAgIT+jAKAgUA
# 7hVBfQIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAID
# B6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBCwUAA4IBAQBflTR+tuVJhPGQgc7T
# qQHT52+Of7xuVVjG0S2KbWu6HsWah5g23lmpyyeQlHSQ3B4X4zrg0JqhksEZPwaq
# iKHShGyfinqzrNxauCDEwwt3mD7XshyJK5R/vd1J/k4h2pMH35h1e9L0Zhi3QcT3
# bPl3xwPSzr3Cnw1Yh1+QdmOGc+duFpoN4Jb5XVQW2bGFSx4aVBAKthb46IIjTQQN
# aO3M8ZzzBDETMmZ0yDZQQYfAb5t8naSSukTBI7o+Qdit4uqGJkoWDizjJn6vNENr
# QBce5XFvoeij/pgkIYYu5bMtGPD8yz8DhJDP8ZCSQY7Q1i0skY+9VMurlVDJiGdF
# TBXIMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAC
# EzMAAAIVGAPTgQcmfFMAAQAAAhUwDQYJYIZIAWUDBAIBBQCgggFKMBoGCSqGSIb3
# DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgwUqAU7BqV81AP/oe
# Iw5dCEQ7YJt83QbbAi4ZajVnZiAwgfoGCyqGSIb3DQEJEAIvMYHqMIHnMIHkMIG9
# BCBwEPR2PDrTFLcrtQsKrUi7oz5JNRCF/KRHMihSNe7sijCBmDCBgKR+MHwxCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jv
# c29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAACFRgD04EHJnxTAAEAAAIVMCIE
# IDWQQ7UydSIBtLuXy9Am7uOmaoqxoQP0Fn7KuIDcg2seMA0GCSqGSIb3DQEBCwUA
# BIICAG1MLCJe9ECWlEYXEvB+RBXr0z4MkhEI+J6VxSkde8TNnLmsDBIz7mcqFPUu
# x8tIYiPYHUaoRsyAbvTMiwHRAZcCyVNOwcWiiyNC8jwh+evZQukA/Ag9mxmNIX2t
# M7nrEoOTvgxfmyLKb05GxN3wlTOvpduyzTG3jH5NckENK4Z/xey9eAE/WJ0B/DO0
# LQnTZbIKJbf1x4jfywMf6jfgtowStfkV1ogGUfwgcfKkFm9HomON9YRYGw7Cm5Ru
# rAhdZtCwviUwcZGeHQdrtg0Ph1NZgWNRSWnWhFpAOF1Ud8XpiWgPtQ+JHSXn1aQ6
# 3IseFyza+kLpEnL+ywCdihXyF0T32iB6opbefRkDw/6rvXUnAOBEOYA0D7ptMwpW
# JATHCtZaHGgAvYeO/4gYQ3lAa9t/DnmHd92cjeS3bVSljVppjfLER7owJ/U8W3+p
# spdjnKmGHbWv3Mn+GFM8tqYdzQge0KyxMnxs8VXKHyvSdo7BiusOvOF0TRTJX6K8
# WO4+ClFGT6tk386/Hjb05L4ZVy7z4BP+l2yhQyeey6HckkaV8Wppp78u/FeqhxDc
# kglHqfUEBM9QUaEKLP6jZ1UMHuwqplVaxgM118B583qcWCxdb38SNAWyC/rjBAF/
# j14tm6USYyHCyYFayqUlJEQDVE06Dg/pk0A7HFjsGt8EPsHM
# SIG # End signature block