PowerShell: Script to Update SharePoint Content Type Document Template


Introduction

One of the great things about Content Types are that you can have a document template associated to the Content Type.

This means that when you create a new document a customised word template with its own look and feel can be used to guide the user through the process of filling the document and setting up the content type’s metadata.

Recently, we had the situation where we had content types being used across lots of site collections each for the different departments in the organisation.

One of the management overheads is when a document template needs to be updated. How can you do that programmatically using PowerShell?

Well the following script helps you get that done.

Solution

The PowerShell Script, Update-SPContentTypeDocumentTemplate.ps1 below does just that.

So how do you use it?

Well you provide the URL of the site, the path to the document template and also the name of the Content Type.

It will access the site, check if the content type already has a document template, upload the selected document and configure the content type to use the new document template.

You can decide if you want to update all the child content types which have been assigned to document libraries. if you want to do this which is recommended then make sure you include the -UpdateChild switch.

Example

So what would happen if you wanted to update a number of sites?

Well you can just get a list of the sites and pipe that array into the command and it will update the content type on each site.

Also the same technique could be used to update multiple content types on a number of sites.

Download Script

The PowerShell Script is part of the iThink SharePoint PowerShell GitHub Repository, which can be found here:

https://github.com/ithinksharepoint/PowerShell

Anyway, I hope you find the solution useful, please let me know if you did and also if you have some additions or changes then please share them!

All the best

Simon

PowerShell: Repairing SharePoint Content Databases


Introduction

When you get a warning from SharePoint saying that a database has orphaned content, the message is not the most helpful.

This is an example of health analyser message in SharePoint Central Admin

orphaneditemshealthcheckerror

There is no information on which content database is affected, although you can click on the “Repair Automatically” option but you don’t have any context as to which database is affected. This is going to be a problem if we need to repair the database via a documented change process.

The following process will show you how to identify the item and database that is affected.

Start by running the SharePoint Management Shell.

Get-SPContentDatabase | %{Write-Host $_; $_.Repair($false);}

This will return something like below:-

Database Name 1
<OrphanedObjects Count="0" />
Database Name 2
<OrphanedObjects Count="0" />
Database Name 3
<OrphanedObjects Count="0" />
Database Name 4
<OrphanedObjects Count="0" />
Database Name 4
<OrphanedObjects Count="0" />
Database Name 5
<OrphanedObjects Count="0" />
Database Name 6
<OrphanedObjects Count="0" />
Database Name 7
<OrphanedObjects Count="0" />
Database Name 8
<OrphanedObjects Count="1">
 <Orphan Type="SecurityScope" SiteId="{166BF298-DE66-4919-A506-4F3412E8A86E}"
Name="sites/test/SiteCollectionImages/Forms/Video/docsethomepage.aspx" InRecycleBin="Yes" />
</OrphanedObjects>

Now we can see that there is some orphaned content in content database “Database Name 8”.

To fix the database, run the following:-

$repairdb = Get-SPContentDatabase -Identity "[Database Name]";

Check that the database is the right one by outputting the $repairdb object.

To repair the database run the following command.

$repairdb.Repair($true)
<OrphanedObjects Count="1">
 <Orphan Type="SecurityScope" SiteId="{166BF298-DE66-4919-A506-4F3412E8A86E}"
Name="sites/test/SiteCollectionImages/Forms/Video/docsethomepage.aspx" InRecycleBin="Yes" />
</OrphanedObjects>

Now let’s check that the corruption is gone by re-running the command

Get-SPContentDatabase | %{Write-Host $_; $_.Repair($false);}

We should see that there are no more corruptions

Now go into Central Admin site and re-run the failed health rule, to resolve the issue.

PowerShell: Getting Sandbox Solutions in a SharePoint Web Application


Introduction

