SharePoint Automation Gary Lapointe – Founding Partner, Aptillon, Inc.


Announcing My Custom SharePoint Online Cmdlets

For quite a while now I’ve been pointing out the lack of cmdlets that are available for working with Office 365 and SharePoint 2013 (SharePoint Online) and I’ve mentioned several times that someone should really do something about that and that I’d love to be that person if only I had the time. Well, as it turns out, over Christmas break I managed to find some free time so I went ahead and got started on my own custom cmdlets for SharePoint Online which I’m now officially releasing with this post.

If you refer back to my earlier post where I detailed the SharePoint Online cmdlets provided by Microsoft, you’ll note that there are currently only 30 cmdlets – with my new offering I just about double that number by adding an additional 27 cmdlets. I’m only going to briefly outline by design goals and a couple simple examples in this article so I encourage you to visit the downloads page of my site to download the installer and/or source code for the project and for details about each cmdlet you should go to the command index page (click the SharePoint Online tab to see the cmdlets).

In creating the cmdlets I had two core goals that I wanted to achieve: first I wanted to add some basic retrieval functionality for common objects such as SPWeb and SPList objects so that I could do some simple discovery type operations just as I would with SharePoint on-premises cmdlets; second, I wanted to make working with the cmdlets and the objects returned by them much more like working with the on-premises API so that you don’t have to think about calling the Load and ExecuteQuery methods every time you try to do something. To accomplish these goals I had to not only create the actual cmdlets themselves (which was the easy part) but I also had create custom wrapper objects for several of the objects in the Microsoft.SharePoint.Client namespace. For example, when you call my Get-SPOWeb cmdlet what you get back is an SPOWeb object, not a Microsoft.SharePoint.Client.Web object. By taking this approach I an avoid the common uninitialized property errors that you’d see when you output the object to the PowerShell console. These errors makes working with the native objects nearly impossible as it requires you to know which properties are initialized and which ones aren’t – by creating a wrapper object I can hide this issue and make working with the objects very simple. I can also do things like create an Update method which handles the calling of the ExecuteQuery method as well as the refresh of the object, again, taking a lot of the nuances of working with the .NET CSOM API out of the picture. For those of you not familiar with working with the .NET CSOM API (and for those that are) the point to take away from all my technical babbling is that using my cmdlets will make working with SharePoint Online very similar to working with SharePoint on-premises.

Let’s take a look at how we can use my cmdlets. First off you need to download and install the cmdlets – I’ve created the cmdlets so that they work just like the Microsoft provided SharePoint Online cmdlets in that I just created a PowerShell V3 module manifest which references a binary assembly (dll) that contains all the cmdlets. All the installer does is put all the required files (dependent Microsoft.SharePoint.Client dlls, my assembly containing the cmdlets themselves, and the PowerShell help and format file) into an appropriate directory and then adds the path to that directory to the PSModulePath environment variable. This makes cmdlets available without having to manually load the module and is just like what the Microsoft SharePoint Online cmdlets do. Note that Microsoft provides a shortcut for the SharePoint Online Management Shell which is simply a PowerShell console with the module explicitly loaded but use of the management shell is completely unnecessary so I don’t bother creating an equivalent shortcut. To see that the module is installed correctly simply open any PowerShell console and run the Get-Module cmdlet passing in the -ListAvailable parameter. You should see the module listed as shown below:

Get-Module -ListAvailable

With the cmdlets installed you can now connect to a Site Collection using the Connect-SPOSite cmdlet. Note that the majority of my cmdlets are scoped to a single Site Collection and you must establish a connection to that Site Collection before you can do anything else; if you need to work on a different Site Collection then you’ll need to call Connect-SPOSite again.  In this example I’m connecting to a site by providing my username and the Site Collection to connect to:

Connect-SPOSite -Credential "" -Url ""


I recommend you actually create a variable to store you credential information ($cred = Get-Credential) so that you can reuse the information each time you connect to a different Site Collection. Oh, and as a bonus, though the default behavior is to connect to SharePoint Online, if you pass in the –NetworkCredentials switch parameter then you can use these cmdlets against SharePoint on-premises – you’re welcome. To kill a connection use the Disconnect-SPOSite cmdlet (I particularly recommend you do this when creating scripts, not much point if you’re just doing something one-off in the console but if you writing a script you want to make sure you kill your context so someone can’t come behind you and hijack your credentials – this is absolutely the same pattern that the Microsoft SharePoint Online cmdlets follow so if you’re familiar with them this should not be new to you).

Once you’ve established a connection you’re ready to start using the other cmdlets. If you’d like to retrieve the root Site (SPWeb) or a child Site you can use the Get-SPOWeb cmdlet as shown:

$rootWeb = Get-SPOWebIdentity "/" -Detail

$childWeb = Get-SPOWebIdentity "/test" -Detail


Note the –Detail parameter which is useful when you want to see as much information as possible. If you’re just looking for a list Sites then I would omit the parameter so that you’re bringing back less information which should help it to run a little faster (to see all the Sites omit the –Identity parameter).

When you get back an object I encourage you to use the Get-Member cmdlet (aliased as gm) to see the list of properties and methods available. All of my cmdlets will return my own SPO* wrapper object you can always get back to the original Microsoft.SharePoint.Client object via a property on my object. The fact is I couldn’t wrap every single sub-object or every single property and method so there will be times when you’ll have to use the native object but hopefully what I did provide will at least cover a 80% of the common use cases (I hope). The following screenshot shows the members for the SPOWeb object:


Notice the highlighted Web property which you can use to get to the original Microsoft.SharePoint.Client.Web object. If you need to update any properties on the object you can either use the Set-SPOWeb cmdlet or update the property directly on the object and then call the Update() method – no need to call ExecuteQuery and then refresh the object, it’s all handled for you.

I don’t want to spend time going through every cmdlet and object that I’ve created as I detail each of the cmdlets on my command index page and the object members are easily discovered using the Get-Member cmdlet so to wrap up I want to simply point out that this is definitely a work in progress and will hopefully grow over time. Also, I don’t claim to be a .NET CSOM expert so there may be some areas that can be improved upon from a performance point of view so if you download the code and see something that can be improved please share you feedback, or if you see anything else that can be improved again, please share (note that I’m absolutely horrible when it comes to responding to comments on my blog but I do eventually get to them all, just not necessarily very quickly).

Have fun and happy PowerShelling!



SharePoint 2013 Version

So today I was doing some SharePoint 2013 app development against my Office 365 SharePoint 2013 tenant and I needed to view the HTTP traffic from the site in order to troubleshoot some issues I was having and I stumbled across something I found very interesting when I looked at the header details in Fiddler:


Yup, that’s right – my tenant is on SharePoint 16 – not 15 which is the current public release of SharePoint. To confirm that this wasn’t just something with the headers I navigated to and there it is again:


(In case you’re wondering, the service.cnf file hard codes the version information for the current web application and if you have an on-prem version you can see it in the _vti_pvt folder of you local web application’s site – you can also look at _vti_pvt/buildversion.cnf to get the actual build number).

Another confirmation test I hadn’t thought of but James Love (@jimmywim) pointed out to me was that the page layouts within the site are also referencing assemblies. I downloaded the DefaultLayout.aspx file to confirm and this is what I see:

<%@ Page language="C#"   Inherits="Microsoft.SharePoint.Publishing.PublishingLayoutPage, Microsoft.SharePoint.Publishing,Version=,Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

So you may be asking yourself – what does all this mean? Has Microsoft upgraded my SharePoint Online Farm to the next version of SharePoint? Well, I honestly don’t know but I think all the evidence is pretty clear that they must have. In terms of what is different, I simply couldn’t tell you as I’ve not noticed anything different – perhaps you have? If so post a comment as I’d love to know!

I personally don’t like speculating about what this means and what Microsoft is doing so for me what is important about this information is the fact that I/you might have clients or customers running on bits that are not just different due to patch levels but are in fact on an entirely different version. As I’m working on SharePoint Apps that will be sold in the App Store this type of information is critical when it comes to troubleshooting problems. So until Microsoft releases some public information about what’s up with all of this, the best we can do is keep the information handy as we work on various projects and, hopefully, keep the discussions going so that as folks discover version related differences we communicate that information to each other for our global benefit.



My First Pluralsight Course

Throughout the years I've done numerous presentations related to using PowerShell with SharePoint and through them all I've often found myself wanting more time so that I could share more details. Recently some friends of mine pointed me in the direction of Pluralsight and the opportunities they had for new authors – I saw this as a fantastic way to take many of the presentations I've done in the past and polish them up, add some details, and create a real course out of them. So with that I'm pleased to announce that my first Pluralsight course is now available: Using Windows PowerShell with SharePoint 2010 and SharePoint 2013. The folks at Pluralsight were amazing to work with and going through the authoring process has given me a whole new level of respect for the existing authors and for Pluralsight as a company; they seem to be doing everything right and every Pluralsight employee I've interacted with exemplifies professionalism and dedication to the goal of producing a great product, and I am humbled by the acceptance of my course into their library.

So if you're a developer or an administrator and you're working with SharePoint then I strongly recommend you go through some or all of my course to help you better understand how to use PowerShell, and more specifically, how to use it with SharePoint. You can see the full course outline by following the previous link but I've gone ahead and included the course and module descriptions here for your direct reference:

Using Windows PowerShell with SharePoint 2010 and SharePoint 2013

When it comes to administering and automating SharePoint 2010, 2013, and Office 365, there is no better tool than Windows PowerShell. After going through this course you'll have the skills and knowledge necessary to be productive with PowerShell. In the first two modules you'll get a jump start into PowerShell where you'll learn everything from basic syntax to creating functions and scripts, all within the context of SharePoint. Next you'll discover what's new when it comes to using PowerShell V3 with SharePoint 2013. Administering SharePoint with PowerShell does not mean that you're limited to what you can do directly on the server and in this course you'll learn everything you need to know to manage your Farm remotely, whether you are using Office 365 or an on-premises installation. And finally, sometimes the out of the box cmdlets just aren't enough so we'll teach you how to create your own custom cmdlets that you can deploy to your SharePoint Farm. After completing this course you'll be on your way to becoming a SharePoint superstar as you'll have all the core knowledge you need to start administering and automating SharePoint using Windows PowerShell.

  1. Introduction to PowerShell for SharePoint

    This module focuses on the basics of Windows PowerShell, all with an emphasis on SharePoint. At the conclusion of this module, you should have enough basic knowledge to start working with SharePoint via the SharePoint Management Shell.

  2. Scripting with PowerShell & SharePoint

    This module builds on the foundations presented in the first module and gets beyond what is typically done in the console. During this module you'll start by learning about conditional logic and looping and then move onto creating functions and scripts.

  3. PowerShell V3 + SharePoint 2013

    In this module you'll learn about many of the new features offered by Windows PowerShell V3 with SharePoint 2013.

  4. PowerShell & Office 365

    In this module we'll shift from SharePoint on-premises to SharePoint Online. You'll learn how to connect to your SharePoint Online tenant and what you can and can't do with the available SharePoint Online cmdlets.

  5. PowerShell Remoting

    In this module, we'll switch gears back to on-premises SharePoint installations as we take a look at how you can use PowerShell from your client machine to remotely connect to and manage your on-premises SharePoint Farm.

  6. Creating Custom Cmdlets for SharePoint

    In this module you'll learn how to extend the out of the box SharePoint cmdlets by creating your own custom cmdlets and PipeBind objects.

I already have some ideas for another course to essentially round out the PowerShell + SharePoint side of things – specifically I'm planning on creating a course that assumes you know PowerShell and now you need to learn how to better apply that knowledge to solve specific problems – so my plan for the next course will be to provide more solution focused education (at least, that's the plan, I'll have to see how this first course does before I commit to anything).

I hope that you find my course useful and please provide feedback (positive or negative) as I'm anxious to know what works and what doesn't so that I can continue to improve and bring better and better stuff to the community.


Parallel SharePoint Tasks with PowerShell

