DogFoodCon 2014 to feature dedicated PowerShell track!


For several years now, the IT conference slate in Central Ohio has been dominated by the ever popular Dog Food Conference. That trend will continue this year, when Columbus once again hosts the 2-day Microsoft Dog Food Conference on September 29th and 30th. Multiple technologies will be featured, including Windows PowerShell.

I will be presenting on Managing SharePoint Anywhere using PowerShell, alongside these nationally recognized PowerShell Experts:

The event will certainly be phenomenal once again, and I hope to see you there!

cloud

 

Using PowerShell to manage SharePoint Online


Anybody who knows me or has ever read a single post of mine knows I’m a big PowerShell geek. I like it, I love it and I always want some more of it. Bad song lyrics aside, I quite literally use PowerShell every day for one task or another. Over the past 6 months or so I’ve been quietly working on creating some Cmdlets/Functions that will allow me to run PowerShell against Office 365 SharePoint Online. This might sound easy – but spoiler alert – it’s not. That’s not to say it’s difficult, if you’re a developer who is comfortable with CSOM, you’ll be just fine. However, I didn’t have those skills when I took off on this adventure; so needless to say it’s been a bit of a learning experience, combined with a lot of trial & error.

There are really a few key steps which must be taken prior to getting SharePoint Online and PowerShell to talk to one another.

  1. Set up the SharePoint Online Management Shell Windows PowerShell environment
  2. Run Connect-SPOService to connect to a SharePoint Online Administration Center

Once you’ve completed those two simple tasks, you’ve got the baseline environmental requirements in place to start using PowerShell with SharePoint Online. However, if I was writing a blogpost to tell you how to run the 30 built-in cmdlets you get by loading the Microsoft.Online.SharePoint.PowerShell module; well, you’d be left wanting more.

To really start doing the fun developer stuff, you will want to make sure you load the Microsoft.SharePoint.Client and Microsoft.SharePoint.Client.Runtime assemblies into your session. I’ve written a nice little function for this, which looks like:

function Add-SPOAssemblies {
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") | Out-Null
}

Then, to run it – just use:

Add-SPOAssemblies

Pretty simple, and it just loads those two assemblies so you can access all the goodies that come with them.

Once you’ve gotten there, you can start to do things like create ClientContext against an SPWeb:

$webUrl = "SPOWebUrl"
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($webUrl)
$creds = Get-Credential -Message "Please enter your Office 365 Administrative credentials"
$ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($creds.UserName,$creds.Password)
$spoweb = $ctx.Web
$ctx.Load($spoweb)
$ctx.ExecuteQuery()

So that’s cool, but it hasn’t done anything yet! Well try this:

$spoweb.Title

Ohhhh… So now that’s cool! Once you’ve gotten this far, i’m sure you can start to see the possibilities.

In case you want to wrap that up into a nice function, here’s a simple example that I think works well:

function New-SPOServiceContext {
[CmdletBinding()]
Param(
[System.String]$EmailAddress,
[System.String]$SPOWebUrl
)
try {
$assemblies=Add-SPOAssemblies
}
catch {
Write-Error "Unable to load Microsoft.SharePoint.Client assemblies"
}
if($assemblies){
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SPOWebUrl)
$creds = Get-Credential -Message "Please enter your Office 365 Administrative credentials" -UserName $EmailAddress
$ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($creds.UserName,$creds.Password)
$spoweb = $ctx.Web
$ctx.Load($spoweb)
$ctx.ExecuteQuery()
}
}

And of course to run it, use:

New-SPOServiceContext -EmailAddress your.email@your-company.com -SPOWebUrl https://something.sharepoint.com

“But wait, at the beginning you said this was challenging – this was way too easy!?”

Well, I wasn’t used to having to create a context object, then a credential object, followed by a web variable, and then I have to load and execute a query?! All new to me, but again – I haven’t done very much (read: any) development on the client side.

