Quickly Remove ALL Webs under a Site Collection Using PowerShell


I was cleaning up my demo site collection, and I needed to remove all subwebs… Here’s a quick one-liner of PowerShell to do exactly that.

Get-SPSite <SiteUrl> | Get-SPWeb -Limit All | ForEach-Object {Remove-SPWeb -Identity $_ -Confirm:$false}
</ShortestPostEver>

Remove SharePoint List Views Using PowerShell


Ever have a need to delete list views using PowerShell?  Of course you do, it’s a great reason to use PowerShell!

Luckily for us, there is great access to the Object Model and we can readily access lists, items, and of course views.

I threw together a nifty little function that accepts three parameters, WebUrl, ListName and ViewName and will remove a single view from a SharePoint list.

The code is quite simple, basically we grab an SPWeb object using the WebUrl parameter – we then grab an SPList using the ListName parameter, and finally we grab an SPListView using the ViewName parameter.  Once we’ve drilled down to the specific SPListView, we can call the Delete() method using the ID of the view.

Here’s my function, enjoy!

function Remove-SPListView {
Param(
[string]$WebUrl,
[string]$ListName,
[string]$ViewName
)
Start-SPAssignment -Global
$SPWeb = Get-SPWeb $WebUrl
$List = $SPWeb.Lists[$ListName]
$View = $List.Views[$ViewName]
$List.Views.Delete($View.ID)
$List.Update()
$SPWeb.Update()
$SPWeb.Dispose()
Stop-SPAssignment -Global
}

Making SharePoint 2010 PowerShell Scripts Backward-Compatible with 2007


Recently I received an e-mail from one of my ICC SharePoint team-mates asking for some PowerShell code to create and then delete a lot of list items. Like 20000. Well, I already had code to create the list items – so it was easy to add a single line to call the delete() method immediately after the item was added.

I provided the updated function to my teammate, only to find out later that they wanted to do this in MOSS 2007 – not SP2010. Oops! I hadn’t considered that, I assumed since they were asking me for PowerShell code that they were dabbling in a 2010 environment. Not the case. However, this particular person is one of our better SharePoint Developers and quickly modified the code to work in MOSS.

After having that discussion, it became clear to me that it would be REALLY cool to create PowerShell Scripts and Functions that would work both in V4 as well as V3. And the journey began..

After some experimentation, googling, trial & error – it became apparent that this isn’t rocket science. In SharePoint 2010 we use the following PowerShell cmdlet to add the SharePoint Snap-in:

Add-PSSnapIn Microsoft.SharePoint.PowerShell

There’s no equivalent for MOSS environments, but we can load the SharePoint assemblies by using the following line of code:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

Once we’ve done that, we can do other things such as get the farm build version and tell us what version we’re working with:

function Get-SPFarmBuildVersion {
# using the [microsoft.sharepoint.administration.spfarm] line to get the local farm regardless of version #
# this works in 2007 and 2010 #
$farm = [Microsoft.SharePoint.Administration.SPFarm]::Local
$farmBuild = $farm.BuildVersion.ToString()

      if ($farmBuild.StartsWith("12")) {
      Write-Host "This is WSS or MOSS"
      } 
      
      elseif ($farmBuild.StartsWith("14")) {
      Write-Host "This is SP2010"
      }

}

How cool is that!?

Now that we know that simple tidbit, we can easily create our scripts and functions with backward compatibility in mind by doing something like if/elseif as seen above. Developers may chime in with a better way, I’m sure there are better – perhaps more elegant approaches to this same theory – but this works for me for now.

Anyhow, back to the story – my developer friend Aaron wanted to create list items in MOSS using PowerShell. Here’s the code to do that – and it’s backwards compatible!

function Add-MultipleListItems {
[CmdletBinding()]
Param(
[string]$ListName=(Read-Host "Please enter the name of the list you wish to add to."),
[string]$Amount=(Read-Host "Please enter a number of list items to create."),
[string]$Choices=(Read-Host "Please enter choices separated by semicolons, enclosed in double quotes."),
[string]$ListItem=(Read-Host "Please enter a string for the title of each list item (Example: Added by Powershell)"),
[string]$WebUrl=(Read-Host "Please enter a URL of a SharePoint site (Example: http://intranet)")
)

$choicesForCategory = $Choices -split ";"

$assemblies = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
$farm = [Microsoft.SharePoint.Administration.SPFarm]::Local
$farmBuild = $farm.BuildVersion.ToString()
	
	if ($farmBuild.StartsWith("14")) {
		Start-SPAssignment -Global
		$mylist = (Get-SPWeb -identity $webUrl -AssignmentCollection $StartSpAssignment).Lists[$listName]
		Write-Host "Creating $amount list items in $listName" -ForegroundColor Green
		$i = 1
		do 
		{
		    $newItem = $mylist.Items.Add()
		    $newItem["Title"] = $listItem
		    $newItem["Category"] = $choicesForCategory | Get-Random
		    $newItem.Update()
		    $i++
		}
		while ($i -le $amount)

		Write-Host "Finished!" -ForegroundColor Green
		Stop-SPAssignment -Global
	}
	elseif ($farmBuild.StartsWith("12")) {
		$SPWeb = Get-SPWeb $webUrl
		$mylist = $SPWeb.Lists[$listName]
		Write-Host "Creating $amount list items in $listName" -ForegroundColor Green
		$i = 1
		do 
		{
		    $newItem = $mylist.Items.Add()
		    $newItem["Title"] = $listItem
		    $newItem["Category"] = $choicesForCategory | Get-Random
		    $newItem.Update()
		    $i++
		}
		while ($i -le $amount)
		$SPWeb.dispose()
		Write-Host "Finished!" -ForegroundColor Green
	}
}