Like all good SharePoint developers we have been using Sandbox Solutions where we can. Of course one of the problems with Sandbox solutions is that its difficult to find out what you have installed and where.
This is particularly important if you have a Sandbox solution that is used for branding and is installed into a number of site collections.
Therefore I built a script which will retrieve sandbox solutions in a web application.
You can filter which sandbox solutions by the name.
Please fill free to use and modify the script, though make sure you test it before using in Production.
If you do make some enhancement that you think is useful, please let me know as would love to see what additional functionality is useful.

How does the script works

The script is a PowerShell script which works in the following way:
  • The script is run by providing the Url for the Web Application
  • The script will enumerate through all the site collections in the web application and creates an array object which has two properties, SiteCollection and Solution
  • Once all site collections have been enumerated then the array will be outputted.
This way you can use the output for further processing steps. For example, to filter the results for one solution and upgrade the solutions in all the site collections returned.
The script is shown below:

param
(
[Parameter(Mandatory=$false, HelpMessage='Solution Name')]
[string]$SolutionName="",
[Parameter(Mandatory=$false, HelpMessage='Solution Name')]
[string]$WebApplicationUrl="")$memoryAssignment = Start-SPAssignment;
$numberOfSolutionsFound = 0;
$webApplication = Get-SPWebApplication -Identity $WebApplicationUrl -ErrorAction SilentlyContinue -AssignmentCollection $memoryAssignment;
if($webApplication -ne $null)
{
#enumerate through site collections in web application
$allSites = Get-SPSite -WebApplication $webApplication -Limit ALL -Confirm:$false -AssignmentCollection $memoryAssignment;
foreach($checkSite in $allSites)
{
#Write-Output "Checking Site " $checkSite.Url " for solution " $SolutionName;
if($SolutionName -eq "")
{
$checkSolutions = Get-SPUserSolution -Site $checkSite -AssignmentCollection $memoryAssignment;
foreach($solution in $checkSolutions)
{
$output = New-Object -TypeName "System.Object";
Add-Member -InputObject $output -MemberType NoteProperty -Name "Solution" -Value "";
Add-Member -InputObject $output -MemberType NoteProperty -Name "SiteCollection" -Value "";
$output.Solution = $solution;
$output.SiteCollection = $checkSite;
Write-Output -InputObject $output;
$numberOfSolutionsFound++
}
}
else
{
$checkSolution = Get-SPUserSolution -Identity $SolutionName -Site $checkSite -ErrorAction SilentlyContinue -AssignmentCollection $memoryAssignment;
if($checkSolution -ne $null)
{
$output = New-Object -TypeName "System.Object";
Add-Member -InputObject $output -MemberType NoteProperty -Name "Solution" -Value "";
Add-Member -InputObject $output -MemberType NoteProperty -Name "SiteCollection" -Value "";
$output.Solution = $checkSolution;
$output.SiteCollection = $checkSite;
Write-Output -InputObject $output;
$numberOfSolutionsFound++
}
}
}
}&lt;/p&gt;
&lt;p style="direction: ltr; margin-top: 0; margin-left: 0; width: 7.5875in;"&gt;Write-Output "Found $numberOfSolutionsFound Instances of Solution $SolutionName";
Stop-SPAssignment $memoryAssignment;&lt;/p&gt;
&lt;p style="direction: ltr; margin-top: 0; margin-left: 0; width: 7.5875in;"&gt;

 

How to execute the script

 To execute the script do the following:
  • Logon to SharePoint 2013 server
  • Run the SharePoint Management Shell
    • .\Get-SPUserSolutionInWebApplication -WebApplicationUrl https://sharepoint
    • There is an optional parameter -SolutionName which allows you to only return the solutions with a particular name

The script will output an array of Solution Objects with an associated Site Collection object.

We can assign a value to the output and then do some further processing using that value.

Here is an example of the output from the script without assigning the result to a variable.

getusersolutionsfromwebapp

To do something more useful then assign the output to a variable. You can then enumerate through the variable array.

For example, the following screenshot shows the output being assigned to a variable $solutions and then it is being enumerated using the following:

$solutions | %{Write-Host $_.Solution.Name “in” $_.SiteCollection.Url}

enumerate-usersolutionarray

