Create and Manage SharePoint Online Sites by Using PowerShell

Microsoft Scripting Guy, Ed Wilson, is here. Today we have a guest post by SharePoint MVP, Corey Roth. Corey will be presenting at TechEd 2014 this year in Houston, and he has taken the time to share his thoughts with us today. Here is a little bit about Corey:

Corey Roth is an independent SharePoint consultant specializing in solutions in the Oil and Gas industry. Corey is a four-time recipient of the Microsoft MVP award in SharePoint Server. He has always focused on rapid adoption of new Microsoft technologies, including SharePoint 2013, Office 365, and Visual Studio 2013. When it comes to SharePoint, he specializes in ECM, Enterprise Search, and Apps. As an active member of the SharePoint community, he often speaks at conferences, events, and user groups. In his blog, Dot Net Mafia, he posts about the latest technology and SharePoint. Corey is a member on the board for the Houston SharePoint Users Group. He has also recently founded an App development company called SP2, specializing in apps for SharePoint 2013.

Note All scripts from today's post are available in the Script Center Repository:

The SharePoint Online Management Shell has been out for a while now, allowing you to script some tasks with your Office 365 deployment. It lets you use Windows PowerShell to create site collections, work with users and groups, and upgrade site collections in SharePoint Online. However, if you are used to working with Windows PowerShell for SharePoint 2013 on-premises, you will notice that a number of common tasks are missing such as creating sites or enabling features.

Luckily, we can make use of the Client Script Object Model (CSOM) in Windows PowerShell to accomplish some of these tasks. Today, we're going to look at creating sites, deleting sites, and getting a list of sites in SharePoint Online. It takes a few more lines of script, but this post will get you started.

Getting started

To work with CSOM in SharePoint Online, we need access to the client assemblies. You can either download the SharePoint Server 2013 Client Components SDK, or you can get the assemblies from a local SharePoint 2013 installation. You don't need to run your Windows PowerShell script on a SharePoint server. It will work from Windows 7 with SP1 or later.

After you have located the assemblies, we need to load them in our script. We can do this a number of ways. If you are working directly on your SharePoint server, you can use LoadWithPartialName:

However, if you copied the assemblies manually somewhere, you might want to use Add-Type:

Add-Type -Path "c:\folder\Microsoft.SharePoint.Client.dll"

Add-Type -Path "c:\folder\Microsoft.SharePoint.Client.Runtime.dll"

We'll add these types to all of our scripts today.

Authentication

After referencing our assemblies, we need to authenticate to SharePoint Online and get a ClientContext object. We use similar command when working with the Managed Client Object Model for SharePoint.

First, store the path to the site collection we want to work with, in addition to the user name. Be sure to specify a user name that has permission to create sites. If you prefer, you could request all of these variables as parameters to your script.

$siteUrl = “https://mytenant.sharepoint.com/sites/mysitecollection”

$username = "admin@mytenant.onmicrosoft.com"

Now, we need to read the password. The easiest way to do this is with Read-Host and the AsSecureString parameter. When you run the script, you will be prompted to type the password.

$password = Read-Host -Prompt "Enter password" -AsSecureString

We have everything we need to get a ClientContext now. Initialize a new one by using New-Object and pass it to $siteUrl. We’ll name ours $ctx.

$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)

Then we need to add the credentials by using the SharePointOnlineCredentials object, and pass $username and $password as parameters. Then, we assign $credentials to the ClientContext object.

At this point, we can use our ClientContext object to create, delete, and retrieve a list of sites. We’ll use the previous lines in all of our scripts.

Creating sites

In our first example, we’ll start with a script to create a site. The beginning of the script will contain the assembly references and authentication script we showed above. When creating a site, we use the WebCreationInformation object.

In the following script, I specify a relative URL to the site collection and a title. The WebTemplate parameter takes any supported web template in SharePoint Online. You can get a list of these by using SharePoint Online Management Shell and the Get-SPOWebTemplate cmdlet. In the following example, I am using the Team Site template, which is STS#0.

Getting a list of sites

Retrieving a list of sites is a bit more complicated, because of the load requirements around the Web object. Chris O'Brien's post, Using CSOM in PowerShell scripts with Office 365, pointed me in the right direction to make this work. In this script, we’ll return all subsites of the site collection in SharePoint Online. We’ll start the script by using the same script as before to add references and authentication.

