functions/disable-d365iispreload.ps1


<#
    .SYNOPSIS
        Disables IIS Preload for the AOSService application pool and website.
         
    .DESCRIPTION
        Reverts IIS Preload settings for the AOSService application:
        - Sets Application Pool Start Mode to OnDemand
        - Sets Idle Time-out to 0 (default)
        - Disables Preload on the AOSService website
        - Sets doAppInitAfterRestart to false (if Application Initialization is installed)
        - Restores previous IIS Preload configuration from backup if available
        - Restores or removes the initializationPage property as appropriate
        - Uninstalls IIS Application Initialization feature if it was not installed in the backup
         
    .EXAMPLE
        PS C:\> Disable-D365IISPreload
         
        Disables IIS Preload for the AOSService application pool and website, restoring previous settings from backup if available.
         
    .NOTES
        Author: Florian Hopfner (FH-Inway)
        Based on Denis Trunin's article "Enable IIS Preload to Speed Up Restart After X++ Compile" (https://www.linkedin.com/pulse/enable-iis-preload-speed-up-restart-after-x-compile-denis-trunin-86j5c)
        Written with GitHub Copilot GPT-4.1, mostly in agent mode. See commits for prompts.
         
    .LINK
        Get-D365IISPreload
         
    .LINK
        Enable-D365IISPreload
#>