Downloads

If you would like to try out the PowerShell script, then you can download the script here:

Get-SPUserSolutionInWebApplication.zip

Please fill free to use and modify the script, though make sure you test it before using in Production.

Also let me know if you find it useful and if you have made some cool changes let me know as always looking for ways to make things better!

PowerShell: Deleting SharePoint List Items


Introduction

Whilst I love SharePoint Workflows and how versatile they can be, they can generate quite a bit of data. Well mine do as I like to log plenty of information so that the support / admin teams can find out what’s going on with the workflow.

Unfortunately when you log plenty of information this means that the workflow history list can get quite large.

One of the workflows that we built over a ten month period has processed a couple of hundred thousand list items and has created about 3 million list items in the workflow history list.

We wanted to clear down this list and so PowerShell came to the rescue.

Solution

We built the following PowerShell script which you provide the following parameters:0

  • Url – Url of web hosting the workflow history list
  • AgeOfItemsToDelete – days of logs that you wish to keep
  • ListName – the display name of the workflow history list
  • NumberOfItemsInBatch – the number of items that should be returned in each query.

The original script looked like this:-

param
(
	[Parameter(Mandatory=$false, HelpMessage='System Host Url')]
	[string]$Url = "http://sharepoint",
	[Parameter(Mandatory=$false, HelpMessage='List Name')]
	[string]$ListName = "Workflow Tasks",
	[Parameter(Mandatory=$false, HelpMessage='Age of items in list to keep (number of days).')]
	[int]$AgeOfItemsToKeepInDays = 365,
	[Parameter(Mandatory=$false, HelpMessage='What size batch should we delete the items in?')]
	[int]$NumberOfItemsToDeleteInBatch = 1000
	
)

$assignmentCollection = Start-SPAssignment -Global;

$rootWeb=Get-SPWeb $Url -AssignmentCollection $assignmentCollection;

$listToProcess = $rootWeb.Lists.TryGetList($ListName);
if($listToProcess -ne $null)
{
	$startTime = [DateTime]::Now;
	$numberOfDaysToDelete = [TimeSpan]::FromDays($AgeOfItemsToKeepInDays);
	$deleteItemsOlderThanDate = [DateTime]::Now.Subtract($numberOfDaysToDelete);
	$isoDeleteItemsOlderThanDate = [Microsoft.SharePoint.Utilities.SPUtility]::CreateISO8601DateTimeFromSystemDateTime($deleteItemsOlderThanDate);
	$numberOfItemsToRetrieve = $NumberOfItemsToDeleteInBatch;
	
	$camlQueryString = [String]::Format("<Where><Leq><FieldRef Name='Modified' /><Value IncludeTimeValue='TRUE' Type='DateTime'>{0}</Value></Leq></Where>", $isoDeleteItemsOlderThanDate);
	$camlQuery = New-Object -TypeName "Microsoft.SharePoint.SPQuery" -ArgumentList @($listToProcess.DefaultView);
	$camlQuery.Query=$camlQueryString;
	$camlQuery.RowLimit=$numberOfItemsToRetrieve;
	
	$deletedItemCount=0;
	
	do
	{
		$camlResults = [Microsoft.SharePoint.SPListItemCollection] $listToProcess.GetItems($camlQuery);
		$itemsCountReturnedByQuery = $camlResults.Count;
		Write-Host "Executed Query and found " $camlResults.Count " Items";
		
		$listItemDataTable = [System.Data.DataTable]$camlResults.GetDataTable();
		foreach($listItemRow in $listItemDataTable.Rows)
		{
			$listItemIdToDelete = $listItemRow["ID"];
			$listItemModifiedDate = $listItemRow["Modified"];
			Write-Host "Deleting Item $listItemIdToDelete - Modified $listItemModifiedDate";
			$listItemToDelete = $listToProcess.GetItemById($listItemIdToDelete);
			$listItemToDelete.Delete();
			$deletedItemCount++;
		}
	}
	while($itemsCountReturnedByQuery -gt 0)
	
	$totalSecondsTaken = [DateTime]::Now.Subtract($startTime).TotalSeconds;
	Write-Host -ForegroundColor Green "Processing took $totalSecondsTaken seconds to delete $deletedItemCount Item(s).";
}
else
{
	Write-Host "Cannot find list: " $ListName;
}