Today I was working on a deployment for a client which entailed activating a custom SharePoint Feature on about 1000 Site Collections. This Feature did a fair number of things and on average it takes about 10-15 minutes to complete in their test environment (which is pretty slow compared to their production environment which I've not yet deployed to but I expect close to a 5 minute run time per Site Collection once I go to production with it). You can obviously do the math and quickly see that it will take me somewhere around 10 days for this to complete if I did one Site Collection at a time. This is just unacceptable as I personally don't want to be monitoring a Feature activation script for that long. What's worse is that when I look at CPU and memory utilization on the servers I can see that they have plenty of resources so it's not like the operation is actually taxing the system, they're just slow operations. So the solution, for me, is pretty obvious: I need to activate these Features in parallel.

There are two ways that I can achieve this using PowerShell and they depend on which version of PowerShell you're using. In my case I'm running SharePoint 2010 which means that I'm using PowerShell V2; because of this my only option is to use the Start-Job cmdlet with some control logic to dictate how many jobs I'm willing to run at once. If I were using SharePoint 2013 I could use the new workflow capabilities of PowerShell V3 thereby making the whole process a lot easier to understand. I'll show both approaches but I want to first start with what you would do for SharePoint 2010 with PowerShell V2.

Using Start-Job for Parallel Operations

The trick with using the Start-Job cmdlet is knowing when to stop creating new jobs until existing jobs have completed. The key is to use the Get-Job cmdlet and filter on the JobStateInfo property's State property and then, if you have reached your job count threshold, call the Wait-Job cmdlet to block the script until a job completes. The following script is a simple example of what I created for my client and can be used as a template for your own scripts:

$jobThreshold = 10

foreach ($site in (Get-SPSite -Limit All)) {
    # Get all running jobs
    $running = @(Get-Job | where { $_.JobStateInfo.State -eq "Running" })

    # Loop as long as our running job count is >= threshold
    while ($running.Count -ge $jobThreshold) {
        # Block until we get at least one job complete
        $running | Wait-Job -Any | Out-Null
        # Refresh the running job list
        $running = @(Get-Job | where { $_.JobStateInfo.State -eq "Running" })

    Start-Job -InputObject $site.Url {
        $url = $input | %{$_}
        Write-Host "BEGIN: $(Get-Date) Processing $url..."

        # We're in a new process so load the snap-in
        Add-PSSnapin Microsoft.SharePoint.PowerShell

        # Enable the custom feature
        Enable-SPFeature -Url $url -Identity MyCustomFeature

        Write-Host "END: $(Get-Date) Processing $url."
    # Dump the results of any completed jobs
    Get-Job | where { $_.JobStateInfo.State -eq "Completed" } | Receive-Job

    # Remove completed jobs so we don't see their results again
    Get-Job | where { $_.JobStateInfo.State -eq "Completed" } | Remove-Job

If you run this script and open up task manager you'll see that it's created a powershell.exe process for each job. You might be able to get away with more processes running at once but I'd recommend starting smaller before you bump it up too high and risk crippling your system.

Using PowerShell V3 Workflow

With PowerShell V3 we now have the ability to create a workflow within which I can specify tasks that should be run in parallel. I actually detailed how to do this in an earlier post so I won't spend much time on it here. I do want to show the code again for the sake of comparison as well as to point out one core difference (I recommend you read the Workflow section of my aforementioned post for more details). First though, here's a slightly modified version of the code so you can compare it to the V2 equivalent:

workflow Enable-SPFeatureInParallel {
    foreach -parallel($url in $urls) {
        InlineScript {
            # Write-Host doesn't work within a workflow
            Write-Output "BEGIN: $(Get-Date) Processing $($using:url)..."
            # We're in a new process so load the snap-in
            Add-PSSnapin Microsoft.SharePoint.PowerShell
            # Enable the custom feature
            Enable-SPFeature -Identity $using:feature -Url $using:url
            Write-Output "END: $(Get-Date) Processing $($using:url)."
Enable-SPFeatureInParallel (Get-SPSite -Limit All).Url "MyCustomFeature"

The first thing you should be asking yourself when you look at this is how many will be processed simultaneously? With the V2 version we could set the limit to whatever arbitrary value made sense for our situation. With this approach, however, we're limited to only 5 processes. You can see this if you run the code and open up task manager where, like the Start-Job approach, you'll see the powershell.exe for each process (note that it's not the workflow that is creating the powershell.exe process, it's the call to the InlineScript activity which is doing it – this call to InlineScript just helps to point out that you'll never see more than five created).


So, though we're limited by the number of processes and there are some downsides in terms of how we output information (like the fact that we can't use Write-Host and any output generated by one run could be intermixed with output from another run) I think the V3 approach is much cleaner and easier to use. That said, you could make the Start-Job approach generic so that you pass in a script to run along with an array of input values so that this could be easily used without having to look at the details of what's happening.


Provisioning Search on SharePoint 2013 Foundation Using PowerShell

There was recently a twitter conversation between @cacallahan, @toddklindt, and @brianlala discussing provisioning Search on SharePoint Foundation and whether it was possible or not and somewhere during the conversation it was suggested that I might know how to do this (sorry guys for not responding immediately) – unfortunately I hadn’t actually done any work with SharePoint 2013 Foundation yet and so had not yet tried and thus didn’t know the answer (I knew there were issues and suspected a workaround was possible but I didn’t have a server built to test anything). Well, last night and today I managed to have some free time so I figured I’d take a look at the problem to see if my guess about a workaround was correct.

Before I get to the results of my discovery let’s first look at what the blocking issue is. It’s actually quite simple – the product team, for various reasons, have decided that for SharePoint 2013 Foundation you can only have one Search Service Application and you shouldn’t be able to modify the topology of the Service Application; this means that when you provision Search using the Farm Configuration Wizard it will create a default topology for you in which all roles are on a single server. So, to enforce these rules they chose to make it so that the PowerShell cmdlets would not allow you to provision the service application or run any method or cmdlet that would otherwise allow you to modify an existing topology (so you can’t change the topology created by the wizard). I totally get the reasoning for the restriction – if you need enterprise topology type structures then pony up the money and get off the free stuff. That said, I think they took the lazy way out by simply blocking the cmdlets when they could have easily put in other restrictions that would have achieved their goals while still allowing users to use PowerShell to provision the environment.

If you’re curious as to what happens when you try to provision the service using PowerShell on SharePoint Foundation 2013 here’s a screenshot which shows the error that is thrown:


This error is thrown by a simple piece of code in the InternalValidate() method of the cmdlet which checks to make sure you are on Standard or Enterprise before allowing the cmdlet to execute (and any other cmdlets or methods that would otherwise affect the topology likewise perform this check).

To solve the problem I decided to start from the perspective of code run via the browser and drill down to see what I could find. So using Reflector I located the class and associated methods that are called by the Farm Configuration Wizard; this quickly led me to the public Microsoft.Office.Server.Search.Administration.SearchService.CreateApplication() static methods. So I did a quick test calling one of these methods and I was happy to find that the Search Service Application created perfectly – though there was one minor problem: the topology was empty. At first glance I figured this wouldn’t be an issue – I could simply clone the topology and add my components – unfortunately this is where I learned that they applied the SKU check to methods and cmdlets that would allow you to manipulate the topology. (On a side note, using these methods for Standard or Enterprise is potentially a great alternative to the New-SPEnterpriseSearchServiceApplication cmdlet as it lets you specify the names of databases that you can’t specify when using the cmdlet and because it creates an initially empty topology there’s less cleanup and manipulation of the cloned topology (assuming you don’t want to use what’s created) and it provisions slightly faster because it does less). So at this point I figured I’d hit the real road block – I could create the service application but it was useless as I couldn’t manipulate it.

This left me with only one option – to use reflection to call the internal method that the Farm Configuration Wizard calls to provision the service application. Now, before I get to the code that demonstrates how to do this I need to share a word of caution – using reflection to call internal methods is totally not supported. So what does this mean? Will Microsoft no longer support your Farm? Well, my understanding (and folks in the know please correct me if I’m in the wrong) is that Microsoft will continue to support you and that you will simply have to remove unsupported code before they will help you troubleshoot issues. Well, in this case it’s a one-time operation so there’s nothing really to remove; I figure the worst case scenario is that they’ll tell you that you need to recreate the service application using the Farm Configuration Wizard and then they’ll help you with your issue. But let’s take the question of supportability out of the equation for a second and look at it from a completely practical standpoint – if you were to look at the code that the Farm Configuration Wizard calls you’d see that, outside of some error checking and data validation and variable initialization, there’s effectively just two lines of code that do the provisioning of the service so I believe that the probability of getting it wrong is pretty low and the fact is search will either work or it won’t so if it doesn’t work then try again or just use the dang wizard. So, with all that said, if you decide to use any of this code you need to weigh the risks yourself and make an informed decision with those risks in mind. Alright, enough of that crap – you want to see the code so let’s get to the code.

To keep the PowerShell itself nice and simple I decide to derive this example from a script that Todd Klindt provides on his blog (the script I use is considerably more complex as it handles the changing of service options like the index folder and the service and crawl accounts, to name a few, and I don’t want the point of this post to be lost in all those details). Just to make sure the full chain of credit is provided I should note that Todd’s script is actually a derivative of what Spence Harbar provides on his blog but I wanted to reference Todd’s post specifically as it’s a bit shorter and more focused on the topic. Okay, background info – check; disclaimer – check; attribution – check – looks like it’s time for some code so here you go:

#Start the service instances
Start-SPEnterpriseSearchServiceInstance $env:computername
Start-SPEnterpriseSearchQueryAndSiteSettingsServiceInstance $env:computername

#Provide a unique name for the service application
$serviceAppName = "Search Service Application"

#Get the application pools to use (make sure you change the value for your environment)
$svcPool = Get-SPServiceApplicationPool "SharePoint Services App Pool"
$adminPool = Get-SPServiceApplicationPool "SharePoint Services App Pool"

#Get the service from the service instance so we can call a method on it
$searchServiceInstance = Get-SPEnterpriseSearchServiceInstanceLocal
$searchService = $searchServiceInstance.Service

#Use reflection to provision the default topology just as the wizard would
$bindings = @("InvokeMethod", "NonPublic", "Instance")
$types = @([string], [Type], [Microsoft.SharePoint.Administration.SPIisWebServiceApplicationPool], [Microsoft.SharePoint.Administration.SPIisWebServiceApplicationPool])
$values = @($serviceAppName, [Microsoft.Office.Server.Search.Administration.SearchServiceApplication], [Microsoft.SharePoint.Administration.SPIisWebServiceApplicationPool]$svcPool, [Microsoft.SharePoint.Administration.SPIisWebServiceApplicationPool]$adminPool)
$methodInfo = $searchService.GetType().GetMethod("CreateApplicationWithDefaultTopology", $bindings, $null, $types, $null)
$searchServiceApp = $methodInfo.Invoke($searchService, $values)

#Create the search service application proxy (we get to use the cmdlet for this!)
$searchProxy = New-SPEnterpriseSearchServiceApplicationProxy -Name "$serviceAppName Proxy" -SearchApplication $searchServiceApp

#Provision the search service application


Basically there’s two things that need to be done: first we need to use reflection to get the MethodInfo object for the CreateApplicationWithDefaultTopology() method of the Microsoft.Office.Server.Search.Administration.SearchService class and we’ll use this object to invoke the actual method, passing in the parameter types and values (and yes, the cast of the SPIisWebServiceApplicationPool objects is necessary otherwise you’ll get an error about trying to convert PSObjects to SPIisWebServiceApplicationPool types); the next thing we need to do, after the service application is created, is to create the service application proxy and then call the Provision() method on the search service application that we previously created (if you miss this step you’ll get errors about things like the admin component not be started and whatnot).

Once completed you’ll get a fully functional, PowerShell provisioned search service application. If you navigate to the search administration page you should see something that looks just like this (just like if you used the wizard):


So there you have it – it is indeed possible to provision the service using PowerShell – I’ll let you determine whether you should or not :)

Happy PowerShelling!



SharePoint Evolution Conference 2013

Today I finally got around to booking my travel for my favorite SharePoint conference – the SharePoint Evolution Conference in London England. For the third year in a row I have the honor of being able to present, and once again I’ll be covering the PowerShell side of things at the conference. Normally I tend to do more of a deep dive when I present but this time I’ll be stepping back a bit and providing more of an introductory type session to perhaps help those who have yet to realize the power of PowerShell get up to speed. This time I’ll only be doing the one session so I’ll get plenty of time to sit in on what I expect to be some great sessions (I originally was going to present on the SharePoint Education features but as those features are going away it was decided to scrub the session rather than present on something people shouldn’t be using).

Here’s the abstract for my session if your planning on attending:

The Power that is PowerShell – learn all about using PowerShell in SharePoint.
Audience: Developer / IT Pro

With the release of SharePoint 2013 Microsoft has nearly doubled the number of PowerShell cmdlets that are available for managing the product. This increase coupled with the fact that many things can now only be managed using PowerShell (such as search topology) means that administrators and developers alike must embrace PowerShell in order to be successful with SharePoint. In this session you will learn the basics of how to use PowerShell, from simple syntax to creating scripts for common or complex tasks; additionally, we’ll look at some of the new features available with PowerShell V3, the required version for SharePoint 2013.

Steve Smith and his crew at Combined Knowledge know how to put on an incredible show with fantastic speakers, sessions, and after-hours events. If you’re only given a budget for one conference each year you may not initially think about flying to London (assuming you’re not local) for that conference but I highly suggest you consider it. I’ve only been out of the States twice before in my life and both times were for this conference and it was totally worth it. From a purely educational standpoint the sessions are top notch with speakers who truly know their stuff so you can be assured that you’re getting quality information that stems from real world experience and not just playing around in a lab environment.

If you do make it to the conference please stop by my session and say hi!



Fix: The trust relationship between this workstation and the primary domain failed

This short post is really just for my own memory as I keep bumping into this with my virtual machines but I figured others might also find it useful. Typically when I do SharePoint development I do everything on an all-up server but with SharePoint 2013 I’ve moved my Domain Controller to a separate server (where I also will install the Office Web Apps); however, if I leave any of my machines off for a while then the computer password will expire which means that things start to break and you’ll see errors like "The trust relationship between this workstation and the primary domain failed." The common fix is to remove the server from the domain and then join it back in but that takes some time so what I prefer to do is to simply run the following command which will reset the password:

netdom.exe resetpwd /s:domain_controller_name /ud:domain\administrator /pd:*

Be sure to replace the domain_controller_name placeholder with the name of your domain controller server. If you’re not already logged in to the server then you’ll have to log in using a local administrator account. After running the command it will prompt for a password for the specified account (it’s an odd prompt as it doesn’t show any characters being typed – not even masked). After providing the password reboot the server and you should be good to go.

If you want to prevent the server from changing its password in the first place (or prevent the DC from accepting the password change) you can follow the steps in this support article to disable the setting and avoid the issue altogether: (more times than not I forget to do this in new development environments which prompted me to post the reset password fix).

UPDATE 4/12/2013: Seems you can do all this using PowerShell: "Test-ComputerSecureChannel -Repair". Thanks Alexey for pointing this out - learn something new every day!


Tagged as: 5 Comments

Announcing My SharePoint 2013 Custom Cmdlets

I’ve been putting this off for quite a while but I’ve finally pushed out a SharePoint 2013 build of my custom cmdlets. The reason it took so long was because I had to make a fair bit of changes to my existing stuff so that it would be easier to maintain both builds going forward. Specifically I needed to change the namespace of all the classes (which had 2010 in them) and I wanted to use a different name for the WSPs so the version wasn’t included in it either. So now I have just one WSP name for the SharePoint 2010 and SharePoint 2013 cmdlets for both Server and Foundation: Lapointe.SharePoint.PowerShell.wsp. If you previously had my old 2010 cmdlets deployed you’ll need to fully retract them before installing this new build (technically you can rename the new WSP file to the old name but I’d rather you embrace the change and just suck it up and do the dang retraction – it only takes a minute, so don’t be lazy!)

I’ve updated my downloads page to point to the correct WSP for each environment and I’ve deleted the old WSPs so if you were foolishly linking directly to my WSPs (please don’t do that) then your links are now broken. I’ve also posted the source code which has been upgraded for Visual Studio 2012 and contains a separate project for SharePoint 2010 and SharePoint 2013 (in addition to my custom MAML generator).

Another change I’ve made to help me manage these custom cmdlets better was that I got rid of my old command index page and created a new app for displaying the cmdlet details (the old page is still there, it just redirects to the new page). This new page is actually built dynamically using the PowerShell help file that I generate dynamically from the actual cmdlet classes – so for me this is pretty cool because now all the PowerShell help documentation and online documentation of each cmdlet is generated automatically so I don’t have to do anything other than provide the actual help details in the cmdlet classes themselves and I don’t do anything special to keep them in sync (just copy the help files up to my site).

At present both the SharePoint 2010 and SharePoint 2013 cmdlets are exactly the same (except for a few in code changes to make it work with 2013). I have, however, added a few new cmdlets from what was previously available and I’ll be added some more in the coming weeks (I’m hoping to start converting some of my more frequently used utility scripts and functions to cmdlets so I don’t have to keep hunting around for them). There is however, one breaking change (well, two to be exact) – the first is that I had to rename my Repair-SPSite cmdlet to Repair-SPMigratedSite because SharePoint 2013 introduces a cmdlet of the same name; the second was that I removed the gl-applytheme STSADM command as the functionality that it provided was specific to SharePoint 2007 and is no longer available (but I’m not really supporting the STSADM stuff anyways and contemplated removing them entirely but decided to leave them in, for now).

I haven’t had time to do a ton of testing of all the cmdlets on SharePoint 2013 - there’s just too many of them and I don’t make any money on these things so it’s not a high priority – so, as always, your feedback is appreciated and I’ll do my best to fix any bugs that are discovered but I can’t promise when I’ll get to them.

Happy PowerShelling!



Using PowerShell to Manage SharePoint 2013 Online

When SharePoint 2010 was released we had hundreds of cmdlets available for our on-premises deployments but when it came to Office365 we only had cmdlets available for manipulating our subscription details, users in AD, and Exchange Online ( With the release of SharePoint 2013 as part of the Office365 offering we now have the ability to use PowerShell to manipulate our SharePoint Site Collections in the cloud. The capabilities are somewhat limited in that our abilities are limited to manipulating Site Collections, but it’s a start. In this article I’ll walk through the available cmdlets and detail some examples of how to use them.

Getting Started

Before you can start working with the SharePoint Online cmdlets you must first download those cmdlets. Having the cmdlets as a separate download (separate from SharePoint on-premises that is) allows you to use any machine to run the cmdlets. All we have to do is make sure we have PowerShell V3 installed along with the .NET Framework v4 or better (required by PowerShell V3). With these prerequisites in place simply download and install the cmdlets from Microsoft:

Once installed open the SharePoint Online Management Shell by clicking Start > All Programs > SharePoint Online Management Shell > SharePoint Online Management Shell.  Just like with the SharePoint Management Shell for on-premises deployments the SharePoint Online Management Shell is just a standard PowerShell window. You can see this by looking at the target attribute of the shortcut properties:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoExit -Command "Import-Module Microsoft.Online.SharePoint.PowerShell -DisableNameChecking;"

As you can see from the shortcut, a PowerShell module is loaded: Microsoft.Online.SharePoint.PowerShell. Unlike with SharePoint on-premises, this is not a snap-in but a module, which is basically the new, better way of loading cmdlets. The nice thing about this is that, like with the snap-in, you can load the module in any PowerShell window and are not limited to using the SharePoint Online Management Shell. (The -DisableNameChecking parameter of the Import-Module cmdlet simply tells PowerShell to not bother checking for valid verbs used by the loaded cmdlets and avoids warnings that are generated by the fact that the module does use an invalid verb – specifically, Upgrade). Note that unlike with the snap-in, there’s no need to specify the threading options because the cmdlets don’t use any unmanaged resources which need disposal.

Getting Connected

Now that you’ve got the SharePoint Online Management Shell installed you are now ready to connect to your tenant administration site. This initial connection is necessary to establish a connection context which stores the URL of the tenant administration site and the credentials used to connect to the site. To establish the connection use the Connect-SPOService cmdlet:

Connect-SPOService -Url -Credential

Running this cmdlet basically just stores a Microsoft.SharePoint.Client.ClientContext object in an internal static variable (or a sub-classed version of it at least). Future cmdlet calls then use this object to connect to the site, thereby negating the need to constantly provide the URL and credentials. (The downside of this object being internal is that we can’t extend the cmdlets to add our own, unless we want to use reflection which would be unsupported). To clear this internal variable (and make the session secure against other code that may attempt to use it) you can run the Disconnect-SPOService cmdlet. This cmdlet takes no parameters.

One tip to help make loading the module and then connecting to the site a tad bit easier would be to encapsulate the commands into a single helper method. In the following example I created a simple helper method named Connect-SPOSite which takes in the user and the tenant administration site to connect to, however, I default those values so that I only have to provide the password when I wish to get connected. I then put this method in my profile file (which you can edit by typing “ise $profile.CurrentUsersAllHosts”):

function Connect-SPOSite() {

    param (

        $user = "",

        $site = ""


    if ((Get-Module Microsoft.Online.SharePoint.PowerShell).Count -eq 0) {

        Import-Module Microsoft.Online.SharePoint.PowerShell -DisableNameChecking


    $cred = Get-Credential $user

    Connect-SPOService -Url $site -Credential $cred



SPO Cmdlets

Now that you’re connected you can finally do something interesting. First let’s look at the cmdlets that are available. There are currently only 30 cmdlets available to us and you can see the list of those cmdlets by typing “Get-Command -Module Microsoft.Online.SharePoint.PowerShell”. Note that all of the cmdlets will have a noun which starts with “SPO”. The following is a list of all the available cmdlets:

  • Site Groups
  • Users
    • Add-SPOUser – Add a user to an existing Site Collection Site Group.
    • Get-SPOUser – Get an existing user.
    • Remove-SPOUser – Remove an existing user from the Site Collection or from an existing Site Collection Group.
    • Set-SPOUser – Set whether an existing Site Collection user is a Site Collection administrator or not.
    • Get-SPOExternalUser – Returns external users from the tenant’s folder.
    • Remove-SPOExternalUser - Removes a collection of external users from the tenancy's folder.
  • Site Collections
    • Get-SPOSite – Retrieve an existing Site Collection.
    • New-SPOSite – Create a new Site Collection.
    • Remove-SPOSite – Move an existing Site Collection to the recycle bin.
    • Repair-SPOSite – If any failed Site Collection scoped health check rules can perform an automatic repair then initiate the repair.
    • Set-SPOSite – Set the Owner, Title, Storage Quota, Storage Quota Warning Level, Resource Quota, Resource Quota Warning Level, Locale ID, and/or whether the Site Collection allows Self Service Upgrade.
    • Test-SPOSite – Run all Site Collection health check rules against the specified Site Collection.
    • Upgrade-SPOSite – Upgrade the Site Collection. This can do a build-to-build (e.g., RTM to SP1) upgrade or a version-to-version (e.g., 2010 to 2013) upgrade. Use the -VersionUpgrade parameter for a version-to-version upgrade.
    • Get-SPODeletedSite – Get a Site Collection from the recycle bin.
    • Remove-SPODeletedSite – Remove a Site Collection from the recycle bin (permanently deletes it).
    • Restore-SPODeletedSite – Restores an item from the recycle bin.
    • Request-SPOUpgradeEvaluationSite  - Creates a copy of the specified Site Collection and performs an upgrade on that copy.
    • Get-SPOWebTemplate – Get a list of all available web templates.
  • Tenants
    • Get-SPOTenant – Retrieves information about the subscription tenant. This includes the Storage Quota size, Storage Quota Allocated (used), Resource Quota size, Resource Quota Allocated (used), Compatibility Range (14-14, 14-15, or 15-15), whether External Services are enabled, and the No Access Redirect URL.
    • Get-SPOTenantLogEntry – Retrieves company logs (as of B2 only BCS logs are available).
    • Get-SPOTenantLogLastAvailableTimeInUtc – Returns the time when the logs are collected.
    • Set-SPOTenant – Sets the Minimum and Maximum Compatibility Level, whether External Services are enabled, and the No Access Redirect URL.
  • Apps
  • Connections

It’s important to understand that when working with all of the cmdlets which retrieve an object you will only ever be getting a simple data object which has no ability to act upon the source object. For example, the Get-SPOSite cmdlet returns an SPOSite object which has no methods and, though some properties do have a setter, they are completely useless and the object and its properties are not used by any other cmdlet (such as Set-SPOSite). This also means that there is no ability to access child objects (such as SPWeb or SPList items, to name just a couple).

The other thing to note is the lack of cmdlets for items at a lower scope than the Site Collection. Specifically there is no Get-SPOWeb or Get-SPOList cmdlet or anything of the sort. This can be potentially be quite limiting for most real world uses of PowerShell and, in my opinion, limit the usefulness of these new cmdlets to just the initial setup of a subscription and not the long-term maintenance of the subscription.

In the following examples I’ll walk through some examples of just a few of the more common cmdlets so that you can get an idea of the general usage of them.

Get a Site Collection

To see the list of Site Collections associated with a subscription or to see the details for a specific Site Collection use the Get-SPOSite cmdlet. This cmdlet has two parameter sets:

Get-SPOSite [[-Identity] <SpoSitePipeBind>] [-Limit <string>] [-Detailed] [<CommonParameters>]

Get-SPOSite [-Filter <string>] [-Limit <string>] [-Detailed] [<CommonParameters>]

The parameter that you’ll want to pay the most attention to is the -Detailed parameter. If this optional switch parameter is omitted then the SPOSite objects that will be returned will only have their properties partially set. Now you might think that this is in order to reduce the traffic between the server and the client, however, all the properties are still sent over the wire, they simply have default values for everything other than a couple core properties (so I would assume the only performance improvement would be in the query on the server). You can see the difference in the values that are returned by looking at a Site Collection with and without the details:

PS C:\> Get-SPOSite | select *

LastContentModifiedDate   : 1/1/0001 12:00:00 AM
Status                    : Active
ResourceUsageCurrent      : 0
ResourceUsageAverage      : 0
StorageUsageCurrent       : 0
LockIssue                 :
WebsCount                 : 0
CompatibilityLevel        : 0
Url                       :
LocaleId                  : 1033
LockState                 : Unlock
Owner                     :
StorageQuota              : 1000
StorageQuotaWarningLevel  : 0
ResourceQuota             : 300
ResourceQuotaWarningLevel : 255
Template                  : EHS#1
Title                     :
AllowSelfServiceUpgrade   : False

PS C:\> Get-SPOSite -Detailed | select *

LastContentModifiedDate   : 11/2/2012 4:58:50 AM
Status                    : Active
ResourceUsageCurrent      : 0
ResourceUsageAverage      : 0
StorageUsageCurrent       : 1
LockIssue                 :
WebsCount                 : 1
CompatibilityLevel        : 15
Url                       :
LocaleId                  : 1033
LockState                 : Unlock
Owner                     : s-1-5-21-3176901541-3072848581-1985638908-189897
StorageQuota              : 1000
StorageQuotaWarningLevel  : 0
ResourceQuota             : 300
ResourceQuotaWarningLevel : 255
Template                  : STS#0
Title                     : Contoso Team Site
AllowSelfServiceUpgrade   : True

Create a Site Collection

When we’re ready to create a Site Collection we can use the New-SPOSite cmdlet. This cmdlet is very similar to the New-SPSite cmdlet that we have for on-premises deployments. The following shows the syntax for the cmdlet:

New-SPOSite [-Url] <UrlCmdletPipeBind> -Owner <string> -StorageQuota <long> [-Title <string>] [-Template <string>] [-LocaleId <uint32>] [-CompatibilityLevel <int>] [-ResourceQuota <double>] [-TimeZoneId <int>] [-NoWait] [<CommonParameters>]

The following example demonstrates how we would call the cmdlet to create a new Site Collection called “Test”:

New-SPOSite -Url -Title "Test" -Owner "" -Template "STS#0" -TimeZoneId 10 -StorageQuota 100


Note that the cmdlet also takes in a -NoWait parameter; this parameter tells the cmdlet to return immediately and not wait for the creation of the Site Collection to complete. If not specified then the cmdlet will poll the environment until it indicates that the Site Collection has been created. Using the -NoWait parameter is useful, however, when creating batches of Site Collections thereby allowing the operations to run asynchronously.

One issue you might bump into is in knowing which templates are available for your use. In the preceding example we are using the “STS#0” template, however, there are other templates available for our use and we can discover them using the Get-SPOWebTemplate cmdlet, as shown below:

PS C:\> Get-SPOWebTemplate

Name                     Title                         LocaleId  CompatibilityLevel
----                     -----                         --------  ------------------
STS#0                    Team Site                         1033                  15
BLOG#0                   Blog                              1033                  15
BDR#0                    Document Center                   1033                  15
DEV#0                    Developer Site                    1033                  15
DOCMARKETPLACESITE#0     Academic Library                  1033                  15
OFFILE#1                 Records Center                    1033                  15
EHS#1                    Team Site - SharePoint Onl...     1033                  15
BICenterSite#0           Business Intelligence Center      1033                  15
SRCHCEN#0                Enterprise Search Center          1033                  15
BLANKINTERNETCONTAINER#0 Publishing Portal                 1033                  15
ENTERWIKI#0              Enterprise Wiki                   1033                  15
PROJECTSITE#0            Project Site                      1033                  15
COMMUNITY#0              Community Site                    1033                  15
COMMUNITYPORTAL#0        Community Portal                  1033                  15
SRCHCENTERLITE#0         Basic Search Center               1033                  15
visprus#0                Visio Process Repository          1033                  15

Give Access to a Site Collection

Once your Site Collection has been created you may wish to grant users access to the Site Collection. First you may want to create a new SharePoint group (if an appropriate one is not already present) and then you may want to add users to that group (or an existing one). To accomplish these tasks you use the New-SPOSiteGroup cmdlet and the Add-SPOUser cmdlet, respectively.

Looking at the New-SPOSiteGroup cmdlet you can see that it takes only three parameters, the name of the group to create, the permissions to add to the group, and the Site Collection within which to create the group:

New-SPOSiteGroup [-Site] <SpoSitePipeBind> [-Group] <string> [-PermissionLevels] <string[]> [<CommonParameters>]

In the following example I’m creating a new group named “Designers” and giving it the “Design” permission:

$site = Get-SPOSite -Detailed

$group = New-SPOSiteGroup -Site $site -Group "Designers" -PermissionLevels "Design“

(Note that I’m seeing the Site Collection to a variable just to keep the commands a little shorter, you could just as easily provide the string URL directly).

Once the group is created we can then use the Add-SPOUser cmdlet to add a user to the group. Like the New-SPOSiteGroup cmdlet this cmdlet takes three parameters:

Add-SPOUser [-Site] <SpoSitePipeBind> [-LoginName] <string> [-Group] <string> [<CommonParameters>]

In the following example I’m adding a new user to the previously created group:

Add-SPOUser -Site $site -Group $group.LoginName -LoginName ""

Delete and Recover a Site Collection

If you’ve created a Site Collection that you now wish to delete you can easily accomplish this by using the Remove-SPOSite cmdlet. When this cmdlet finishes the Site Collection will have been moved to the recycle bin and not actually deleted. If you wish to permanently delete the Site Collection (and thus remove it from the recycle bin) then you must use the Remove-SPODeletedSite cmdlet. So to do a permanent delete it’s actually a two step process, as shown in the example below where I first move the “Test” Site Collection to the recycle bin and then delete it from the recycle bin:

Remove-SPOSite "" -Confirm:$false

Remove-SPODeletedSite -Identity "" -Confirm:$false


If you decide that you’d actually like to restore the Site Collection from the recycle bin you can simply use the Restore-SPODeletedSite cmdlet:


Both the Remove-SPOSite and the Restore-SPODeletedSite cmdlets accept a -NoWait parameter which you can provide to tell the cmdlet to return immediately.

Parting Thoughts

There are obviously many other cmdlets available to explore (per the previous list), however, I hope that in the simple samples shown in this article you will find that working with the cmdlets is quite easy and fairly intuitive. The key thing to remember is that you are working in a stateless environment so changes to an object such as SPOSite will not affect the actual Site Collection in any way and cmdlets like the Set-SPOSite cmdlet will not honor changes made to the properties as it will use nothing more than the URL property to know which Site Collection you are updating.

Though the existence of these cmdlets is definitely a good start and absolutely better than nothing, I have to say that I’m extraordinarily displeased with the number of available cmdlets and with how the module was implemented. My biggest gripe is that the module is not extensible in any way so if I wish to add cmdlets for the management of SPWeb objects or SPList objects I’d have to create a whole new framework which would require an additional login as I wouldn’t be able to leverage the context object created by Connect-SPOService cmdlet. This results in a severely limiting product that prevents community and ISV generated solutions from “fitting in” to the existing model. Perhaps one day I’ll create my own set of cmdlets to show Microsoft how it should have been done…perhaps one day I’ll have time for such frivolities :) .


SharePoint 2013 PowerShell Cmdlets: Changes from Public Preview to RTM

In a recent post I detailed all the PowerShell changes from SharePoint 2010 to SharePoint 2013 Public Preview (part 1, part 2) – well, apparently I should have held off a couple of weeks because I’m now running the RTM version of SharePoint 2013 and have found that they have made a ton more changes. I don’t want to go through all the 2010 to 2013 changes again so instead I’ll just detail what has changed since the Public Preview; these changes include new cmdlets, removed cmdlets, and renamed cmdlets. (Note that some of the removed and new cmdlets may actually just be renamed cmdlets – not worth the effort for to verify them all at this point).

Removed Cmdlets

  1. Add-SPSocialAppPermissions
  2. Copy-SPAccessServicesDatabase
  3. Get-SPTrustedSecurityTokenService
  4. New-SPTrustedSecurityTokenService
  5. Remove-SPSocialAppPermissions
  6. Remove-SPTrustedSecurityTokenService
  7. Repartition-SPEnterpriseSearchLinksDatabases
  8. Set-SPSecureStoreSystemAccounts
  9. Set-SPTrustedSecurityTokenService

New Cmdlets

  1. Add-SPSecureStoreSystemAccount
  2. Copy-SPAccessServicesDatabaseCredentials
  3. Move-SPEnterpriseSearchLinksDatabases
  4. New-SPOnlineApplicationPrincipalManagementServiceApplicationProxy
  5. Remove-SPSecureStoreSystemAccount
  6. Set-SPAppSiteDomain
  7. Set-SPEnterpriseSearchFileFormatState
  8. Update-SPDistributedCacheSize

Renamed Cmdlets

  1. Add-SPDistributedCacheServiceInstanceOnLocalServer => Add-SPDistributedCacheServiceInstance
  2. Clear-SPAppDeniedEndpoints => Clear-SPAppDeniedEndpointList
  3. Copy-LocalActivitiesToWorkflowService => Copy-SPActivitiesToWorkflowService
  4. Get-SPAppAcquisitionSettings => Get-SPAppAcquisitionConfiguration
  5. Get-SPAppDeniedEndpoints => Get-SPAppDeniedEndpointList
  6. Get-SPAppDisableSettings => Get-SPAppDisablingConfiguration
  7. Get-SPAppHostingQuotas => Get-SPAppHostingQuotaConfiguration
  8. Get-SPAppMarketplaceSettings => Get-SPAppStoreConfiguration
  9. Get-SPBingMapsBlockInAllLocales => Get-SPBingMapsBlock
  10. Get-SPSecureStoreSystemAccounts => Get-SPSecureStoreSystemAccount
  11. Get-TranslationThrottlingSettings => Get-SPTranslationThrottlingSetting
  12. Get-WorkflowServiceApplicationProxy => Get-SPWorkflowServiceApplicationProxy
  13. Move-SPSocialComments => Move-SPSocialComment
  14. New-WorkflowServiceApplicationProxy => New-SPWorkflowServiceApplicationProxy
  15. Remove-SPDistributedCacheServiceInstanceOnLocalServer => Remove-SPDistributedCacheServiceInstance
  16. Restart-SPAppInstanceJobs => Restart-SPAppInstanceJob
  17. Set-SPAppAcquisitionSettings => Set-SPAppAcquisitionConfiguration
  18. Set-SPAppDisableSettings => Set-SPAppDisablingConfiguration
  19. Set-SPAppHostingQuotas => Set-SPAppHostingQuotaConfiguration
  20. Set-SPAppMarketplaceSettings => Set-SPAppStoreConfiguration
  21. Set-SPBingMapsBlockInAllLocales => Set-SPBingMapsBlock
  22. Set-TranslationThrottlingSettings => Set-SPTranslationThrottlingSetting
  23. Stop-SPDistributedCacheServiceInstanceGracefullyOnLocalServer => Stop-SPDistributedCacheServiceInstance
  24. Update-SPAppCatalogSettings => Update-SPAppCatalogConfiguration

Changed Cmdlets


  1. Added the following new parameter set: Backup-SPEnterpriseSearchServiceApplicationIndex -Abort [-SearchApplication] <SearchServiceApplication> [-BackupHandleFile] <string> [[-Retries] <int>]


  1. The “[-Force <bool>]” parameter was added.


  1. The “[[-AccessAppsOnly] <bool>]” parameter was added.


  1. The “-Identity” parameter was renamed to “-SiteSubscription”.


  1. The “[-OwnerAlias]” parameter was removed.
  2. The “[-MySiteHost] <SPSitePipeBind>” parameter was added.
  3. The “[-SearchCenter] <SPSitePipeBind>” parameter was added.


  1. The “[-AddToLatestVersion]” switch parameter was changed to “[-CompatibilityLevel <string>]”.


  1. The “[-AddToLatestVersion]” switch parameter was changed to “[-CompatibilityLevel <string>]” for all parameter sets.


  1. The “[-RecoveryPointObjective <int>]” parameter was added to all parameter sets.


  1. The “[-SafeForAnonymous <bool>]” parameter was added.


  1. The “[-DocType <string>]” parameter was removed.
  2. The “[-Extension <string>]” parameter was added.
  3. The “[-ProgId <string>]” parameter was added.
  4. The “[-WOPIAction <string>]” parameter was renamed to “[-Action <string>]”.
  5. The “[-WOPIBinding <SPWopiBindingPipeBind>]” parameter set was removed.


  1. The “[-Force]” switch parameter was added.


  1. The “[-DocType <string>]” parameter was removed.
  2. The “[-Extension <string>]” parameter was added.
  3. The “[-ProgId <string>]” parameter was added.
  4. The “[-WOPIAction <string>]” parameter was renamed to “[-Action <string>]”.
  5. A new parameter set accepting only the “[-Identity <string>]” parameter was added.


  1. The “[-RecoveryPointObjective <int>]” parameter was added.


  1. The “-Identity <SPSiteSubscriptionPipeBind>” parameter was renamed to “-SiteSubscription <SPSiteSubscriptionPipeBind>”.


  1. The “[-SafeForAnonymous <bool>]” parameter was added.


  1. The “[-MachineTranslationCategory <string>]” parameter was added.


  1. The “[-NumberOfExchangeJobsPerServer <uint32>]” parameter was removed.
  2. The “[-MinimumTimeBetweenEwsSyncSubscriptionSearches <timespan>]” parameter was added.
  3. The “[-NumberOfUsersPerEwsSyncBatch <uint32>]” parameter was added.
  4. The “[-NumberOfUsersEwsSyncWillProcessAtOnce <uint32>]” parameter was added.
  5. The “[-NumberOfSubscriptionSyncsPerEwsSyncRun <uint32>]” parameter was added.


  1. The “[-Graceful]” parameter was added.


  1. The “[-CompatibilityLevel <string>]” parameter was added to all parameter sets.


  1. The “[-CompatibilityLevel <string>]” parameter was added.


  1. The “[-SiteUrl <string>]” parameter was added.
  2. The “-AccountName <string>” parameter is now optional.


  1. The “[-SiteSubscription <SPSiteSubscriptionPipeBind>]” parameter was removed.