function Disable-D365IISPreload {
    [CmdletBinding()]
    param ()

    if (-not (Get-Module -ListAvailable -Name WebAdministration)) {
        Write-PSFMessage -Level Warning -Message "The 'WebAdministration' module is not installed. Please install it with: Install-WindowsFeature -Name Web-WebServer -IncludeManagementTools or Install-Module -Name WebAdministration -Scope CurrentUser"
        return
    }

    Import-Module WebAdministration -ErrorAction Stop

    $appPool = "AOSService"
    $site = "AOSService"

    # Set default values first
    $startMode = 'OnDemand'
    $idleTimeout = [TimeSpan]::Zero
    $preloadEnabled = $false
    $doAppInitAfterRestart = 'False'
    $preloadPage = $null

    # Try to restore previous IIS Preload configuration from backup if available
    $backupDir = Join-Path $Script:DefaultTempPath "IISConfigBackup"
    $backupFile = $null
    if (Test-Path $backupDir) {
        $backupFiles = Get-ChildItem -Path $backupDir -Filter 'IISPreloadConfig.*.json' | Sort-Object LastWriteTime -Descending
        if ($backupFiles) {
            $backupFile = $backupFiles[0].FullName
        }
    }
    if ($backupFile) {
        Write-PSFMessage -Level Host -Message "Restoring IIS Preload configuration from backup: $backupFile"
        $preloadConfig = Get-Content $backupFile | ConvertFrom-Json
        if ($preloadConfig.StartMode) { $startMode = $preloadConfig.StartMode }
        if ($preloadConfig.IdleTimeout) { $idleTimeout = $preloadConfig.IdleTimeout }
        if ($null -ne $preloadConfig.PreloadEnabled) { $preloadEnabled = $preloadConfig.PreloadEnabled }
        if ($preloadConfig.DoAppInitAfterRestart) { $doAppInitAfterRestart = $preloadConfig.DoAppInitAfterRestart }
        if ($preloadConfig.PreloadPage) { $preloadPage = $preloadConfig.PreloadPage }
        # Uninstall IIS Application Initialization feature if it was not installed in the backup
        if ($preloadConfig.IISApplicationInitFeature -eq 'Not installed') {
            Write-PSFMessage -Level Host -Message "Uninstalling IIS Application Initialization feature (Web-AppInit) as per backup state."
            try {
                Uninstall-WindowsFeature -Name Web-AppInit -Confirm:$false | Out-Null
            } catch {
                Write-PSFMessage -Level Warning -Message "Failed to uninstall IIS Application Initialization feature. $_"
            }
        }
    }

    # Set Application Pool Start Mode and Idle Time-out
    $setAppPoolStartModeParams = @{
        Path  = "IIS:\AppPools\$appPool"
        Name  = 'startMode'
        Value = $startMode
    }
    Write-PSFMessage -Level Verbose -Message "Setting Application Pool '$appPool' startMode to '$startMode'"
    Set-ItemProperty @setAppPoolStartModeParams
    $setAppPoolIdleTimeoutParams = @{
        Path  = "IIS:\AppPools\$appPool"
        Name  = 'processModel.idleTimeout'
        Value = $idleTimeout
    }
    Write-PSFMessage -Level Verbose -Message "Setting Application Pool '$appPool' idleTimeout to '$idleTimeout'"
    Set-ItemProperty @setAppPoolIdleTimeoutParams
    $setSitePreloadParams = @{
        Path  = "IIS:\Sites\$site"
        Name  = 'applicationDefaults.preloadEnabled'
        Value = $preloadEnabled
    }
    Write-PSFMessage -Level Verbose -Message "Setting Site '$site' applicationDefaults.preloadEnabled to '$preloadEnabled'"
    Set-ItemProperty @setSitePreloadParams
    try {
        $setDoAppInitParams = @{
            pspath      = "MACHINE/WEBROOT/APPHOST/$site"
            filter      = 'system.webServer/applicationInitialization'
            name        = 'doAppInitAfterRestart'
            value       = $doAppInitAfterRestart
            ErrorAction = 'Stop'
        }
        Write-PSFMessage -Level Verbose -Message "Setting Site '$site' doAppInitAfterRestart to '$doAppInitAfterRestart'"
        Set-WebConfigurationProperty @setDoAppInitParams
    } catch {
        Write-PSFMessage -Level Verbose -Message "Application Initialization not installed or not available. Skipping doAppInitAfterRestart."
    }

    # Reset or remove initializationPage setting
    $getInitPagesParams = @{
        pspath      = 'MACHINE/WEBROOT/APPHOST'
        filter      = 'system.webServer/applicationInitialization'
        name        = '.'
        location    = $site
        ErrorAction = 'Stop'
    }
    $initPages = Get-WebConfigurationProperty @getInitPagesParams
    if ($initPages -and $initPages.Collection -and $initPages.Collection.Count -gt 0) {
        $currentPreloadPage = $initPages.Collection[0].initializationPage
    }
    if ($currentPreloadPage) {
        if ($preloadPage -and $preloadPage -ne "Not configured" -and $preloadPage -ne "Not available") {
            try {
                Write-PSFMessage -Level Verbose -Message "Setting Site '$site' initializationPage to '$preloadPage'"
                $setInitPageParams = @{
                    pspath      = "MACHINE/WEBROOT/APPHOST/$site"
                    filter      = 'system.webServer/applicationInitialization'
                    name        = '.'
                    value       = @{ initializationPage = $preloadPage }
                    AtElement   = @{ initializationPage = $currentPreloadPage }
                    ErrorAction = 'Stop'
                }
                Set-WebConfigurationProperty @setInitPageParams
            } catch {
                Write-PSFMessage -Level Verbose -Message "Preload page $preloadPage cannot be set. Application Initialization may not be installed or not available. Skipping initializationPage."
            }
        } else {
            try {
                Write-PSFMessage -Level Verbose -Message "Removing initializationPage from Site '$site'"
                if ($currentPreloadPage) {
                    $removeInitPageParams = @{
                        pspath      = "MACHINE/WEBROOT/APPHOST/$site"
                        filter      = 'system.webServer/applicationInitialization'
                        name        = '.'
                        AtElement   = @{ initializationPage = $currentPreloadPage }
                        ErrorAction = 'Stop'
                    }
                    Remove-WebConfigurationProperty @removeInitPageParams
                }
            } catch {
                Write-PSFMessage -Level Verbose -Message "Failed to remove initializationPage from Site '$site'. It may not exist."
            }
        }
    }
    
    Write-PSFMessage -Level Host -Message "IIS Preload disabled for $site."

    # Restart IIS service to apply changes
    try {
        Write-PSFMessage -Level Host -Message "Restarting IIS service (W3SVC) to apply changes..."
        Restart-Service -Name 'W3SVC' -Force -ErrorAction Stop
        Write-PSFMessage -Level Host -Message "IIS service restarted successfully."
    } catch {
        Write-PSFMessage -Level Warning -Message "Failed to restart IIS service (W3SVC): $_"
    }
}