Thursday, 9 September 2010

Create and manage SharePoint site collection quotas using PowerShell

Whilst you can enforce disk quotas on any site collection in SharePoint, I have seen them used most commonly to cap the amount of disk space used in My Sites. Providing a default site quota template from which all My Sites inherit during creation is easy enough, but it can be a pain for administrators to change the template on existing My Sites as the interface used to modify quota templates on site collections is fine for the odd one or two, but there are no options in the SharePoint UI to bulk modify the quota template used on multiple sites. In this article I will explain how to use PowerShell with SharePoint 2010 to create a new quota template, apply it to a single site collection, and then multiple site collections in one hit.

First, run this script below to set up a function for creating new quota templates:

function CreateQuotaTemplate ($Name, $MaxLevelMB, $WarnLevelMB)
{
    $quotaTemplate = New-Object Microsoft.SharePoint.Administration.SPQuotaTemplate
    $quotaTemplate.Name = $Name
    $quotaTemplate.StorageMaximumLevel = ($MaxLevelMB*1024)*1024
    $quotaTemplate.StorageWarningLevel = ($WarnLevelMB*1024)*1024
    $contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
    $contentService.QuotaTemplates.Add($quotaTemplate)
    $contentService.Update()
}

Once you have run the script, type the following command to create a new quota template in your SharePoint farm:

CreateQuotaTemplate –Name “Template Name” –MaxLevelMB MaximumLevelInMB –WarnLevelMB WarningLevelInMB

For example, if we wanted to create a new quota template called “Media Users” with a maximum quota size of 500 MB and warning level of 400 MB, then we can type this command:

CreateQuotaTemplate –Name “Media Users” –MaxLevelMB 500 –WarnLevelMB 400

Now run this script to set up a function for assigning a quota template to a single site collection:

function AssignQuotaTemplate ($Name, $Url)
{
    $contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
    $quotaTemplate = $contentService.QuotaTemplates[$Name]
    Set-SPSite -Identity $Url -QuotaTemplate $quotaTemplate
}

Once this script has been run, you can now use the following command to assign our “Media Users” quota template to a single site collection:

AssignQuotaTemplate –Name “Media Users” –Url http://mysite/personal/phil.childs

Finally, run this script to set up a function for replacing a quota template across all site collections in a web application:

function BulkReplaceQuotaTemplates ($WebApp, $OldTemplate, $NewTemplate)
{
    $contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
    $oldQuotaTemplate = $contentService.QuotaTemplates[$OldTemplate]
    $newQuotaTemplate = $contentService.QuotaTemplates[$NewTemplate]
    $webApplication = Get-SPWebApplication $WebApp
    $webApplication | Get-SPSite -limit all | ForEach-Object {
        if ($_.Quota.QuotaID -eq $oldQuotaTemplate.QuotaID) {   
            Set-SPSite -Identity $_.Url -QuotaTemplate $newQuotaTemplate
        }
    }
}

This function allows you to specify the web application, old quota template you want to replace, and the new quota template you want to replace it with. For example, lets assume that all My Sites in your SharePoint implementation have been created with the default “Personal Site” quota template. We could run a script to simply bulk change all of these site collections to a new quota template, but there may be the odd one or two that have been configured with individual quotas. Therefore, the command below will walk through each site collection in the web application and change the quota template to “Media Users”, but only on site collections that are currently configured with the “Personal Site” quota template – leaving alone any site collections that have been configured with individual quota templates:

BulkReplaceQuotaTemplates -WebApp http://mysite -OldTemplate "Personal Site" -NewTemplate "Media Users”