I could share loads of other cool things I’ve done, but you’ll have to wait while I clean up and finish some of the functions I’ve been working on. Until then, happy PowerShelling!

Run all SharePoint Health Analyzer Jobs with PowerShell


Today I had a need to run all health analyzer jobs to make sure everything was good after a clean install of SharePoint 2010. Of course I knew there had to be a quick PowerShell approach to this. I did a quick search and found a few different variations of the same basic code, so I took what I liked and made it into a simple function that I will store in the profile on my SP machines going forward.

The blog that had exactly what I wanted, both in the body and the comments was Matthew McDermott’s blog – here. Matthew has a more structured approach using a foreach loop to iterate through each job in the collection, and then he calls the RunNow() method to start the jobs. Gary LaPointe commented and provided a one-liner, which I’m going to use – although I am putting that one-liner into a function…

By making a simple function, I can just run the function like a cmdlet – so it makes it very easy to run going forward.

Here is the function:

function Start-SPHealthTimerJobs {Get-SPTimerJob | Where-Object {$_.Title -like “*Health Analysis Job*”} | Start-SPTimerJob}

And to run it, I simply type:

Start-SPHealthTimerJobs

SharePoint Saturday Austin 2013


Today I spoke in front of a great crowd at SharePoint Saturday Austin, which was an all-around blast!

The presentation was about PowerShell (shocker, right?) – but this time had a different vibe as I modified one of my presentations to work in SharePoint 2013 – and I also utilized PowerShell Web Access in Google Chrome for 100% of the technical demonstrations.

Below is a description of the topic itself along with PowerPoint Slides and the PowerShell and XML code that was used in the demo:

The Power is in the Shell, use it wisely!

The topic: The Power is in the Shell, use it wisely!
The story: You may have heard of PowerShell, but do you know what it’s capable of? Gone are the days of long, painful STSADM batch files – we have Windows PowerShell, and it’s here to stay.Learn how you can use Windows PowerShell both to perform simple one-off tasks as well as complex, bulk operations. Leveraging the Object Model gives Administrators and Developers the ability to do in a few lines of code what would’ve taken a lot more work (and probably a Developer or two) in the WSS platform.

In this demo filled session, you’ll see how you can get started with PowerShell, and you will hopefully leave with not only a greater understanding of what PowerShell is – but what it is capable of and how you can start using it to automate tasks in your SharePoint 2010 or 2013 environment.

Here are my slides, and below are the code snippets:

PowerShell code:

Demo 1

Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
$Template = Get-SPWebTemplate BLANKINTERNETCONTAINER`#0
$Url = "http://sp2013.spsatx.adventureworks.com"
$Site = Get-SPSite $Url
$Site = New-SPSite $Url -OwnerAlias adventureworks\rdennis -Template $Template
$Web = $Site.RootWeb
$web | Get-Member -MemberType property</em></em></em>
$Web.Title = "SharePoint Saturday - Austin, TX"
$Web.Update()
$Web.Dispose()
$Site.Dispose()

Demo 2

function Set-SPWebTitle {
<#
.Synopsis
	Use Set-SPWebTitle to update the Title of a SharePoint Web.
.Description
	This function uses SharePoint Cmdlets and Object Model code to set the title property of a SharePoint Web.
.Example
	C:\PS>Set-SPWebTitle -WebUrl http://<siteUrl> -Title "New Title"
    This example updates the title of a web at http://<siteUrl> to "New Title"
.Notes
	Name: Set-SPWebTitle
	Author: Ryan Dennis
	Last Edit: 2/24/2013
.Link
	http://www.sharepointryan.com
 	http://twitter.com/SharePointRyan
.Inputs
	None
.Outputs
	None
#Requires -Version 2.0
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)][System.String]$WebUrl,
[Parameter(Mandatory=$true)][System.String]$Title
)
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
$Web = Get-SPWeb $WebUrl
$Web.Title = $Title
$Web.Update()
$Web.Dispose()
}

Demo 3

function New-SPWebFromXml {
<#
.Synopsis
	Use this PowerShell Script to create lots of sites, very quickly!
.Description
	This advanced function uses Get-Content, ForEach-Object and New-SPWeb 
	cmdlets to bulk create SharePoint webs from an XML file.
.Example
	C:\PS>New-SPWebFromXml -Url http://<siteUrl> -XmlInput c:\Sites.xml
	This example creates sites from an XML located at c:\Sites.xml under a site 
	collection at http://<siteUrl>. 
.Notes
	Name: New-SPWebFromXml
	Author: Ryan Dennis
	Last Edit: 2/24/2013
	Keywords: New-SPWeb, Get-Content, ForEach-Object, New-Timespan, XML
.Link
	http://www.sharepointryan.com
 	http://twitter.com/SharePointRyan
.Inputs
	None
.Outputs
	None
#Requires -Version 2.0
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)][System.String]$Url,
[Parameter(Mandatory=$true)][System.String]$XmlInput
)
Clear-Host

# If SharePoint Snapin isn't loaded - load it #
if ((Get-PSSnapin Microsoft.SharePoint.PowerShell)-eq $null)
{
	Write-Host "Adding SharePoint Snapin"
	Add-PSSnapin Microsoft.SharePoint.PowerShell
}
$i=0
do {

# Read in list of sites from XML file #
[xml]$SitesXml = Get-Content $($XmlInput)
if ($SitesXml -eq $null) { return }

$siteCount = $SitesXml.Sites.Site.Count
Write-Progress -Activity "Provisioning SharePoint Webs from XML" -PercentComplete (($i/$siteCount) * 100) `
-Status "Retrieving XML Data" -ErrorAction SilentlyContinue
Start-Sleep -Seconds 2

Start-SPAssignment -Global

# Loop through each site node to extract data #
$SitesXml.Sites.Site | ForEach-Object {
    $SiteTitle = [string]$_.SiteTitle
	$SiteUrl = [string]$_.SiteUrl
    Write-Progress -Activity "Provisioning SharePoint Webs from XML" -PercentComplete (($i/$siteCount) * 100) `
    -Status "Creating an SPWeb at $($SiteUrl)" -ErrorAction SilentlyContinue
	$i++
	# Site specifics # 
	$WebTemplate = "BLANKINTERNET`#0"
	$LangId = "1033"
	$SiteUrl = $Url+$SiteUrl
	# Create the SPWeb #
	if ($_.create -ne "false")
	{
	$Web = New-SPWeb -Url $SiteUrl -Language $LangId -Template $WebTemplate `
	-Name $SiteTitle
	}
	else
	{
	$Web = Get-SPWeb -Identity $SiteUrl
	}
	# Get publishing site and web objects
	$site = $web.Site
	$pWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)
	$pagesLib = $pWeb.PagesList

    # Enable moderation on Pages libraries #
	$pagesLib.EnableModeration = $true;
	$pagesLib.EnableMinorVersions = $true;
	$pagesLib.Update()	

	# Create all Pages using ForEach-Object #
	if ($_.Page -ne $null){
	$pages = $_.Page | ForEach-Object {
	
	# Create page content variables from XML file
	$PageTitle = [string]$_.PageTitle
	$PageUrl = [string]$_.PageUrl
	$PageLayout = [string]$_.PageLayout
	$PageContent = [string]$_.PageContent
	$PageImage = [string]$_.PageImage
	$layout = $pWeb.GetAvailablePageLayouts() | Where-Object {$_.Title -match $PageLayout}
	
    # Create blank page using Add method
	Write-Progress -Activity "Provisioning SharePoint Webs from XML" -PercentComplete (($i/$siteCount) * 100) `
    -Status "Creating $($PageTitle).aspx page" -ErrorAction SilentlyContinue
    $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.Update()
	
   	# Check-in and publish page
    $item.File.CheckIn("")
    $item.File.Publish("")
	$item.File.Approve("")
	$file = $item.File
	# If the page is marked as the Home Page in XML, set it as welcome page #
	if($_.IsHomePage -eq "true"){
	$pWeb.DefaultPage = $file
	}
	$pWeb.Update()
	
	} #end Page Foreach
	
	} # End if block #
	
} # End ForEach-Object loop #
} while ($i -lt $siteCount)
} # End function