Stop-SPAssignment -Global -AssignmentCollection $assignmentCollection;

Write-Host "Finished";

However, whilst this worked ok for a list that was quite small. When we went to use it on the Production environment it performed like a dog. Fortunately the script was run out of hours so didn’t impact the environment too much. Though the memory that it consumed was quite large (4GB) after deleting the second item.

There was something seriously wrong with approach being taken, so after a bit of investigation it was obvious what was going on.

Look at the script again, there is a line of code that is:-

$listToProcess.Items.DeleteItemById($listItemIdToDelete);

Well it turns out that this call, updates the collection after the DeleteItemById function is called. So we made a small modification and the offensive line became:-

$listItemToDelete = $listToProcess.GetItemById($listItemIdToDelete);
$listItemToDelete.Delete();

This change meant that the PowerShell session now only consumed 270Mb (I say only!) and memory usage did not rise. The deletion of the items was much quicker too, probably by a few 1000%!

Here is the final script for completeness.

param
(
[Parameter(Mandatory=$false, HelpMessage='System Host Url')]
[string]$Url = "<a href="http://sharepoint&quot;">http://sharepoint"</a>,
[Parameter(Mandatory=$false, HelpMessage='List Name')]
[string]$ListName = "Workflow Tasks",
[Parameter(Mandatory=$false, HelpMessage='Age of items in list to keep (number of days).')]
[int]$AgeOfItemsToKeepInDays = 365,
[Parameter(Mandatory=$false, HelpMessage='What size batch should we delete the items in?')]
[int]$NumberOfItemsToDeleteInBatch = 1000

)

$assignmentCollection = Start-SPAssignment -Global;

$rootWeb=Get-SPWeb $Url -AssignmentCollection $assignmentCollection;

$listToProcess = $rootWeb.Lists.TryGetList($ListName);
if($listToProcess -ne $null)
{
$startTime = [DateTime]::Now;
$numberOfDaysToDelete = [TimeSpan]::FromDays($AgeOfItemsToKeepInDays);
$deleteItemsOlderThanDate = [DateTime]::Now.Subtract($numberOfDaysToDelete);
$isoDeleteItemsOlderThanDate = [Microsoft.SharePoint.Utilities.SPUtility]::CreateISO8601DateTimeFromSystemDateTime($deleteItemsOlderThanDate);
$numberOfItemsToRetrieve = $NumberOfItemsToDeleteInBatch;

$camlQueryString = [String]::Format("&lt;Where&gt;&lt;Leq&gt;&lt;FieldRef Name='Modified' /&gt;&lt;Value IncludeTimeValue='TRUE' Type='DateTime'&gt;{0}&lt;/Value&gt;&lt;/Leq&gt;&lt;/Where&gt;", $isoDeleteItemsOlderThanDate);
$camlQuery = New-Object -TypeName "Microsoft.SharePoint.SPQuery" -ArgumentList @($listToProcess.DefaultView);
$camlQuery.Query=$camlQueryString;
$camlQuery.RowLimit=$numberOfItemsToRetrieve;

$deletedItemCount=0;

do
{
$camlResults = [Microsoft.SharePoint.SPListItemCollection] $listToProcess.GetItems($camlQuery);
$itemsCountReturnedByQuery = $camlResults.Count;
Write-Host "Executed Query and found " $camlResults.Count " Items";

$listItemDataTable = [System.Data.DataTable]$camlResults.GetDataTable();
foreach($listItemRow in $listItemDataTable.Rows)
{
$listItemIdToDelete = $listItemRow["ID"];
$listItemModifiedDate = $listItemRow["Modified"];
Write-Host "Deleting Item $listItemIdToDelete - Modified $listItemModifiedDate";
$listItemToDelete = $listToProcess.GetItemById($listItemIdToDelete);
$listItemToDelete.Delete();
$deletedItemCount++;
}
}
while($itemsCountReturnedByQuery -gt 0)

$totalSecondsTaken = [DateTime]::Now.Subtract($startTime).TotalSeconds;
Write-Host -ForegroundColor Green "Processing took $totalSecondsTaken seconds to delete $deletedItemCount Item(s).";
}
else
{
Write-Host "Cannot find list: " $ListName;
}