If you read this line by line, you’ll notice that they are fundamentally identical. Really the only difference is in V3 we don’t get any cmdlets, so we don’t have Start-SPAssignment and Stop-SPAssignment. This just means we have to make sure we’re disciplined to use dispose() methods for any SPWeb and SPSite objects.

With all that in mind, my goal from here on out is to try and make any and all PowerShell code backwards compatible.

RD

SharePoint Saturday Cincinnati 2011


This past weekend I broke new ground in my career – I completed my first public speaking engagement! While I have spoken on various topics in front of my SharePoint Team at ICC – this was my first public speaking engagement and overall I think it went very well.

The topic: The Power is in the Shell, use it wisely!
The story: What is PowerShell – how does it fit into the SharePoint 2010 puzzle? How can we take commands run in the Shell and easily convert them to scripts or functions? How can we use the Get-Content cmdlet and some XML to automate content loading or migrations? What are some best practices around PowerShell as it relates to SharePoint 2010?

This was the first SharePoint Saturday in Cincinnati, and I was very proud to be a part of a great event.

My session went pretty flawlessly, as I lucked out and had zero issues with the presentation or the three demos. I had a small group of attendees, but all of them were very engaged in dialog throughout. For those of you who attended, thank you for being a part of it – and if you have any feedback or questions feel free to contact me either on Twitter or via e-mail (rdennis at iccohio dot com).

I promised to upload my slides and demo PowerShell code, so the slides are on Slideshare and the XML and PowerShell code is below:

First demo function – Set-SPWebTitle

function Set-SPWebTitle {
Param(
[string]$SiteUrl,
[string]$SiteTitle
)
$site = Get-SPSite $SiteUrl
$web = $site.RootWeb                                                                                                   
$web.Title = $SiteTitle
Write-Host "Changing title to:" $SiteTitle
$web.Update()                                                                                                          
$web.Dispose()                                                                                                        
$site.Dispose()           
Write-Host "Finished!"
}

Second demo function – New-SPWebFromXml
XML Syntax:

<?xml version="1.0" encoding="utf-8"?>
<Sites>
  	<Site>
    		<SiteTitle>Ryan Dennis</SiteTitle>
	    	<SiteUrl>http://sps.adventureworks.com/rdennis</SiteUrl>
	    	<Page>
			<PageTitle>Home</PageTitle>
			<PageUrl>Home.aspx</PageUrl>
			<PageContent>HTML Content</PageContent>
			<PageLayout>Body Only</PageLayout>
		</Page>
  	</Site>
</Sites>

PowerShell code:

function New-SPWebFromXml {
# Xml Input parameter - accepts string to filename
[CmdletBinding()]
	Param(
    [Parameter(Mandatory=$true)]
	[string]$XmlInput
	)

# Read in list of sites from XML file
[xml]$SitesXml = Get-Content $($XmlInput)
if ($SitesXml -eq $null) {return}
Start-SPAssignment -Global #Stores all objects in the global store for proper disposal
$StartTime = Get-Date #Grab the date & time for further calculation later

# Upload speaker images to the PublishingImages library
Write-Host "Uploading speaker images to the PublishingImages library..."
Add-SPFilesToLibrary -WebUrl http://sps.adventureworks.com -LibraryName PublishingImages -FileExtension "*.jpg" -FolderLocation "C:\SPSDemo\Speakers"

	# Loop through each site node to extract data
	$SitesXml.Sites.Site | ForEach-Object {
	$SiteTitle = [string]$_.SiteTitle
	$SiteUrl = [string]$_.SiteUrl
	$WebTemplate = "CMSPUBLISHING#0"
	$LangId = "1033"
	
	# Get publishing site and web objects
	$site = New-Object Microsoft.SharePoint.SPSite($SiteUrl)
	$psite = New-Object Microsoft.SharePoint.Publishing.PublishingSite($site)
	$web = $site.OpenWeb()
	$pWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)
	
	# Create the SPWeb
	Write-Host "Creating an SPWeb at $($SiteUrl)"
	New-SPWeb -Url $SiteUrl	-Language $LangId -Template $WebTemplate -Name $SiteTitle
	
	# Create page content variables from XML file
	$PageTitle = [string]$_.Page.PageTitle
	$PageUrl = [string]$_.Page.PageUrl
	$PageLayout = [string]$_.Page.PageLayout
	$PageContent = [string]$_.Page.PageContent
	$PageImage = [string]$_.Page.PageImage
	$layout = $pWeb.GetAvailablePageLayouts() | Where-Object {$_.Title -match $PageLayout}
	
    # Create blank page using Add method
	Write-Host "Creating $($PageTitle).aspx page"
    $pages = $pWeb.GetPublishingPages($pWeb)
	$page = $pages.Add($PageUrl, $layout)
	$page.Update()
	
    # Update the filename to the one specified in the XML, add HTML content to Page Content zone
    $item = $page.ListItem
	$item["Title"] = $PageTitle;
	$item["Page Content"] = $PageContent;
	$item.Update()
	
    # Check-in and publish page
    $item.File.CheckIn("")
    $item.File.Publish("")
	$file = $item.File
	$pWeb.DefaultPage = $file
	$pWeb.Update()
	
	# Get and delete original default.aspx page
	Write-Host "Deleting default.aspx page"
	$list = $web.lists["Pages"]
	$oldPage = $list.items | Where-Object {$_.Name -match "default"}
	$oldPage.Delete();
	$web.Update()
	} #End ForEach-Object loop
	
$EndTime = Get-Date #Grab the ending date & time to get the timespan
$TimeSpan = New-TimeSpan $StartTime $EndTime #Calculate total time taken
Write-Host "$($SitesXml.Sites.Site.Count) sites created in $timespan"
Stop-SPAssignment -Global #Stop assignment, safely disposing all site and web objects
} #End Function

Update: Use PowerShell to make an entire web application read-only


For those who have been following my posts for a while, they’re probably wondering why I’m blogging about something I’ve already done.

The answer is simple: I found a better way!

In the 7 months since I wrote a post on how to make an entire web application read-only, I’ve learned quite a bit about PowerShell, and the ForEach-Object cmdlet. I now have a better version of the advanced function I showed off back in March, and this one has a new switch parameter (-AllContentWebApplications) which obviously allows you to run the Set-SPSiteLockState function against all web applications (excluding Central Admin).

I like this version a LOT better, and it’s much cleaner. If you only need to run the function against a single web app, that functionality still exists – just exclude the switch param.

Here it is!

function Set-SPSiteLockState {
<#
.Synopsis
	Use this PowerShell script to set the Lock State of a SharePoint Web Application to Unlock, ReadOnly, NoAdditions or NoAccess.
.Description
	This PowerShell script uses Set-SPSiteAdministration to set the Lock State of a SharePoint Web Application.
.Example
	C:\PS>Set-SPSiteLockState -WebAppUrl http://intranet -LockState ReadOnly
	This example sets all site collections in a web application at http://intranet to read-only.
.Example
	C:\PS>Set-SPSiteLockState -AllContentWebApplications -LockState ReadOnly
	This example sets all web applications to read-only.
.Notes
	Name: Set-SPSiteLockState
	Author: Ryan Dennis
	Last Edit: 10/14/2011
	Keywords: Set Lock State, Set-SPSiteAdministration, Set-SPSiteLockState
.Link
	http://www.sharepointryan.com
 	http://twitter.com/SharePointRyan
.Inputs
	None
.Outputs
	None
#Requires -Version 2.0
#>
[CmdletBinding()]
Param(
[string]$WebAppUrl,
[string]$LockState=(Read-Host "Please enter a Lock State (Examples: Unlock, NoAccess, ReadOnly)"),
[switch]$AllContentWebApplications
)
Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue
Start-SPAssignment -Global
if($AllContentWebApplications){
Write-Host "Setting all web applications to $($LockState)..."
$WebApp = Get-SPWebApplication
	$WebApp | ForEach-Object{
	$AllSites = $WebApp | Get-SPSite -Limit All -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
		$AllSites | ForEach-Object{
		Set-SPSiteAdministration -LockState $LockState -Identity $_.url
		}
	}
}
else{
$WebApp = Get-SPWebApplication $WebAppUrl
$AllSites = $WebApp | Get-SPSite -Limit All -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
Write-Host "Setting $WebAppUrl to $lockState..." -ForegroundColor Yellow
$AllSites | ForEach-Object { Set-SPSiteAdministration -LockState $lockState -Identity $_.url }
}

Stop-SPAssignment -Global
Write-Host "Finished!" -ForegroundColor Green
}