XML Syntax:

<?xml version="1.0" encoding="utf-8"?>
<Sites>
  <SiteAdmins>
    <User>adventureworks\rdennis</User>
    <User>adventureworks\spfarm</User>
  </SiteAdmins>
  <!-- root site -->
  <Site Create="false">
    <SiteTitle>Home</SiteTitle>
    <SiteUrl>/</SiteUrl>
		<Page IsHomePage="false">
		  <PageTitle>Intranet Governance</PageTitle>
		  <PageUrl>Intranet-Governance.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Terms of Use</PageTitle>
		  <PageUrl>Terms-of-Use.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Privacy Policy</PageTitle>
		  <PageUrl>Privacy-Policy.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Linking Policy</PageTitle>
		  <PageUrl>Linking-Policy.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Legal Disclaimer</PageTitle>
		  <PageUrl>Legal-Disclaimer.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Help Me</PageTitle>
		  <PageUrl>Help-Me.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
  </Site>
  <!-- 2nd level sites -->
  <Site>
    <SiteTitle>My Company</SiteTitle>
    <SiteUrl>/My-Company</SiteUrl>
		<Page IsHomePage="true">
		  <PageTitle>My Company</PageTitle>
		  <PageUrl>My-Company.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Our Culture</PageTitle>
		  <PageUrl>Our-Culture.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>History and Timeline</PageTitle>
		  <PageUrl>History-And-Timeline.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Sustainability</PageTitle>
		  <PageUrl>Sustainability.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>My Community</PageTitle>
		  <PageUrl>My-Community.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
  </Site>
  <Site>
    <SiteTitle>Our Customers</SiteTitle>
    <SiteUrl>/Our-Customers</SiteUrl>
		<Page IsHomePage="true">
		  <PageTitle>Our Customers</PageTitle>
		  <PageUrl>Our-Customers.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Customer Engagement</PageTitle>
		  <PageUrl>Customer-Engagement.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Employee Ambassadors</PageTitle>
		  <PageUrl>Employee-Ambassadors.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
  </Site>
  <Site>
    <SiteTitle>News and Info</SiteTitle>
    <SiteUrl>/News-And-Info</SiteUrl>
		<Page IsHomePage="false">
		  <PageTitle>Utility Performance</PageTitle>
		  <PageUrl>Utility-Performance.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>News Archive</PageTitle>
		  <PageUrl>News-Archive.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Calendar</PageTitle>
		  <PageUrl>Calendar.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Social Media</PageTitle>
		  <PageUrl>Social-Media.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
  </Site>
  <Site>
    <SiteTitle>Task Center</SiteTitle>
    <SiteUrl>/Task-Center</SiteUrl>
		<Page IsHomePage="true">
		  <PageTitle>Task Center</PageTitle>
		  <PageUrl>Task-Center.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Travel</PageTitle>
		  <PageUrl>Travel.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Toolbox</PageTitle>
		  <PageUrl>Toolbox.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Managing Employees</PageTitle>
		  <PageUrl>Managing-Employees.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
  </Site>
  <Site>
    <SiteTitle>Collaboration</SiteTitle>
    <SiteUrl>/Collaboration</SiteUrl>
		<Page IsHomePage="true">
		  <PageTitle>Collaboration</PageTitle>
		  <PageUrl>Collaboration.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Communities</PageTitle>
		  <PageUrl>Communities.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Employee Surveys</PageTitle>
		  <PageUrl>Employee-Surveys.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
  </Site>
</Sites>