Skip to main content

How to Recycle an Application Pool in IIS from Batch Script

Recycling an application pool is one of the most important IIS maintenance operations. It gracefully shuts down the current worker process (w3wp.exe) and spins up a fresh one, clearing accumulated memory, releasing stale file handles, and resetting application state. Unlike stopping and starting a pool (which creates a brief outage), recycling uses an overlapping strategy where the new worker process starts before the old one finishes, enabling near-zero-downtime restarts.

In this guide, we will explore how to recycle application pools from a Batch Script using appcmd.exe, including targeted recycling, scheduled recycling, and monitoring techniques.

Understanding Recycling vs. Stop/Start

OperationDowntimeWhat Happens
RecycleNear zeroIIS starts a new worker process, then gracefully shuts down the old one. Requests are seamlessly handed over.
Stop + StartSeveral secondsThe pool stops completely (all requests fail), then restarts. Clients receive errors during the gap.
iisreset3-10+ secondsThe entire IIS server stops and restarts, affecting all websites.

Recycling is almost always the preferred option for production environments.

Method 1: Simple Application Pool Recycle

@echo off
setlocal

set "appcmd=%SystemRoot%\System32\inetsrv\appcmd.exe"
set "pool_name=DefaultAppPool"

:: Verify Admin
net session >nul 2>&1
if %errorlevel% neq 0 (
echo [ERROR] Administrator privileges required.
pause
exit /b 1
)

echo Recycling application pool "%pool_name%"...

"%appcmd%" recycle apppool /apppool.name:"%pool_name%"

if %errorlevel% equ 0 (
echo [SUCCESS] "%pool_name%" has been recycled.
) else (
echo [ERROR] Failed to recycle. Pool may be stopped or does not exist.
)

pause
endlocal

What Happens During a Recycle

  1. IIS creates a new worker process (w3wp.exe) for the pool.
  2. New incoming requests are routed to the new process.
  3. The old worker process finishes handling its remaining in-flight requests.
  4. Once the old process is idle (or a shutdown timeout is reached), it terminates.
  5. The pool is now running on a fresh process with clean memory.

Method 2: Recycling All Application Pools

For server-wide maintenance, you may want to recycle every pool on the machine.

@echo off
setlocal enabledelayedexpansion

set "appcmd=%SystemRoot%\System32\inetsrv\appcmd.exe"

net session >nul 2>&1
if !errorlevel! neq 0 (
echo [ERROR] Admin required.
pause
exit /b 1
)

echo Recycling ALL application pools...
echo.

set "count=0"
set "skipped=0"

for /f "tokens=*" %%P in ('"%appcmd%" list apppool /text:name') do (
echo Recycling: %%P
"%appcmd%" recycle apppool /apppool.name:"%%P" >nul 2>&1

if !errorlevel! equ 0 (
echo [OK]
set /a "count+=1"
) else (
echo [SKIP] Pool may be stopped.
set /a "skipped+=1"
)
)

echo.
echo [DONE] Recycled !count! pool(s), skipped !skipped!.
pause
endlocal
info

A pool that is in the Stopped state cannot be recycled. The script above gracefully skips stopped pools rather than failing.

Method 3: Post-Deployment Recycle

The most common use case for recycling is after deploying new application code. Recycling forces the .NET CLR to reload updated DLLs from disk.

@echo off
setlocal

set "appcmd=%SystemRoot%\System32\inetsrv\appcmd.exe"
set "pool_name=ProductionApiPool"
set "deploy_source=\\BuildServer\Releases\API\Latest\*"
set "deploy_target=C:\inetpub\sites\api"

net session >nul 2>&1
if %errorlevel% neq 0 (
echo [ERROR] Admin required.
pause
exit /b 1
)

echo =============================================
echo ZERO-DOWNTIME DEPLOYMENT
echo =============================================
echo.

:: Step 1: Copy new files (the old worker still serves requests)
echo [1/2] Deploying new files...
xcopy "%deploy_source%" "%deploy_target%\" /s /e /y /q >nul

if %errorlevel% neq 0 (
echo [ERROR] File copy failed. Aborting deployment.
pause
exit /b 1
)

echo Files copied.

:: Step 2: Recycle the pool (seamless transition to new code)
echo [2/2] Recycling pool "%pool_name%"...
"%appcmd%" recycle apppool /apppool.name:"%pool_name%"

if %errorlevel% equ 0 (
echo.
echo [SUCCESS] Deployment complete. New code is live.
) else (
echo.
echo [ERROR] Recycle failed. Manual intervention may be needed.
)

pause
endlocal

Why Recycling Works for Deployments

When you copy new .dll files into the application directory, the currently running worker process still has the old DLLs loaded in memory. The new files are sitting on disk but unused. When the pool recycles, the new worker process loads the fresh DLLs from disk, effectively activating the new code. This is why recycling after deployment is essential.

Method 4: Recycling with Verification

A robust script should verify the recycle was successful by checking that the Process ID (PID) of the worker changed.

@echo off
setlocal enabledelayedexpansion

set "appcmd=%SystemRoot%\System32\inetsrv\appcmd.exe"
set "pool_name=DefaultAppPool"

net session >nul 2>&1
if !errorlevel! neq 0 (
echo [ERROR] Admin required.
pause
exit /b 1
)