19 comments:

  1. Hi, Thank you for your script but i can't do it on my 2007 Farm. The command Set-SPSite isn't reconized. Have you an idea ?

    Nicolas LAVOLO
    France

    ReplyDelete
  2. You should be able to do the same thing by setting up a $spsite variable from a new SPSite object (see an example at http://nickgrattan.wordpress.com/2007/09/03/preparing-powershell-for-sharepoint-and-moss-2007/) and then using this line:

    $spsite.Quota = $quotaTemplate

    or for the bulk replace script:

    $spsite.Quota = $newQuotaTemplate

    although bear in mind that I haven't tested it yet for 2007...

    ReplyDelete
  3. Thank you for your help but it doesn't Work.
    Here my Sscript if you've an idea. I'm a newbee in powershell but i try :)

    [System.Reflection.Assembly]::Load(“Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”)
    [System.Reflection.Assembly]::Load(“Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”)

    function CreateQuotaTemplate ($Name, $MaxLevelMB, $WarnLevelMB)
    {
    $quotaTemplate = New-Object Microsoft.SharePoint.Administration.SPQuotaTemplate
    $quotaTemplate.Name = $Name
    $quotaTemplate.StorageMaximumLevel = ($MaxLevelMB*1024)*1024
    $quotaTemplate.StorageWarningLevel = ($WarnLevelMB*1024)*1024
    $contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
    $contentService.QuotaTemplates.Add($quotaTemplate)
    $contentService.Update()
    }

    CreateQuotaTemplate –Name “Power” –MaxLevelMB 300 –WarnLevelMB 280



    function AssignQuotaTemplate ($Name, $Url)
    {
    $SPsite=[Microsoft.Sharepoint.SPSite] ("http://testcollaboration.eu.areva.corp/test")
    $contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
    $quotaTemplate = $contentService.QuotaTemplates[$Name]
    $SPsite.Quota = $quotaTemplate

    }

    ReplyDelete
  4. Almost... Change the URL you have specified in your $SPSite declaration to the variable $Url. Then include the actual URL when running the AssignQuotaTemplate function - full script below


    [System.Reflection.Assembly]::Load(“Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”)
    [System.Reflection.Assembly]::Load(“Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”)

    function CreateQuotaTemplate ($Name, $MaxLevelMB, $WarnLevelMB)
    {
    $quotaTemplate = New-Object Microsoft.SharePoint.Administration.SPQuotaTemplate
    $quotaTemplate.Name = $Name
    $quotaTemplate.StorageMaximumLevel = ($MaxLevelMB*1024)*1024
    $quotaTemplate.StorageWarningLevel = ($WarnLevelMB*1024)*1024
    $contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
    $contentService.QuotaTemplates.Add($quotaTemplate)
    $contentService.Update()
    }

    CreateQuotaTemplate –Name “Power” –MaxLevelMB 300 –WarnLevelMB 280



    function AssignQuotaTemplate ($Name, $Url)
    {
    $SPsite = [Microsoft.Sharepoint.SPSite] ($Url)
    $contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
    $quotaTemplate = $contentService.QuotaTemplates[$Name]
    $SPsite.Quota = $quotaTemplate
    }

    AssignQuotaTemplate -Name "Power" -Url "http://portal"

    ReplyDelete
  5. Thank you very much for your help. The Script works Well. The issue was the F5 Refresh not Work.
    To see the changed Quotatemlate, you need to go to other page and come back to the sitecollectionquota and locks from central admin page.

    ReplyDelete
  6. Hey this was a great help, i used bits of this in my auto deploy script http://autospdeploy.codeplex.com

    I've tried however to use powershell to delete quotas and have run into problems. I tried the following but no luck:

    Function DeleteQuota ($name)
    {
    $contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
    $quotaTemplate = $contentService.QuotaTemplates[$name]
    $contentService.QuotaTemplates.Delete($quotaTemplate)
    $contentService.Update()
    }

    any thoughts?

    ReplyDelete
  7. James - Are you trying to remove a quota from a site collection or remove the quota template from the farm entirely?

    ReplyDelete
  8. Hi Phil

    Can you explain why you needed to change your code from this

    function AssignQuotaTemplate ($Name, $Url)
    {
    $contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
    $quotaTemplate = $contentService.QuotaTemplates[$Name]
    Set-SPSite -Identity $Url -QuotaTemplate $quotaTemplate
    }

    To this for Nicolas stuff to work

    function AssignQuotaTemplate ($Name, $Url)
    {
    $SPsite = [Microsoft.Sharepoint.SPSite] ($Url)
    $contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
    $quotaTemplate = $contentService.QuotaTemplates[$Name]
    $SPsite.Quota = $quotaTemplate
    }

    I've done the same for myself and everything works like a charm. I'm just trying to understand why?

    ReplyDelete
  9. I'm also now trying to get the BulkLoad code to run, but am getting errors similar the what the above code gave before you amended it and posted back to Nicolas?

    function BulkReplaceQuotaTemplates ($WebApp, $OldTemplate, $NewTemplate)
    {
    $contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
    $oldQuotaTemplate = $contentService.QuotaTemplates[$OldTemplate]
    $newQuotaTemplate = $contentService.QuotaTemplates[$NewTemplate]
    $webApplication = Get-SPWebApplication $WebApp
    $webApplication | Get-SPSite -limit all | ForEach-Object {
    if ($_.Quota.QuotaID -eq $oldQuotaTemplate.QuotaID) {
    Set-SPSite -Identity $_.Url -QuotaTemplate $newQuotaTemplate
    }
    }
    }

    The term 'Get-SPWebApplication' is not recognized as a cmdlet, function, operable program, or script file. Verify the t
    erm and try again.
    At C:\Users\120575b.syn\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1:28 char:43
    + $webApplication = Get-SPWebApplication <<<< $WebApp
    The term 'Get-SPSite' is not recognized as a cmdlet, function, operable program, or script file. Verify the term and tr
    y again.
    At C:\Users\120575b.syn\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1:29 char:33
    + $webApplication | Get-SPSite <<<< -limit all | ForEach-Object {

    Is there some further amendments which need to be made? Any advice much appreciated!

    Many thanks in advance

    Steve

    ReplyDelete
  10. Hmmm, after some more digging, testing, learning! I'm still trying to figure out where I'm going wrong here, however I have some ideas (gradually I think I am fathoming this out!)

    Is your last code snippet for the bulkquotatemplate only going to work with SP2010 because of the included PowerShell cmdlets?

    The real question then, is could it ever work on SharePoint 2007?

    ReplyDelete
  11. VitalHostage - that's a lot of questions! :-)

    Yes, you are correct, SP2010 includes the Set-SPSite cmdlet, which isn't available in 2007. Neither do the Get-SPWebApplication or Get-SPSite cmdlets either.

    Check this article for 2007 replacements to these cmdlets and see if you can work it out from there: http://get-spscripts.com/2011/03/using-powershell-scripts-with-wss-30.html

    ReplyDelete
  12. Hi Phil

    Thanks for the information. Much appreciated. Nothing like trying to reinvent the wheel to get that banging head against wall feeling!

    I can work around the shortcomings of 2007, however I'm still slightly confused over one thing, however I'll figure that out for myself instead of asking you for an answer.

    Cheers for getting back in touch though. Much appreciated

    ReplyDelete
  13. I wanted to thank you because your script saved me a lot of aggravation.

    I needed to have these functions available in C#, so I created a module file in powershell with your functions, but adjusted to play well in powershell.

    You can save the below as a .ps1 file and load it into normal powershell or sharepoint powershell. The parameters were adjusted to the v2 format and the functions were set to global.

    Now you can do New-SPQuotaTemplate


    Add-PSSnapin Microsoft.SharePoint.PowerShell -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
    function global:New-SPQuotaTemplate
    {
    param(
    [Parameter(Position=0, Mandatory=$true)]
    [string]$Name,
    [Parameter(Position=1, Mandatory=$true)]
    [int]$MaxLevelMB,
    [Parameter(Position=2, Mandatory=$true)]
    [int]$WarnLevelMB
    )
    $quotaTemplate = New-Object Microsoft.SharePoint.Administration.SPQuotaTemplate
    $quotaTemplate.Name = $Name
    $quotaTemplate.StorageMaximumLevel = ($MaxLevelMB*1024)*1024
    $quotaTemplate.StorageWarningLevel = ($WarnLevelMB*1024)*1024
    $contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
    $contentService.QuotaTemplates.Add($quotaTemplate)
    $contentService.Update()
    }

    function global:Set-QuotaTemplate
    {
    param(
    [Parameter(Position=0, Mandatory=$true)]
    [string]$Name,
    [Parameter(Position=1, Mandatory=$true)]
    [string]$Url
    )
    $contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
    $quotaTemplate = $contentService.QuotaTemplates[$Name]
    Set-SPSite -Identity $Url -QuotaTemplate $quotaTemplate
    }

    function global:New-BulkReplaceQuotaTemplates
    {
    param(
    [Parameter(Position=0, Mandatory=$true)]
    [string]$WebApp,
    [Parameter(Position=1, Mandatory=$true)]
    [string]$OldTemplate,
    [Parameter(Position=2, Mandatory=$true)]
    [string]$NewTemplate
    )
    $contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
    $oldQuotaTemplate = $contentService.QuotaTemplates[$OldTemplate]
    $newQuotaTemplate = $contentService.QuotaTemplates[$NewTemplate]
    $webApplication = Get-SPWebApplication $WebApp
    $webApplication | Get-SPSite -limit all | ForEach-Object {
    if ($_.Quota.QuotaID -eq $oldQuotaTemplate.QuotaID) {
    Set-SPSite -Identity $_.Url -QuotaTemplate $newQuotaTemplate
    }
    }
    }

    ReplyDelete
  14. Just want to say thanks!!! Your code worked like a charm and saved me many hours of labor.

    ReplyDelete