SPManage.ps1 - SharePoint Farm Management

Script

Name

Description

Last Modified Date

Download

SPManage.ps1

Remote SharePoint Farm Management

22/07/2012

SPManage.ps1

How it works

The script connects to the local farm and identifies each server.  Alternatively servers can be loaded from a configuration file.

Commands can then be issued on each server automatically via a remote power shell session.  Commands are either built in as switches or you can execute your own commands using the -Command switch.

Note: PowerShell Remoting is a technology that allows for remote administration of computers.  Using it has security implications which should be considered before enabling.  Please consult additional sources if you are not sure about appropriate security measures when using PowerShell Remoting.

Script Help PS > .\SPManage.ps1 -Help

SPManage v1.1 - Script Help
This script uses powershell remoting which must be enabled on the servers
Parameters:
   -ServerType ('All', 'APP', 'WFE' - Default is ALL) This is only usable if you are on a local SP 2010 Farm otherwise use -configFile
   -UserName (If on a different domain or if you require a different user account set this value eg; MyDomain\MyUser
   -Password (The password if specifying a UserName)
   -Command (An optional command to execute remotely. eg; {Get-Process})
   -ConfigFile (An xml file that contains a list of servers)
   -Credential (Pass in Get-Credential if you don't want to type in a plain text password)
   -Ping (ICMP echo executed to all servers)
   -VerifyRemoting (Creates a remote session to confirm remoting is available)
   -QueryDiskSpace (Enumerates logical drives on each server)
   -QueryWebApps (Enumerates SP2010 Web Applications and Application Pools (Local Query))
   -QueryFarm (Enumerates servers within the SP2010 farm (Local Query))
   -RestartSPServices (Restarts all SP2010 Services including User Code Host. Security note: If you don't want user code host running do not call this command.)
   -StopSPServices (Stops all SP2010 Services including User Code Host and Search.
   -StartSPServices (Starts all SP2010 Services including User Code Host. Security note: If you don't want user code host running do not call this command.)
   -IISReset (Runs IISReset on all servers)
   -ClearSessions (Clears any existing remote sessions with the servers - not normally needed as script cleans up)
   -NoSP (If the command being issued does not require the SharePoint snappin, use this switch to improve performance)
   -Silent (Don't prompt for Un Safe Commands)
   -Help (This output)
Server configuration:
Each server in the farm must allow PS Remoting.
run: winrm quickconfig (This will allow remote management on HTTP)
run: winrm quickconfig -transport:SSL (This will allow remote management on HTTPS)
run: winrm s winrm/config/client '@{TrustedHosts="RemoteComputer"}' (Adds a trusted computer to the server config)

Cross Domain:
If your client computer is on another domain, you may need to run an additional command on the remote server(s) to allow.
run: 
New-Itemproperty -name LocalAccountTokenFilterPolicy -path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System -propertyType DWord -value 1
(This will allow the remote computer to be controlled from a machine on another domain)

Examples:
.\SPManage.ps1 -Ping #Simple ping test
.\SPManage.ps1 -VerifyRemoting #Creates a remote session on each server
.\SPManage.ps1 -ServerType:App -VerifyRemoting #Creates a remote session on each Application server
.\SPManage.ps1 -UserName "DOM\User" -Password "MyPass" -VerifyRemoting #Uses a username and password to connect to the remote servers
.\SPManage.ps1 -configFile devfarm.xml -Credential (Get-Credential) -VerifyRemoting #Uses a config file to connect to servers
.\SPManage.ps1 -Command {get-process} #Gets the running processes for all servers in the farm
.\SPManage.ps1 -IISReset #Issues IISReset using remote powershell session
.\SPManage.ps1 -RestartSPServices #Restarts all SP2010 Services on each server  
.\SPManage.ps1 -ServerType App -RestartSPServices #Restarts all SP2010 Services on the application servers

Notes:
Sessions are cleaned up at the end of the script.
If a session already exists with the remote computer the script will attempt to use it.
You don't need to specify a username and password if your account has correct permissions
This script must be run from an elevated PowerShell session.
Be aware of the double hop issue when trying to execute SharePoint commands remotely.  If the database is not on the same server the call will fail.

Example Config File (For use when you are not running on a server in the SP Farm. Specify -configFile parameter)
<?xml version="1.0" ?>
<Config>
<Servers>
	<Server Address="SPSERVER01" />
	<Server Address="SPSERVER02" />
</Servers>
</Config>

 

SPManage.ps1

Download Script: SPManage.ps1

#SharePoint Farm management script
#Written By: Tim Wheeler (https://codemonkeysoftware.atlassian.net)
#.\SPManage.ps1 -Help (for information on this script)
param (
		[Parameter(Position=0)]
        [ValidateSet('All','APP','WFE')]
        [System.String]$ServerType = "All",
		$Command,
		$UserName,
		$Password,
		$configFile,
		$Credential,
		[switch] $Ping,
		[switch] $IISReset,
		[switch] $ClearSessions,
		[switch] $QueryDiskSpace,
		[switch] $RestartSPServices,
		[switch] $StopSPServices,
		[switch] $StartSPServices,
		[switch] $VerifyRemoting,
		[switch] $NoSP,
		[switch] $Silent,
		[switch] $QueryFarm,
		[switch] $QueryWebApps,
		[switch] $Help
		)
if($userName -ne $null)
{
	$plainTextPassword = $Password 
	$secureStringPassword   = ConvertTo-SecureString  $plainTextPassword -AsPlainText  -force  
	$Credential = New-Object System.Management.Automation.PSCredential ($UserName, $secureStringPassword)
}
$version = "1.1"
#region Help and Feedback
function Message([string] $computerName, $message)
{
	Write-Host "$computerName : $message"
}
function Help()
{
	Write-Host 
	Write-Host ("SPManage v" + $version +" - Script Help")
	Write-Host 
	Write-Host "This script uses powershell remoting which must be enabled on the servers"
	Write-Host ""
	Write-Host "Parameters:"
	Write-Host "   -ServerType ('All', 'APP', 'WFE' - Default is ALL) This is only usable if you are on a local SP 2010 Farm otherwise use -configFile"
	Write-Host "   -UserName (If on a different domain or if you require a different user account set this value eg; MyDomain\MyUser"
	Write-Host "   -Password (The password if specifying a UserName)"
	Write-Host "   -Command (An optional command to execute remotely. eg; {Get-Process})"
	Write-Host "   -ConfigFile (An xml file that contains a list of servers)"
	Write-Host "   -Credential (Pass in Get-Credential if you don't want to type in a plain text password)"
	Write-Host "   -Ping (ICMP echo executed to all servers)"
	Write-Host "   -VerifyRemoting (Creates a remote session to confirm remoting is available)"
	Write-Host "   -QueryDiskSpace (Enumerates logical drives on each server)"
	Write-Host "   -QueryWebApps (Enumerates SP2010 Web Applications and Application Pools (Local Query))"
	Write-Host "   -QueryFarm (Enumerates servers within the SP2010 farm (Local Query))"
	Write-Host "   -RestartSPServices (Restarts all SP2010 Services including User Code Host. Security note: If you don't want user code host running do not call this command.)"
	Write-Host "   -StopSPServices (Stops all SP2010 Services including User Code Host and Search."
	Write-Host "   -StartSPServices (Starts all SP2010 Services including User Code Host. Security note: If you don't want user code host running do not call this command.)"
	Write-Host "   -IISReset (Runs IISReset on all servers)"
	Write-Host "   -ClearSessions (Clears any existing remote sessions with the servers - not normally needed as script cleans up)"
	Write-Host "   -NoSP (If the command being issued does not require the SharePoint snappin, use this switch to improve performance)"
	Write-Host "   -Silent (Don't prompt for Un Safe Commands)"
	Write-Host "   -Help (This output)"
	Write-Host 
	Write-Host "Server configuration:"
	Write-Host "Each server in the farm must allow PS Remoting."
	Write-Host "run: winrm quickconfig (This will allow remote management on HTTP)"
	Write-Host "run: winrm quickconfig -transport:SSL (This will allow remote management on HTTPS)"
	Write-Host "run: winrm s winrm/config/client '@{TrustedHosts=`"RemoteComputer`"}' (Adds a trusted computer to the server config)"
	Write-Host ""
	Write-Host "Cross Domain:"
	Write-Host "If your client computer is on another domain, you may need to run an additional command on the remote server(s) to allow."
	Write-Host "run: "
	write-host "New-Itemproperty -name LocalAccountTokenFilterPolicy -path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System -propertyType DWord -value 1"
	Write-Host "(This will allow the remote computer to be controlled from a machine on another domain)"
	Write-Host 
	Write-Host "Examples:"
	Write-Host ".\SPManage.ps1 -Ping #Simple ping test"
	Write-Host ".\SPManage.ps1 -VerifyRemoting #Creates a remote session on each server"
	Write-Host ".\SPManage.ps1 -ServerType:App -VerifyRemoting #Creates a remote session on each Application server"
	Write-Host ".\SPManage.ps1 -UserName `"DOM\User`" -Password `"MyPass`" -VerifyRemoting #Uses a username and password to connect to the remote servers"
	Write-Host ".\SPManage.ps1 -configFile devfarm.xml -Credential (Get-Credential) -VerifyRemoting #Uses a config file to connect to servers"
	Write-Host ".\SPManage.ps1 -Command {get-process} #Gets the running processes for all servers in the farm"
	Write-Host ".\SPManage.ps1 -IISReset #Issues IISReset using remote powershell session"
	Write-Host ".\SPManage.ps1 -RestartSPServices #Restarts all SP2010 Services on each server  "
	Write-Host ".\SPManage.ps1 -ServerType App -RestartSPServices #Restarts all SP2010 Services on the application servers"
	Write-Host 
	Write-Host "Notes:"
	Write-Host "Sessions are cleaned up at the end of the script."
	Write-Host "If a session already exists with the remote computer the script will attempt to use it."
	Write-Host "You don't need to specify a username and password if your account has correct permissions"
	Write-Host "This script must be run from an elevated PowerShell session."
	Write-Host "Be aware of the double hop issue when trying to execute SharePoint commands remotely.  If the database is not on the same server the call will fail."
	Write-Host
	Write-Host "Example Config File (For use when you are not running on a server in the SP Farm. Specify -configFile parameter)"
	Write-Host "<?xml version=`"1.0`" ?>"
	Write-Host "<Config>"
	Write-Host "<Servers>"
	Write-Host "	<Server Address=`"SPSERVER01`" />"
	Write-Host "	<Server Address=`"SPSERVER02`" />"
	Write-Host "</Servers>"
	Write-Host "</Config>"
}
if($Help)
{
	Help;
	return;
}
#endregion
#region SharePoint Commands
function GetFarmServers()
{
	$farm = Get-SPFarm
	if($farm -eq $null)
	{
		throw "Cannot connect to local farm"
	}
	if($ServerType -ieq "All")
	{
		return $farm.Servers | where-object {$_.Role -ne "Invalid" }
	}
	if($ServerType -ieq "APP")
	{
		return $farm.Servers | where-object {$_.Role -ieq "Application" }
	}
	if($ServerType -ieq "WFE")
	{
		return $farm.Servers | where-object {$_.Role -ieq "WebFrontEnd" }
	}
}
function QueryFarmCommand()
{
	$farm = Get-SPFarm
	if($farm -eq $null)
	{
		throw "Cannot connect to local farm"
	}
	Write-Host 
	Write-Host "Farm Details"
	Write-Host
	$farm.Servers | sort $_.Role | Ft -AutoSize:$true @{Expression={$_.Role};Label="Role"}, @{Expression={$_.Address};Label="Address";}, @{Expression={$_.Status};Label="Status"}
}
#endregion
#region SharePoint Windows Services
function RestartSharePointServices()
{
	StopSharePointServices
	StartSharePointServices
}
function StartSharePointServices()
{
	$serviceRestart = {
	net start "SharePoint 2010 User Code Host";
	net start "SharePoint 2010 Timer";
	net start "SharePoint 2010 Administration";
	net start "SharePoint Server Search 14";}
	RemoteExecuteCommand $servers $serviceRestart $false $true "Stopping SharePoint Services (2010)"
}
function StopSharePointServices()
{
	$serviceRestart = {
	net stop "SharePoint 2010 User Code Host";
	net stop "SharePoint 2010 Timer";
	net stop "SharePoint 2010 Administration";
	net stop "SharePoint Server Search 14";}
	RemoteExecuteCommand $servers $serviceRestart $false $true "Stopping SharePoint Services (2010)"
}
#endregion
#region IO Functions and Config
function LoadSPSnappin($session)
{
	if($NoSP -eq $false)
	{
		RemoteExecute $session {Add-PSSnapin "Microsoft.SharePoint.PowerShell"} "Loading SharePoint Snappin"
	}
}
function Get-ScriptDirectory 
{ 
	$Invocation = (Get-Variable MyInvocation -Scope 1).Value 
	$dir = Split-Path $Invocation.MyCommand.Path 
	return $dir
} 
function Set-Directory($location)
{
	[IO.Directory]::SetCurrentDirectory((Convert-Path($location)))
}
function LoadConfiguration($configFile)
{
	if(![IO.File]::Exists($configFile))
	{
		throw "Could not configuration file: $configFile. Script Terminated."
	}
	write-host "Found configuration file: $configFile"
	try
	{
		$config = [xml] (get-content -Path $configFile)
		write-host -ForegroundColor Green "Configuration Loaded Successfully"
		return $config.Config
	}
	catch
	{
		Write-Error "Configuration file $config found but could not be loaded. May not be valid XML"
		throw
	}
}
#endregion

#region Ping / Verify Command
function VerifyRemotingCommand($servers)
{
	[bool] $failure = $false;
	foreach($server in $servers)
	{
		Write-Host "Attempting to create a remote PowerShell session in" $server.Address
		$session = $null
		$session = GetRemoteSession $server
		if($session -ne $null -and $session.Availability -eq "Available")
		{
			Write-Host -NoNewline ($server.Address + " : ")
			Write-Host -ForegroundColor Green "Success"
		}
		else
		{
			$failure = $true
			throw "Failed"
		}
		trap 
		{
			Write-Host -ForegroundColor Red ($server.Address + " : Remote PowerShell command failed. " + $_.Exception.Message)
			continue;
		}
	}
	if($failure)
	{
		throw "One or more servers would not except a remote PowerShell session"
	}
}
function PingCommand($servers)
{
	[bool] $failure = $false;
	foreach($server in $servers)
	{
		if(!(Ping $server.Address $Credential))
		{
			$failure = $true;
		}
#		trap 
#		{
#			Write-Host -ForegroundColor Red ($server.Address + ": Ping command failed. " + $_.Exception.Message)
#			continue;
#		}
	}
	if($failure)
	{
		throw "One or more PING commands failed"
	}
}
function Ping([string] $computerName)
{
	Write-Host -NoNewline "PING: $computerName"
	$result = Test-Connection -ComputerName $computerName -ErrorAction:Stop -Count 2 -Quiet;
	if($result)
	{
		Write-Host " Connection Successful"
	}
	else
	{
		Write-Host -ForegroundColor Red " Connection Failed"
	}
	return $result;
}
#endregion
#region Remoting Session Managment
#clears any sessions it can find between this computer and the remote computer
function ClearSessions([string] $computerName)
{
	$session = Get-PSSession -ComputerName $computerName -ErrorAction:SilentlyContinue
	while($session -ne $null)
	{
		Message $session.ComputerName "Removing session"
		Remove-PSSession $session.Id
		$session = Get-PSSession -ComputerName $computerName -ErrorAction:SilentlyContinue
	}
}
#Only clears sessions in the sessionWatch variable
function ClearCurrentSessions()
{
	#ensures PowerShell Session Cleanup	
	foreach($key in $sessionWatch.Keys)
	{
		$session = $sessionWatch[$key]
		if($session -ne $null)
		{
			Write-Host "Exiting remote session " $session.Id
			Remove-PSSession $session.Id
		}
	}
	$sessionWatch.Clear();
}
function GetRemoteSession($server)
{
	$computerName = $server.Address;
	if($sessionWatch.ContainsKey($computerName))
	{
		return $sessionWatch[$computerName];
	}
	$session = Get-PSSession -ComputerName $computerName -ErrorAction:SilentlyContinue
	if($session -ne $null -and $session.Availability -eq "Available")
	{
		$sessionWatch.Add($computerName, $session);
		return $session;
	}
	if($Credential -ne $null)
	{
		$session = New-PSSession -ComputerName $computerName -Credential $Credential -ErrorAction:Stop
	}
	else
	{
		$session = New-PSSession -ComputerName $computerName -ErrorAction:Stop
	}
	
	$sessionWatch.Add($computerName, $session);
	return $session
}
#endregion
#region Command Execution
function RemoteExecuteCommand($servers, $command, [bool] $job, [bool] $requiresSP, [string] $comment)
{
	$jobWatch = @{};
	$jobWatch.Clear();
	foreach($server in $servers)
	{
		$session = GetRemoteSession $server
		if($requiresSP)
		{
			LoadSPSnappin $session
		}
		if($job)
		{
			$pendingJob = RemoteExecuteJob $session $command $comment
			$jobWatch.Add($session.ComputerName,$pendingJob)
		}
		else
		{
			RemoteExecute $session $command $comment
		}
		trap 
		{
			Write-Host -ForegroundColor Red ($computerName + ": $Command : " + $_.Exception.Message)
			break;
		}
	}
	if($job)
	{
		foreach($id in $jobWatch.Keys)
		{
			Message $id "Receiving Job"
			$pendingJob = $jobWatch[$id] 
			while($pendingJob.State -eq "Running")
			{
				Sleep 1
				Receive-Job -InstanceId $pendingJob.InstanceId
			}
			Write-Host
			$pendingJob  | Wait-Job | Receive-Job
			Remove-Job $pendingJob.InstanceId # | Out-Null
		}
		$jobWatch.Clear()
	}
}
function RemoteExecute($session, $script, $comment)
{
	Message $session.ComputerName $comment
	Invoke-Command -Session $session -ScriptBlock $script
}
function RemoteExecuteJob($session, $script, $comment)
{
	Message ($session.ComputerName + " [Job]") $comment
	return Invoke-Command -AsJob -Session $session -ScriptBlock $script
}
function LocalExecute($script, $comment)
{
	Message $env:ComputerName $comment
	Invoke-Command -ScriptBlock $script
}
#Provides a confirmation prompt
function SafeFunction($question)
{
	if(!$Silent)
	{
		if((Read-Host $question) -ine "Y")
		{
			Write-Host "Cancelled"
			return $false;
		}
	}
	return $true;
}
#endregion
$sessionWatch = @{};
$sessionWatch.Clear();
try
{
	cls
	$servers = $null;
	if($configFile -eq $null)
	{
		#Gets the servers depending on ServerType (All, App, WFE)
		$servers = GetFarmServers
	}
	else
	{
		$scriptDir = Get-ScriptDirectory
		$config = LoadConfiguration ([System.IO.Path]::Combine($scriptDir,$configFile))
		$servers = $config.Servers.Server
		if($servers -eq $null -or $servers.Count -eq 0)
		{
			throw "No servers to process, please check config file."
		}
	}
	if($ClearSessions)
	{
		$servers | ForEach-Object { ClearSessions $_.Address }
	}
	if($Ping)
	{
		PingCommand $servers
	}
	if($VerifyRemoting)
	{
		VerifyRemotingCommand $servers
	}
	if($QueryFarm)
	{
		$query = {QueryFarmCommand}
		LocalExecute $query "Query Farm (Local)"
	}
	if($QueryWebApps)
	{
		$query = {Get-SPWebApplication | Ft -AutoSize:$true @{Expression={$_.DisplayName};Label="Name"}, @{Expression={$_.Url};Label="Url";}, @{Expression={$_.ApplicationPool.Name};Label="App Pool"}, @{Expression={$_.ApplicationPool.Status};Label="Status"}}
		#RemoteExecuteCommand $servers $query $true $true "Query Web Applications"
		LocalExecute $query "Query Web Applications (Local)"
	}
	if($IISReset)
	{
		$q = "Are you sure you want to execute IISReset on selected servers? Press Y to confirm."	
		if(SafeFunction($q))
		{
			RemoteExecuteCommand $servers {& IISReset} $true $false "IISRESET"
		}
	}
	if($Command -ne $null)
	{
		$q = "Are you sure you want to execute a custom command on all servers in config $configFile ? Press Y to confirm."	
		if(SafeFunction($q))
		{
			RemoteExecuteCommand $servers $Command $true (!$NoSP) $Command.ToString().Trim()
		}
	}
	if($QueryDiskSpace)
	{
		$query = { gwmi win32_logicaldisk -filter "drivetype=3" | Ft -AutoSize:$true @{Expression={$_.deviceid};Label="Device"},@{Expression={"{0:0.0}" -f ($_.size/1gb)};Label="Size (GB)"}, @{Expression={"{0:0.0}" -f ($_.freespace/1gb)};Label="Free Space (GB)"}, @{Expression={"{0:0.0}" -f (([int64]$_.size - [int64]$_.freespace)/1gb)};Label="Used (GB)"}, @{Expression={"{0:0}%" -f ((([int64]$_.size - [int64]$_.freespace) * 100.0)/$_.size)};Label="Used Percentage"}}
		RemoteExecuteCommand $servers $query $false $false "Query Disk Space"
	}
	
	if($RestartSPServices)
	{
		RestartSharePointServices
	}
	if($StopSPServices)
	{
		StopSharePointServices
	}
	if($StartSPServices)
	{
		StartSharePointServices
	}
	Write-Host "Complete (Use switch -Help for script information)"
}
finally
{
	ClearCurrentSessions
}



 

 

 

CodeMonkey Software is a division of JCHMedia www.jchmedia.com