SharePoint Maintenance

From time to time you may need to temporarily make SharePoint unavailable due to applying a CU, Service Pack etc. One of my customers places an App_Offline.htm file at the root of the IIS Virtual Directory for each Web Application on each WFE server within their farm, this presents users with a nice friendly message when the try to access SharePoint explaining that SharePoint is currently unavailable due to scheduled maintenance.

This works really well and they wanted to automate the process for copying the App_Offline.htm file prior to performing maintenance, I wrote the following two scripts to automate this. The first script copies the file (to enter maintenance), the second deletes it (to return SharePoint into service).

The script has logic to handle MOSS 2007, SharePoint 2010 and 2013. It will iterate through all Web Apps and Zones and copy the App_Offline holding page to the Webroot of the IIS site for each Web Application on each server that hosts a Web Application. Simply execute with PowerShell on a server within the farm, the script expects there to be an App_Offline.htm file within the directory that the script is executed from. The script needs to be run using an account that has local admin permissions on each server and makes the presumption that SMB/CIFS access is available.

Enter Maintenance

#Load SharePoint assembly
$Assemblies = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

#Check if the script is running on MOSS 2007
If (Test-Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12"){$Mode="2007"}

#Grab all Web Apps
$WebApps = [Microsoft.SharePoint.Administration.SPWebService]::ContentService.WebApplications

#Retrieve Servers
$Farm = [Microsoft.SharePoint.Administration.SPFarm]::Local
$SPServers = $Farm.Servers | Where {$_.Role -eq "Application"} | Foreach {$_.Name}

Foreach ($WebApp in $WebApps)
{
Foreach ($URL in $WebApp.AlternateUrls)
    {
    If ($Mode = "2007")
    {
    $WebRoot = ($WebApp.GetIisSettingsWithFallback($URL.URLZone)).Path.FullName -replace ":","$"
    }
    Else
    {
    $WebRoot = ($WebApp.GetIisSettingsWithFallback($URL.Zone)).Path.FullName -replace ":","$"
    }
    Write-Host "Setting the Holding Page for" $WebApp.Name "- Zone:" $Url.URLZone -ForegroundColor Green
    Foreach ($Server in $SPServers)
        {
        Write-Host "-Updating" $Server -ForegroundColor Green
        Copy-Item "app_offline.htm" "\\$Server\$Webroot\"
        }
    }
}

Return SharePoint into Service

#Load SharePoint assembly
$Assemblies = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

#Check if the script is running on MOSS 2007
If (Test-Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12"){$Mode="2007"}

#Grab all Web Apps
$WebApps = [Microsoft.SharePoint.Administration.SPWebService]::ContentService.WebApplications

#Retrieve Servers
$Farm = [Microsoft.SharePoint.Administration.SPFarm]::Local
$SPServers = $Farm.Servers | Where {$_.Role -eq "Application"} | Foreach {$_.Name}

Foreach ($WebApp in $WebApps)
{
Foreach ($URL in $WebApp.AlternateUrls)
    {
    If ($Mode = "2007")
    {
    $WebRoot = ($WebApp.GetIisSettingsWithFallback($URL.URLZone)).Path.FullName -replace ":","$"
    }
    Else
    {
    $WebRoot = ($WebApp.GetIisSettingsWithFallback($URL.Zone)).Path.FullName -replace ":","$"
    }
    Write-Host "Removing the Holding Page for" $WebApp.Name "- Zone:" $Url.URLZone -ForegroundColor Green
    Foreach ($Server in $SPServers)
        {
        Write-Host "-Updating" $Server -ForegroundColor Green
        Remove-Item "\\$Server\$Webroot\app_offline.htm"
        }
    }
}

Brendan Griffin - @brendankarl