Stop-SPAssignment -Global -AssignmentCollection $assignmentCollection;

Write-Host "Finished";

Hope that helps someone who has the same problem. Please let me know if you have an alternative solution!

Links to the scripts:-

Delete-ListItemsOlderThan-Slow.txt

Delete-ListItemsOlderThanV2.txt

PowerShell, SharePoint and Memory Leaks (Start-SPAssignment)


Introduction

Over the last couple of years I have been using PowerShell to do more & more within my SharePoint environments.

Recently I have been writing a script to move a large number of SharePoint Web objects from one site collection to another.

Whilst this was being tested, it was obvious that something wasn’t quite right as I kept seeing the following messages in the ULS logs:-

Potential excessive number of SPRequest objects (60) currently unreleased on thread 10. Ensure that this object or its parent (such as an SPWeb or SPSite) is being properly disposed. This object is holding on to a separate native heap. This object will not be automatically disposed…

 

Now I am used to seeing these “Object Not disposed messages” in logs when writing code and the majority are easily fixed. Please see Stefan Goßner’s excellent article on Disposing of SPWeb and SPSite objects for more information.

The reason for the errors being displayed are that the objects are not being correctly disposed after they are used. This leads to the memory slowly being consumed and not released. Eventually if there are enough objects created, then memory pressure is placed on the server and performance is impacted.

With C# code this is easily sorted out by either calling .Dispose() or wrapping the code that creates the disposable object with a using() statement around the assignment line.
An example is shown below.

For example:-