:: Get the current worker process PID before recycle
set "old_pid="
for /f "tokens=*" %%P in ('"%appcmd%" list wp /apppool.name:"%pool_name%" /text:wp.name 2^>nul') do (
set "old_pid=%%P"
)

if not defined old_pid (
echo [INFO] No active worker process. Pool may be idle or stopped.
echo Recycling anyway...
"%appcmd%" recycle apppool /apppool.name:"%pool_name%"
pause
exit /b 0
)

echo Current Worker PID: !old_pid!
echo Recycling...

"%appcmd%" recycle apppool /apppool.name:"%pool_name%"

if !errorlevel! neq 0 (
echo [ERROR] Recycle command failed.
pause
exit /b 1
)

:: Wait for the new worker to spin up
echo Waiting for new worker process...
set /a "attempts=0"
set "max_attempts=10"

:pid_check
timeout /t 2 /nobreak >nul
set /a "attempts+=1"

set "new_pid="
for /f "tokens=*" %%P in ('"%appcmd%" list wp /apppool.name:"%pool_name%" /text:wp.name 2^>nul') do (
set "new_pid=%%P"
)

if defined new_pid (
if not "!new_pid!" == "!old_pid!" (
echo [SUCCESS] Worker recycled. Old PID: !old_pid! -^> New PID: !new_pid!
pause
exit /b 0
)
)

if !attempts! lss !max_attempts! goto pid_check

if defined new_pid (
echo [WARNING] PID unchanged after !max_attempts! checks. Recycle may still be in progress.
) else (
echo [WARNING] No new worker process detected. Pool may be idle (no requests yet^).
)

pause
endlocal

Configuring Automatic Recycling Rules

Instead of manually recycling pools, you can configure automatic recycling schedules via appcmd.

Time-Based Recycling

@echo off
setlocal

set "appcmd=%SystemRoot%\System32\inetsrv\appcmd.exe"
set "pool_name=ProductionPool"

:: Recycle every 6 hours (360 minutes)
"%appcmd%" set apppool /apppool.name:"%pool_name%" /recycling.periodicRestart.time:"06:00:00"

if %errorlevel% equ 0 (
echo [OK] Pool will auto-recycle every 6 hours.
) else (
echo [ERROR] Failed to set recycling interval.
)

pause
endlocal

Schedule-Based Recycling (Specific Times)

@echo off
setlocal

set "appcmd=%SystemRoot%\System32\inetsrv\appcmd.exe"
set "pool_name=ProductionPool"

:: Disable interval-based recycling (set to 0) so only scheduled times apply
"%appcmd%" set apppool /apppool.name:"%pool_name%" /recycling.periodicRestart.time:"00:00:00"

:: Add scheduled recycles at 2 AM and 2 PM
"%appcmd%" set apppool /apppool.name:"%pool_name%" /+recycling.periodicRestart.schedule.[value='02:00:00']
"%appcmd%" set apppool /apppool.name:"%pool_name%" /+recycling.periodicRestart.schedule.[value='14:00:00']

if %errorlevel% equ 0 (
echo [OK] Pool will auto-recycle at 2:00 AM and 2:00 PM daily.
) else (
echo [ERROR] Failed to set recycling schedule.
)

pause
endlocal

Memory-Based Recycling

@echo off
setlocal

set "appcmd=%SystemRoot%\System32\inetsrv\appcmd.exe"
set "pool_name=LeakyAppPool"

:: Recycle when private memory exceeds 1 GB (value in KB)
"%appcmd%" set apppool /apppool.name:"%pool_name%" /recycling.periodicRestart.privateMemory:1048576

if %errorlevel% equ 0 (
echo [OK] Pool will auto-recycle when memory exceeds 1 GB.
) else (
echo [ERROR] Failed to set memory-based recycling.
)

pause
endlocal

Common Mistakes

The Wrong Way: Using IISRESET Instead of Recycling

:: WRONG - Restarts the ENTIRE IIS server
iisreset /restart

Output Concern: iisreset stops and restarts all IIS services, affecting every website and pool on the server. If you only need to refresh one application, recycling its specific pool is the correct, surgical approach.

The Wrong Way: Recycling a Stopped Pool

:: WRONG - A stopped pool has no worker to recycle
"%appcmd%" recycle apppool /apppool.name:"StoppedPool"

You cannot recycle a pool that is not running. The command will return an error. Start the pool first with appcmd start apppool, then recycle if needed.

Best Practices

  1. Recycle instead of stop/start: Recycling provides near-zero-downtime transitions, while stop/start creates a gap.
  2. Recycle after code deployments: New DLLs are only loaded when the worker process restarts. Recycling ensures the new code is active.
  3. Set memory-based auto-recycling: For applications known to have memory leaks, configure privateMemory limits to recycle before the server runs out of RAM.
  4. Verify with PID checks: After recycling, confirm the worker process PID changed to ensure the recycle actually completed.
  5. Schedule during low traffic: If using scheduled recycling, target early morning hours when request volume is lowest to minimize the impact of the brief transition period.

Conclusion

Recycling application pools from a Batch Script is the preferred maintenance operation for production IIS servers. The appcmd recycle apppool command initiates a graceful worker process replacement that keeps the site responsive during the transition. For automated environments, configuring time-based, schedule-based, or memory-based recycling rules ensures pools stay healthy without manual intervention. Combined with post-deployment verification and PID monitoring, recycling scripts form the backbone of professional IIS lifecycle management.