PowerShell: Elegant IIS Application Pool Recycling Schedule Configuration Without Add-WebConfiguration


2 views

When working with IIS 7.5+ application pools through PowerShell, many administrators find themselves struggling with inconsistent syntax patterns. While basic settings like identity and pipeline mode work beautifully with object property assignment, recycling schedules force us into less elegant Add-WebConfiguration or appcmd approaches.

The root of the problem lies in how IIS stores scheduled recycling times. Unlike simple properties, these are stored as collections within the application pool configuration:

$pool = Get-Item IIS:\AppPools\MyAppPool
$pool.recycling.periodicRestart.schedule.Collection.GetType()
# Shows System.Configuration.ConfigurationElementCollection

Here are three production-tested approaches that maintain clean PowerShell syntax:

Method 1: Using Clear() and Add()

$pool = Get-Item IIS:\AppPools\MyAppPool
$pool.recycling.periodicRestart.schedule.Collection.Clear()
$pool.recycling.periodicRestart.schedule.Collection.Add("01:30:00")
$pool.recycling.periodicRestart.schedule.Collection.Add("12:00:00")
$pool | Set-Item

Method 2: Leveraging Configuration Attributes

$pool = Get-WebAppPool -Name "MyAppPool"
$pool.recycling.periodicRestart.schedule.Attributes["value"].Value = @("01:30:00","12:00:00")
$pool | Set-Item

Method 3: Creating Extension Functions

function Add-RecycleSchedule {
    param(
        [Parameter(Mandatory=$true)]
        [string]$AppPoolName,
        [Parameter(Mandatory=$true)]
        [string[]]$Times
    )
    
    $pool = Get-WebAppPool -Name $AppPoolName
    $pool.recycling.periodicRestart.schedule.Attributes["value"].Value = $Times
    $pool | Set-Item
}

Add-RecycleSchedule -AppPoolName "CriticalApp" -Times @("02:00:00", "14:00:00")

When working with PowerShell's New-TimeSpan, remember to convert to the IIS expected format:

$time = New-TimeSpan -Hours 1 -Minutes 30
$formattedTime = "{0:hh\:mm\:ss}" -f $time
$pool.recycling.periodicRestart.schedule.Collection.Add($formattedTime)

Here's how to apply consistent schedules across multiple pools:

$pools = @("WebApp1", "WebApp2", "WebApiPool")
$recycleTimes = @("01:00:00", "13:00:00")

foreach ($poolName in $pools) {
    $pool = Get-WebAppPool -Name $poolName
    $pool.recycling.periodicRestart.schedule.Attributes["value"].Value = $recycleTimes
    $pool | Set-Item
}

After configuration, verify settings with:

Get-WebAppPool -Name "MyAppPool" | 
    Select-Object -ExpandProperty Recycling | 
    Select-Object -ExpandProperty periodicRestart | 
    Select-Object -ExpandProperty schedule

When automating IIS 7.5/8.0 configurations via PowerShell, many administrators find themselves stuck between two undesirable approaches:

# The verbose method:
Set-ItemProperty 'IIS:\\AppPools\\DemoPool' -Name recycling.periodicRestart.time -Value "01:30:00"

# The configuration-heavy method:
Add-WebConfiguration -Filter "system.applicationHost/applicationPools" -Value @{recycling=@{periodicRestart=@{time="01:30:00"}}}

Here's how I prefer to handle Application Pool configuration in PowerShell:

$pool = Get-Item IIS:\\AppPools\\MyAppPool
$pool.processModel.identityType = "SpecificUser"
$pool.processModel.userName = "domain\\user"
$pool.processModel.password = "password"
$pool.managedRuntimeVersion = "v4.0"
$pool | Set-Item

The stumbling block comes when trying to configure recycling schedules with this clean syntax. The straightforward attempt:

$pool.recycling.periodicRestart.schedule = (New-TimeSpan -Hours 1 -Minutes 30)

Fails because the schedule property is actually a collection that requires special handling.

After much experimentation, here's the cleanest method I've found:

$pool = Get-Item IIS:\\AppPools\\MyAppPool
$recycling = $pool.Recycling
$periodicRestart = $recycling.periodicRestart

# Clear existing schedules if needed
$periodicRestart.scheduleCollection.Clear()

# Add new schedules
$periodicRestart.scheduleCollection.Add("01:30:00")
$periodicRestart.scheduleCollection.Add("12:00:00")

$pool | Set-Item

Putting it all together:

$appPools = @("ProductionPool", "StagingPool", "TestPool")
$recycleTimes = @("01:30:00", "12:00:00", "18:00:00")

foreach ($poolName in $appPools) {
    $pool = New-WebAppPool -Name $poolName -Force
    
    # Basic configuration
    $pool.processModel.identityType = "SpecificUser"
    $pool.processModel.userName = "domain\\user"
    $pool.processModel.password = "password"
    $pool.managedRuntimeVersion = "v4.0"
    
    # Recycling configuration
    $periodicRestart = $pool.recycling.periodicRestart
    $periodicRestart.scheduleCollection.Clear()
    
    foreach ($time in $recycleTimes) {
        $periodicRestart.scheduleCollection.Add($time)
    }
    
    # Configure other recycling settings
    $periodicRestart.memory = 0 # Disable memory-based recycling
    $periodicRestart.privateMemory = 0
    
    $pool | Set-Item
}

For those who need to work with existing app pools:

function Set-AppPoolRecycling {
    param(
        [string]$appPoolName,
        [string[]]$recycleTimes
    )
    
    $pool = Get-Item "IIS:\\AppPools\\$appPoolName"
    $schedule = $pool.recycling.periodicRestart.schedule
    
    # Convert to collection for manipulation
    $scheduleColl = $pool.recycling.periodicRestart.scheduleCollection
    $scheduleColl.Clear()
    
    foreach ($time in $recycleTimes) {
        $scheduleColl.Add($time)
    }
    
    $pool | Set-Item
}

# Usage:
Set-AppPoolRecycling -appPoolName "CriticalAppPool" -recycleTimes @("02:00:00", "14:00:00")