Start by getting a reference to the root web of the site collection:

$rootWeb = $ctx.Web

Next, we use the Webs property of the Web object to get the list of all subsites. We then need to load both these objects and call ClientContext.ExecuteQuery().

$ctx.Load($rootWeb)

$ctx.Load($sites)

$ctx.ExecuteQuery()

Unfortunately, you can’t simply call $sites to see a nice list. You need to iterate through each subsite and use ClientContext.Load and ClientContext.ExecuteQuery() to populate the values. That means the script makes a round-trip to the server once for each site, which is not exactly efficient. Here’s how we iterate through the sites and write out the Title and Url properties:

foreach($site in $sites)

{

$ctx.Load($site)

$ctx.ExecuteQuery()

Write-Host $site.Title "-" $site.Url

}

The script looks like this when executed:

You’ll notice this returns all subsites including those used by apps. That’s why you see Yammer in the list. You could write additional script to filter that, if desired.

Complete script

Here is the complete script to get all sites in a site collection from SharePoint Online:

By using the Client Script Object Model, you can automate more tasks in SharePoint Online. If you are going to be at TechEd North America this year, be sure to check out my session, Windows PowerShell 3.0 Administration with Microsoft SharePoint 2013 and SharePoint Online (OFC-B328). We’ll cover this example and more for SharePoint Online and SharePoint on-premises.

~Corey

Note Corey has also agreed to be a special guest at the Scripting Guys booth at TechEd. So that will be a great time to meet with Corey and to have all your Windows PowerShell and SharePoint questions answered. WooHoo!

Thank you, Corey, for sharing this. Join me tomorrow when I will talk about more cool Windows PowerShell stuff.

Hello Scripting Guy, I've got the that feedback if I try to execute the script:

"Write-Host "Title" $newWeb.Title
format-default : The collection has not been initialized. It has not been requested or the request has not been executed. It may need
to be explicitly requested.
+ CategoryInfo : NotSpecified: (:) [format-default], CollectionNotInitializedException
+ FullyQualifiedErrorId : Microsoft.SharePoint.Client.CollectionNotInitializedException,Microsoft.PowerShell.Commands.FormatDefaul
tCommand"

Thanks for this. I was thinking we had been very short changed on the Powershell Cmd-Lets for Sharepoint Online, but this looks like it will overcome a lot of what is missing.

One Question: - If we want to create a site based on a custom template rather than a standard one, how do we go about that? I have manually created a site from a custom template, but when I examine it to see the template it was created from it reports the built
in template that the custom template was derived from, not the custom template itself.

Danny

30 Jun 2014 3:27 PM

Awesome script. What I was wondering about, if you create a site with this script and you want to give it unique permissions, how to create groups for it so that when a user wants to add members they see it in the quick links on the left top corner as
associated groups?

Is there a way to convert a PowerShell credential object as returned by Get-Credential into a Microsoft.SharePoint.Client.SharePointOnlineCredentials?

I want to pass the credentials to my script but I have a PS credential. I don't have the username and password at the time the script is called.

~Randy

Michael Boggs

8 Sep 2014 3:20 PM

Is there a way to make the "list of sites" script and make it recursive so that it lists all sites and subsites? currently it only lists sites directly off the site collection root, but not any nested sites. This would be really helpful. Thank you.

I am using the script for creating at site and I am getting this error: format-default :

The collection has not been initialized. It has not been
requested or the request has not been executed. It may need to be explicitly
requested.
+ CategoryInfo : NotSpecified: (:) [format-default], CollectionNo
tInitializedException
+ FullyQualifiedErrorId : Microsoft.SharePoint.Client.CollectionNotInitial
izedException,Microsoft.PowerShell.Commands.FormatDefaultCommand

I have built a more basic script that works fine with the credentials I am using. The script is below. The only difference I see is that I am not specifying credentials in my script, I am already authenticated to SharePoint online using Connect-SPOService

I am seeming to have this same error on a number of scripts others have built so just trying to figure out what I am doing wrong.

Thanks

James

10 Jul 2015 5:19 PM

Is it possible to use Powershell script to change a Office365 subsite to become a fully independent site? Issue we have is a customer has created subsites inadvertantly and has may subfolders and files.