Learn about Windows PowerShell
Summary: Guest blogger, Corey Roth, talks about using Windows PowerShell to create and manage SharePoint online sites.
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.
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.
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 = "firstname.lastname@example.org"
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.
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $password)
$ctx.Credentials = $credentials
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.
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.
$webCreationInformation = New-Object Microsoft.SharePoint.Client.WebCreationInformation
$webCreationInformation.Url = "site1"
$webCreationInformation.Title = "Site 1"
$webCreationInformation.WebTemplate = "STS#0"
$newWeb = $ctx.Web.Webs.Add($webCreationInformation)
We then pass the WebCreationInformation object to the Webs collection, which we find on our ClientContext.Web object.
If you have used the Client Object Model before, you know you aren’t done yet. You need to call ClientContext.Load() with $newWeb. We follow this with ClientContext.ExecuteQuery().
This will send the request to SharePoint and your site will be created. Running the script won’t yield any output.
You might be tempted to add a $newWeb statement after the script executes. However, this will give you the following error message:
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.
That’s because, the Web object contains a number of collections that also need to be loaded explicitly by using ClientContext.Load. However, you can request properties such as the Title or Url.
Write-Host "Title" $newWeb.Title
Here is what the entire script looks like to create a site in SharePoint Online:
To delete a site, the process is fairly similar. Instead of setting the ClientContext URL to the site collection, set it to the site that you want to delete:
$siteUrl = “https://mytenant.sharepoint.com/sites/sitecollection/site1”
After we add the script for the references and authentication, get a reference to ClientContex.Web, load it, and call ExecuteQuery().
$web = $ctx.Web
Finally, call the Web.DeleteObject method to delete the site. This will require an additional call to ExecuteQuery to finalize the deletion.
At this point, the site has been deleted.
Here is the complete script for deleting a site in SharePoint Online:
$siteUrl = “https://mytenant.sharepoint.com/sites/mysitecollection/site1”
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials("email@example.com", $password)
Write-Host $web.Title "Site Deleted"
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().
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)
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.
Here is the complete script to get all sites in a site collection from SharePoint Online:
$siteUrl = "https://mytenant.sharepoint.com/sites/mysitecollection"
$sites = $rootWeb.Webs
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.
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.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at firstname.lastname@example.org, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
Nice article and thanks for sharing your knowledge. I really appropriate your views. If you find same related blog or
https://www.officeclip.com/">online contact management just visit today.
Thanks for the handy demonstration. I'm very delighted to learn how to create and manage sharepoint online site by using PowerShell. It's truly an educative read for me. Glad to be here... http://www.reviewwebhosting.org
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
What I have to do to initialize the collection?
Connect-SPOService -Url https://contoso-admin.sharepoint.com -credential email@example.com
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.
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
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.
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.
awesome post, thanks.