using(SPWeb web=_site.OpenWeb(“http://sharepoint"))

{

if(web.Exists)

{

//do something

}

}

However PowerShell objects such as the SPWebPipeBind object or SPSitePipeBind object don’t have a .Dispose() function. So how the heck do you stop them from leaking memory?

Well the secret is that you make use of the command Start-SPAssignment and Stop-SPAssignment cmdlets.

Start-SPAssignment / Stop-SPAssignment Cmdlets

Whilst using this commands I came across a number of blog posts but the approach that they were taken didn’t really work and I would still see the same memory leaks.
The set of Cmdlets should be used in the following fashion:-


$assignmentCollection = Start-SPAssignment;

$allWebs = Get-SPWeb –Site <a href="http://sharepoint">http://sharepoint</a> –AssignmentCollection $assignmentCollection

foreach($web in $allWebs)

{

Enable-SPFeature –Identity “Feature” –Url $web.Url –AssignmentCollection $assignmentCollection;

}

Stop-SPAssignment $assignmentCollection;

Walking through the code you will see that the Start-SPAssignment is used to return an SPAssignmentCollection object. We keep a reference to this SPAssignmentCollection so that we can use it to collect any objects that need disposing.

So the next question is how do we use the SPAssignmentCollection object to collect the objects?

Well a large number of the SharePoint PowerShell functions have an optional parameter called AssignmentCollection. The variable that we created using Start-SPAssignment should then be passed into these SharePoint PowerShell cmdlets.

For example, Get-SPWeb has the a set of parameters (content taken from TechNet):-

Parameter Required Description
Identity Optional Specifies the name or full or partial URL of the subsite. If you use a relative path, you must specify the Site parameter.A valid URL in the form http://server_name or a relative path in the form of /SubSites/MySubSite.
AssignmentCollection Optional Manages objects for the purpose of proper disposal. Use of objects, such as SPWeb or SPSite, can use large amounts of memory and use of these objects in Windows PowerShell scripts requires proper memory management. Using the SPAssignment object, you can assign objects to a variable and dispose of the objects after they are needed to free up memory. When SPWeb, SPSite, or SPSiteAdministration objects are used, the objects are automatically disposed of if an assignment collection or the Global parameter is not used.
Confirm Optional Prompts you for confirmation before executing the command. For more information, type the following command: get-help about_commonparameters
Filter Optional Specifies the server-side filter to use for the specified scope.The type must be a valid filter in the form {filterName <operator> “filterValue”}.
Limit Optional Limits the maximum number of subsites to return. The default value is 200. To return all sites, enter ALLThe type must be a valid number greater than 0 or ALL.
Site Optional Specifies the URL or GUID of the site collection from which to list subsites.The type must be a valid URL, in the form of http://server_name; a GUID, in the form 1234-5678-9807, or an SPSite object.
WhatIf Optional Displays a message that describes the effect of the command instead of executing the command. For more information, type the following command: get-help about_commonparameters

When the AssignmentCollection parameter is passed then the objects that are created by that function are then stored in this AssignmentCollection.

When the objects are no longer required then they can be released using:-

Stop-SPAssignment –AssignmentCollection $assignmentCollection

This will free the memory and the associated objects.

SPAssignment Modes of Operation

The SPAssignment cmdlets can be used in a couple of ways:-

  • Simple mode, which is used by passing the –Global switch which seems to start monitoring the objects being created and will ensure that they are all disposed of when you call Stop-SPAssignment.
  • Advanced mode, which is where you create an AssignmentCollection using Start-SPAssignment and then manage the entries added to the collection.

I prefer the advanced mode as you are in control of when objects are being disposed of and also after running your PowerShell script a few times you can see where the appropriate calls to release memory should be placed.

When to use Stop-SPAssignment

One of the mistakes that I made was not calling the Stop-SPAssignment at the right time.

For example, say we have a script which is looping through all the Site Collections in a Web Application and then looping through all the Webs in a Site Collection. For each web object an operation is performed such as enabling a feature.

Well I had put the Stop-SPAssignment function being called at the end of the function. Guess what happened?

The PowerShell script would eat loads of RAM. Actually the memory would be freed but with large web applications the PowerShell script would slowing down considerably as the memory allocated started to impact the server.

The fix was relatively simple, move the Stop-SPAssignment function to the end of each loop which processes each site collection. This kept the PowerShell script from consuming too much RAM and it  performed well.

Not too often

I could have moved the Stop-SPAssignment function so that it is called after each web has been processed, however my testing found that this slowed down the script too much as Stop-SPAssignment was called.

Conclusion

Using the SPAssignment cmdlets are essential to building production ready PowerShell scripts. They will ensure that the servers in your SharePoint farm are not affected by over zealous PowerShell scripts consuming huge quantities of RAM!

PowerShell Script: Add user as Site Collection Admin to all sites in Web Application


 

Introduction

 

A few days ago I had a request from one of the SharePoint team. Could we give him Site Collection Admin rights to all site collections in a web application.

Now one method would be to use a Web Application User Policy (see below) and give them the full access permission.

WebApplicationPolicy

However, we didn’t want to take that approach.

So we looked at using a PowerShell script. The important point was that we did not want to assign the permission using the Owner or SecondaryContact properties of the SPSiteobject. Instead we just wanted to add the user as the site collection admin.

When using the user interface this is achieved by doing the following:-

  • Browse to the site collection
  • Click Site Settings
  • Click Site collection administrators (Under Users and Permissions)
    • Add the user to the list and click OK.
      After a bit of investigation using PowerShell I could see how this permissions was set.

 

Solution

So to the solution, how is a user configured as a Site Collection Admin?

Well it turns out that its based on the following property, SPUser.IsSiteAdmin. Site Collection Administrators have the IsSiteAdmin property set to true.

 

Once that information had been understood, then the script was relatively easy and the following script was created:-

param
(
	[Parameter(Mandatory=$true, HelpMessage='username in format DOMAIN\username')]
	[string]$Username = "",
	[Parameter(Mandatory=$true, HelpMessage='url for web application e.g. http://collab')]
	[string]$WebApplicationUrl = ""

)

Write-Host "Setting up user $Username as site collection admin on all sitecollections in Web Application $WebApplicationUrl" -ForegroundColor White;
$webApplication = Get-SPWebApplication $WebApplicationUrl;

if($webApplication -ne $null)
{

foreach($siteCollection in $webApplication.Sites){
    Write-Host "Setting up user $Username as site collection admin for $siteCollection" -ForegroundColor White;
    $userToBeMadeSiteCollectionAdmin = $siteCollection.RootWeb.EnsureUser($Username);
    if($userToBeMadeSiteCollectionAdmin.IsSiteAdmin -ne $true)
    {
        $userToBeMadeSiteCollectionAdmin.IsSiteAdmin = $true;
        $userToBeMadeSiteCollectionAdmin.Update();
        Write-Host "User is now site collection admin for $siteCollection" -ForegroundColor Green;
    }
    else
    {
        Write-Host "User is already site collection admin for $siteCollection" -ForegroundColor DarkYellow;
    }

    Write-Host "Current Site Collection Admins for site: " $siteCollection.Url " " $siteCollection.RootWeb.SiteAdministrators;
}
}
else
{
	Write-Host "Could not find Web Application $WebApplicationUrl" -ForegroundColor Red;
}

The PowerShell script accepts the following parameters:-

  • -UserName – the user to add as a site collection admin (DOMAIN\username)
  • -WebApplication – the URL to the Web Application that should be updated

The script tries to get resolve the Web Application. The script then runs through each site collection in the web application and ensures that the user can be found in the site collection.

If the user is not already a site collection admin then the property is updated and the user object is saved.

The script is not perfect and could have a bit more exception handling, for example the Get-SPWebApplication call does not check the return value.

 

Anyway the link to the PowerShell script is below (just rename the file extension from .txt to ps1):-

Set-UserAsSiteCollectionAdminOnWebApplication.txt

PowerShell Script to Restart SharePoint 2013 Farm services


 

Introduction

 

A while back I wrote a quick script to ‘Restart services on a SharePoint 2010 Farm’, this blog post can be found here.

 

Anyway, I have slightly updated it for SharePoint 2013. Its pretty much the same though I am also restarting the Search process too and also checking that the service exists on the server before restarting.

How you find it useful

 

The Script

 

Here is the script:-

 <pre>
param
(
    [Parameter(Mandatory=$false, HelpMessage='-ServiceNames Optional, provide a set of service names to restart.')]
    [Array]$ServiceNames=@("SharePoint Timer Service","SharePoint Administration", "SharePoint Server Search 15", "World Wide Web Publishing Service","IIS Admin Service")
);

Write-Host "Attempting to get SharePoint Servers in Farm" -ForegroundColor White;
$farm = Get-SPFarm;
$servers = $farm.Servers;
Write-Host "Found" $servers.Count "Servers in Farm (including database servers)" -ForegroundColor White;
foreach($server in $servers)
{
    if($server.Role -ne [Microsoft.SharePoint.Administration.SPServerRole]::Invalid)
    {
        Write-Host "Attempting to restart services on" $server.Name -ForegroundColor White;
        foreach($serviceName in $ServiceNames)
        {
            $serviceInstance = Get-Service -ComputerName $server.Name -Name $serviceName -ErrorAction SilentlyContinue;
            if($serviceInstance -ne $null)
            {
                Write-Host "Attempting to restart service" $serviceName ".." -ForegroundColor White -NoNewline;
                try
                {
                    $restartServiceOutput="";
                    Restart-Service -InputObject $serviceInstance;
                    Write-Host " Done!" -ForegroundColor Green;
                }
                catch
                {
                    Write-Host "Error Occured: " $_.Message;
                }
            }
        }
    }
}
</pre>

Download the script here: Restart-SPServices2013.zip