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!
-Gary
“Stamping” PDF Files Downloaded from SharePoint 2010
First off I want to clarify that the subject of this post is not my idea as it is something that my friend Roman Kobzarev put together for his company and I merely assisted with getting the code to work. The problem that Roman was trying to solve was that his company provided numerous PDF files that registered/paying members could download and, unfortunately, they were finding some of those files being posted to various other sites without their permission; so in an attempt to at least discourage this they wanted to stamp the PDF files with some information about the user who downloaded the file.
There are various ways in which this problem can be solved but perhaps one of the simpler approaches, and the approach outlined here, was to create an HTTP Handler which intercepted requests for any PDF files and then simply retrieve the file from SharePoint, modify it, and then send it on its way. The cool thing about this approach and the pattern shown here is that it can easily be applied to any file type which requires some user or request specific modifications applied to it.
Before I get to the actual code I want to point out one third party dependency that we used: iTextSharp. This is an open source .NET library for PDF generation and manipulation. There are many options available when looking to manipulate PDF files and in this case this one was chosen due to its cost (free). So let’s get to the code.
In terms of code there really isn’t that much which is what makes this such a nice solution. The first piece is the actual implementation of the IHttpHandler interface:
using System.IO; using System.Web; using Microsoft.SharePoint; using iTextSharp.text; using iTextSharp.text.pdf; namespace Aptillon.SharePoint.PDFWatermark { public class PDFWatermarkHttpHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { SPFile file = SPContext.Current.Web.GetFile(context.Request.Url.ToString()); byte[] content = file.OpenBinary(); SPUser currentUser = SPContext.Current.Web.CurrentUser; string watermark = null; if (currentUser != null) watermark = "This download was specially prepared for " + currentUser.Name; if (watermark != null) { PdfReader pdfReader = new PdfReader(content); using (MemoryStream outputStream = new MemoryStream()) using (PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream)) { for (int pageIndex = 1; pageIndex <= pdfReader.NumberOfPages; pageIndex++) { //Rectangle class in iText represent geometric representation... //in this case, rectangle object would contain page geometry Rectangle pageRectangle = pdfReader.GetPageSizeWithRotation(pageIndex); //PdfContentByte object contains graphics and text content of page returned by PdfStamper PdfContentByte pdfData = pdfStamper.GetUnderContent(pageIndex); //create font size for watermark pdfData.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 8); //create new graphics state and assign opacity PdfGState graphicsState = new PdfGState(); graphicsState.FillOpacity = 0.4F; //set graphics state to PdfContentByte pdfData.SetGState(graphicsState); //indicates start of writing of text pdfData.BeginText(); //show text as per position and rotation pdfData.ShowTextAligned(Element.ALIGN_CENTER, watermark, pageRectangle.Width / 4, pageRectangle.Height / 44, 0); //call endText to invalid font set pdfData.EndText(); } pdfStamper.Close(); content = outputStream.ToArray(); } } context.Response.ContentType = "application/pdf"; context.Response.BinaryWrite(content); context.Response.End(); } public bool IsReusable { get { return false; } } } }
As you can see from the previous code listing, the bulk of the code involves the actual processing of the PDF file but the core SharePoint specific piece is in the beginning of the ProcessRequest() method where we use the SPContext.Current.Web.GetFile() method to retrieve the actual file requested and then, if we can get an actual SPUser object, we create a simple message that will be added to the bottom of the PDF. I’m not going to cover what’s happening with the iTextSharp objects as the point of this article is to demonstrate the pattern which can easily be applied to other file types and not how to use iTextSharp.
To deploy this class I created an empty SharePoint 2010 project using Visual Studio 2010 and added the file to the project. I then created a new Web Application scoped Feature which I use to add the appropriate web.config settings which will register the HTTP Handler. The following screenshot shows the final project structure:

Note that I also added the iTextSharp.dll to the project and added it as an additional assembly to the package by double clicking the Package.package element and then, in the package designer, click Advanced to add additional assemblies:

Before I show the code for the Web Application Feature I first want to show what settings I set for the Feature after adding it:

When you add a new Feature to a project it’s going to name it Feature1 and set the default scope to Web. The first thing I do is rename the Feature to something meaningful – in this case, because I know I’ll only have the one Feature I go ahead and name it the same as the project name: Aptillon.SharePoint.PDFWatermark (I always follow the same naming convention for my projects, which equate to WSP file names and Features: <Company>.SharePoint.<Something Appropriate for the Contained Functionality>). The next thing I do is change the Deployment Path property for the Feature so that it only uses the Feature name and does not prepend the project name; and finally I set the scope and title of the Feature. Now I’m ready to add my Feature activation event receiver.
The code that I want to include in the event receiver will handle the addition and removal of the web.config handler elements. I do this using the SPWebConfigModification class. Now there’s debate on whether this should be used or not; this is one of those classes where you might say (as my friend Spence Harbar puts it), “Just because you should use it doesn’t mean you can.” The simple explanation for this is that ideally you should be using this class to make web.config modifications but the reality is that this guy is fraught with issues and usually doesn’t work. That said, what I usually do is, where it makes sense, use this class to add and remove my entries but work under the premise that it will probably not work and plan on making these changes manually (or write a timer job which will do what this guy is attempting to do, but that’s out of scope of this article). So here’s the FeatureActivated() and FeatureDeactivating() methods that I use to add and remove the appropriate web.config entries which register the previously defined HTTP Handler:
public override void FeatureActivated(SPFeatureReceiverProperties properties) { string asmDetails = typeof(PDFWatermarkHttpHandler).AssemblyQualifiedName; SPWebApplication webApp = properties.Feature.Parent as SPWebApplication; if (webApp == null) return; SPWebConfigModification modification = new SPWebConfigModification("add[@name=\"PDFWatermark\"]", "configuration/system.webServer/handlers"); modification.Value = string.Format("<add name=\"PDFWatermark\" verb=\"*\" path=\"*.pdf\" type=\"{0}\" preCondition=\"integratedMode\" />", asmDetails); modification.Sequence = 1; modification.Owner = asmDetails; modification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode; webApp.WebConfigModifications.Add(modification); webApp.Update(); webApp.WebService.ApplyWebConfigModifications(); } public override void FeatureDeactivating(SPFeatureReceiverProperties properties) { string asmDetails = typeof(PDFWatermarkHttpHandler).AssemblyQualifiedName; SPWebApplication webApp = properties.Feature.Parent as SPWebApplication; if (webApp == null) return; List<SPWebConfigModification> configModsFound = new List<SPWebConfigModification>(); Collection<SPWebConfigModification> modsCollection = webApp.WebConfigModifications; for (int i = 0; i < modsCollection.Count; i++) { if (modsCollection[i].Owner == asmDetails) { configModsFound.Add(modsCollection[i]); } } if (configModsFound.Count > 0) { foreach (SPWebConfigModification mod in configModsFound) modsCollection.Remove(mod); webApp.Update(); webApp.WebService.ApplyWebConfigModifications(); } }
With all the code in place I can deploy to my Web Application and now any time a PDF is downloaded I’ll have a nice little message displayed on the bottom of each page. Again, the intent here is to show the simplicity of the pattern and approach – with a little imagination you can easily come up with lots of other uses for this (applying security or password protection to the PDF, adding an image watermark, removing pages based on registration status thus providing “sample” versions, prefilling form fields with user data, adding a version history page, etc.). And of course all this can also be applied to other file types such as the Office files or images (though image handling would take a little more logic to ignore images not coming from document libraries).
Resetting SharePoint 2010 Themes
UPDATE 8/20/2011: I’ve reworked this script and included it as part of my SharePoint 2010 cmdlet downloads. See “Resetting SharePoint 2010 Themes – Part 2, the Reset-SPTheme cmdlet” for details.
One of my current clients is a local school district here in Denver and we (Aptillon) have recently helped them release a new public facing site for the main district office as well as all the schools in the district. The district has chosen a somewhat fixed brand which has had full theming support added so that the individual schools can adjust the color scheme to match the school’s colors. The master page, page layouts, CSS files, and associated images were all deployed to the Farm using various Solution Packages (WSPs). This allows us to make corrections/additions to the brand related files and quickly deploy them to the Farm, thereby updating the district and school sites quite easily. The problem, however, is that the way theming works within SharePoint 2010 is that it makes a copy of all the CSS and image files and stores them in the /_catalogs/theme/Themed/{THEMEID} folder, as shown in the following figure:
Whenever you apply a theme it will copy all the necessary CSS and image files to a new folder in the Themed folder. This means that the site is no longer basing its look and feel off of the Feature deployed files. So if a school has gone in and customized their site to use themes then any updates that we push out to the style sheets and images will be ignored. So I needed a way to effectively “reset” the applied theme after we push out an update to our branding solution. By reset I mean preserve the various color and font settings but re-apply them against the Feature deployed files.
I did some digging with my favorite tool, Reflector, and found that the out of the box theme settings page just uses the Microsoft.SharePoint.Utilities.ThmxTheme class to manipulate the themes. So, after a little experimenting I ended up with some code which will regenerate the current theme using all the source files and the user provided theme settings:
#NOTE: Run in a seperate console instance each time otherwise the changes won't get applied function Reset-SPTheme([Microsoft.SharePoint.PowerShell.SPSitePipeBind]$spSite) { $site = $spSite.Read() try { # Store some variables for later use $tempFolderName = "TEMP" $themedFolderName = "$($site.ServerRelativeUrl)/_catalogs/theme/Themed" $themesUrlForWeb = [Microsoft.SharePoint.Utilities.ThmxTheme]::GetThemeUrlForWeb($site.RootWeb) Write-Host "Old Theme URL: $themesUrlForWeb" # Open the existing theme $webThmxTheme = [Microsoft.SharePoint.Utilities.ThmxTheme]::Open($site, $themesUrlForWeb) # Generate a new theme using the settings defined for the existing theme # (this will generate a temporary theme folder that we'll need to delete) $webThmxTheme.GenerateThemedStyles($true, $site.RootWeb, $tempFolderName) # Apply the newly generated theme to the root web [Microsoft.SharePoint.Utilities.ThmxTheme]::SetThemeUrlForWeb($site.RootWeb, "$themedFolderName/$tempFolderName/theme.thmx", $true) # Delete the TEMP folder created earlier $site.RootWeb.GetFolder("$themedFolderName/$tempFolderName").Delete() # Reset the theme URL just in case it has changed (sometimes it will) $site.Dispose() $site = $spSite.Read() $themesUrlForWeb = [Microsoft.SharePoint.Utilities.ThmxTheme]::GetThemeUrlForWeb($site.RootWeb) Write-Host "New Theme URL: $themesUrlForWeb" # Set all child webs to inherit. if ([Microsoft.SharePoint.Publishing.PublishingWeb]::IsPublishingWeb($site.RootWeb)) { $pubWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($site.RootWeb) $pubWeb.ThemedCssFolderUrl.SetValue($pubWeb.Web.ThemedCssFolderUrl, $true) } else { foreach ($web in $site.AllWebs) { if ($web.isRootWeb) { continue } Write-Host "Setting theme for $($web.ServerRelativeUrl)..." try { [Microsoft.SharePoint.Utilities.ThmxTheme]::SetThemeUrlForWeb($web, $themesUrlForWeb) } finally { $web.Dispose() } } } } finally { if ($site -ne $null) { $site.Dispose() } } }
I saved this to a file named Reset-SPTheme so I can then call the function like so:
. c:\Scripts\Reset-SPTheme.ps1 Reset-SPTheme "http://example.com/"
One odd thing I found, however, is that every time I run this it must be run in a new console instance; otherwise the changes are not picked up (this is basically a combination of a threading and caching issue within the code when executed from a PowerShell context). So remember, start a new PowerShell console every time you need to run this script (yeah, I wasted a couple of hours banging my head against the wall trying to figure that little nugget out).
BTW: I intend to add this to my cmdlet extensions as I believe it will be something I’ll need often so look for an updated build to come out this weekend.
SharePoint 2010 SP1 Public API Changes
I recently published a post detailing the SharePoint 2010 SP1 PowerShell changes and, in that post, I mentioned that I was probably going to detail the API changes. Well, here they are. Note that the list below is not a comprehensive one in that I’m not showing every assembly (I do have the changes for every assembly but frankly I just got tired of translating the results into a readable format so I kept it to the more prominent assemblies (or at least the ones that I just happened to have done at the time)). In reviewing the list you see that there’s honestly not a whole lot of noteworthy changes, but that’s okay as part of my reasoning for doing this was to discover whether there were any (don’t get me wrong, there are some, in fact, for me there’s 1 very big one that made this whole exercise worth it – I’ll let you figure out which one that is). If you find any I missed please add a comment so that others can see it as well.
- Microsoft.SharePoint.dll
- Microsoft.SharePoint.SPRecycleBinItemType
- New enum value:
- Web
- New enum value:
- Microsoft.SharePoint.SPWeb
- New method:
- public void Recycle()
- New method:
- Microsoft.SharePoint.Strings
- New constants:
- public const string CannotRecycleRootWeb
- public const string HealthRule_Explanation_BcsShimsAreEnabled
- public const string HealthRule_Remedy_BcsShimsAreEnabled
- public const string RecycleBinWebMissingContainerError
- public const string SPStorageMetricsProcessingJobDescription
- public const string SPUsageUserCodeRequestsDescription
- public const string SPUsageUserCodeRequestsMonitoredDataDescription
- public const string SiteAlreadyExists
- public const string StorageMetricsDBObjectsNotFound
- public const string StorageMetricsFreshnessWarning
- public const string StorageMetricsNotAvailable
- public const string TimerJobTitleStorageMetricsProcessing
- New constants:
- Microsoft.SharePoint.Administration.SPAce<T>
- New properties:
- public Byte[] BinaryId() { get; }
- public Microsoft.SharePoint.Administration.SPIdentifierType BinaryIdType() { get; }
- New properties:
- Microsoft.SharePoint.Administration.SPAcl<T>
- New method:
- public SPAce<T> Add(string principalName, string displayName, SPIdentifierType identifierType, byte[] identifier, T grantRightsMask, T denyRightsMask)
- New method:
- Microsoft.SharePoint.Administration.SPContentDatabase
- New methods:
- public Microsoft.SharePoint.Administration.SPDeletedSite GetDeletedSite(System.Guid id)
- public void Move(SPContentDatabase destinationDb, List<SPSite> sitesToMove, Dictionary<string, string> rbsProviderMap, out Dictionary<SPSite, string> failedSites)
- New methods:
- Microsoft.SharePoint.Administration.SPContentDatabaseCollection
- New method:
- public SPContentDatabase Add(string strDatabaseServer, string strDatabaseName, string strDatabaseUsername, string strDatabasePassword, int warningSiteCount, int maximumSiteCount, int status, bool flushChangeLog, bool changeSyncKnowledge)
- New method:
- Microsoft.SharePoint.Administration.SPDatabase
- New method:
- public void ChangeDatabaseInstance(string databaseServiceInstance)
- New method:
- Microsoft.SharePoint.Administration.SPIncomingEmailService
- New property:
- public int RetryDeliveryInterval { get; set; }
- New property:
- Microsoft.SharePoint.Administration.SPPolicy
- New method:
- protected Void OnDeserialization()
- New method:
- Microsoft.SharePoint.Administration.SPSiteLookupProvider
- Changed method (breaking change!)
- public Void RenameHostHeaderSite(Guid siteId, string newHostHeader) => public Void RenameHostHeaderSite(Guid siteId, Uri newHostHeaderSiteUri)
- Changed method (breaking change!)
- Microsoft.SharePoint.Administration.SPUsageApplication
- New property:
- public int UsageInsertionTimeOut { get; set; }
- New property:
- Microsoft.SharePoint.Administration.SPUserCodeExecutionTier
- New property:
- public int PriorityPerProcess { get; set; }
- New property:
- Microsoft.SharePoint.Administration.SPWebApplication
- New properties:
- public int StorageMetricsProcessingDuration { get; set; }
- public uint MaxDiscussionBoardItemsForSiteDataFolderQuery { get; set; }
- public uint? UserDefinedWorkflowMaximumComplexity { get; set; }
- New methods:
- public SPDeletedSiteCollection GetDeletedSites()
- public SPDeletedSiteCollection GetDeletedSites(SPDeletedSiteQuery query)
- public SPDeletedSiteCollection GetDeletedSites(Guid siteId)
- public SPDeletedSiteCollection GetDeletedSites(string sitePath)
- public void MigrateUsers(IMigrateUserCallback callback)
- New properties:
- Microsoft.SharePoint.Administration.SPWebService
- New properties:
- public int ImagingDownloadSizeLimit { get; set; }
- public bool EnableHostHeaderSiteBasedSchemeSelection { get; set; }
- New properties:
- Microsoft.SharePoint.Administration.Claims.SPActiveDirectoryClaimProvider
- New method:
- protected override void FillDefaultLocalizedDisplayName(CultureInfo culture, out string localizedName)
- New method:
- Microsoft.SharePoint.Administration.Claims.SPAllUserClaimProvider
- New method:
- protected override void FillDefaultLocalizedDisplayName(CultureInfo culture, out string localizedName)
- New method:
- Microsoft.SharePoint.Administration.Claims.SPClaimHierarchyProvider
- New methods:
- protected override void FillDefaultLocalizedDisplayName(CultureInfo culture, out string localizedName)
- public string GetLocalizedDisplayName()
- New methods:
- Microsoft.SharePoint.Administration.Claims.SPClaimProvider
- New property:
- public virtual bool SupportsUserKey { get; }
- New methods:
- protected override void FillDefaultLocalizedDisplayName(CultureInfo culture, out string localizedName)
- public string GetLocalizedDisplayName()
- public SPClaim UserKeyForEntity(SPClaim entity)
- public virtual string GetClaimTypeForUserKey()
- protected virtual SPClaim GetUserKeyForEntity(SPClaim entity)
- New property:
- Microsoft.SharePoint.Administration.Claims.SPClaimProviderDefinition
- New property:
- public bool IsVisible { get; set; }
- New property:
- Microsoft.SharePoint.Administration.Claims.SPClaimProviderOperationOptions
- New enum value:
- OverrideVisibleFlag
- New enum value:
- Microsoft.SharePoint.Administration.Claims.SPFormsClaimProvider
- New method:
- protected override void FillDefaultLocalizedDisplayName(CultureInfo culture, out string localizedName)
- New method:
- Microsoft.SharePoint.Administration.Claims.SPSystemClaimProvider
- New method:
- protected override void FillDefaultLocalizedDisplayName(CultureInfo culture, out string localizedName)
- New method:
- Microsoft.SharePoint.BusinessData.Administration.LobSystem
- New static method:
- public static LobSystem MergeXml(string xml, out string[] errors, PackageContents packageContents, AdministrationMetadataCatalog metadataCatalog, string settingId)
- New static method:
- Microsoft.SharePoint.BusinessData.Administration.TypeDescriptor
- New static method:
- public static TypeDescriptor MergeXml(string xml, out string[] errors, PackageContents packageContents, Parameter parameter, TypeDescriptor parent, string settingId)
- New static method:
- Microsoft.SharePoint.BusinessData.SharedService.BdcServiceApplicationProxy
- New methods:
- public bool IsSystemTypeEnabled(SystemType systemType)
- public void EnableSystemType(SystemType systemType, bool value)
- New methods:
- Microsoft.SharePoint.JSGrid.GridSerializer
- New method:
- public void ApplyPostViewIncrementalInsertsAndDeletes(IEnumerable
changes, Func
- public void ApplyPostViewIncrementalInsertsAndDeletes(IEnumerable
- New method:
- Microsoft.SharePoint.JSGrid.HierarchyNode
- New property:
- public HierarchyNode Parent { get; set; }
- New property:
- Microsoft.SharePoint.Utilities.SPUtility
- New static method:
- public static Stream ExecuteCellStorageBinaryRequest(SPFile spfile, Stream request, bool coalesce, ref Guid partitionID, string userName, bool coauthVersioning, string etagMatching, bool fExpectNoFileExists, string contentChangeUnit, string clientFileID, string bypassSchemaID, long nLockType, string lockID, long nTimeout, bool createParentFolder, out string etagReturn, out bool allRequestSucceeded, out int coalesceHRESULT, out string coalesceErrorMessage, out bool containHotboxData, out bool haveOnlyDemotionChanges, ref int binaryReqCountQuota)
- New static method:
- Microsoft.SharePoint.WebPartPages.ListFormWebPart
- New method:
- public bool ShouldSerializeTemplateName()
- New method:
- New classes:
- Microsoft.SharePoint.Administration.SPDeletedSite
- Microsoft.SharePoint.Administration.SPDeletedSiteCollection
- Microsoft.SharePoint.Administration.SPDeletedSiteLookupInfo
- Microsoft.SharePoint.Administration.SPDeletedSiteQuery
- Microsoft.SharePoint.Administration.SPUsageUserCodeRequests
- Microsoft.SharePoint.Administration.SPUsageUserCodeRequestsEntry
- Microsoft.SharePoint.Administration.SPUsageUserCodeRequestsMonitoredData
- Microsoft.SharePoint.Administration.SPUsageUserCodeRequestsMonitoredDataEntry
- Microsoft.SharePoint.Administration.Health.SPHealthAnalysisRuleInstance
- Microsoft.SharePoint.WebControls.IEVersionMetaTag
- New enum types:
- Microsoft.SharePoint.Administration.SPIdentifierType
- New interfaces:
- Microsoft.SharePoint.Administration.IMigrateUserCallback
- Microsoft.SharePoint.Administration.ISPSiteLookupProviderRecycleBin
- Microsoft.SharePoint.SPRecycleBinItemType
- Microsoft.SharePoint.Publishing.dll
- Microsoft.SharePoint.Publishing.Internal.CodeBehind
- New property:
- protected bool IsCurrentUserSiteAdmin { get; }
- New property:
- Microsoft.SharePoint.Publishing.WebControls.SpellCheckV4Action
- New method:
- protected bool ShouldRenderWithoutTabs()
- New method:
- Microsoft.SharePoint.Publishing.WebControls.EditingMenuActions.ConsoleAction
- New method:
- protected bool ShouldRenderWithoutTabs()
- New method:
- Microsoft.SharePoint.Publishing.Internal.CodeBehind
- Microsoft.SharePoint.Taxonomy.dll
- Microsoft.SharePoint.Taxonomy.TermStore
- New method:
- public Group GetSiteCollectionGroup(SPSite currentSite)
- New method:
- Microsoft.SharePoint.Taxonomy.TermStore
- Microsoft.SharePoint.Portal.dll
- Microsoft.Office.Server.UserProfiles.UserProfileService
- New methods:
- public void AddLeader(string accountName)
- public Leader[] GetLeaders()
- public void RemoveLeader(string accountName)
- New methods:
- Microsoft.Office.Server.UserProfiles.UserProfileService
- Microsoft.Office.Server.UserProfiles.dll
- Microsoft.Office.Server.SocialData.PluggableSocialSecurityTrimmerManager
- New methods:
- public static string[] GetUrlFoldersRequiringTrim(SPServiceContext serviceContext)
- public static string[] GetUrlFoldersToAlwaysAllow(SPServiceContext serviceContext)
- public static void SetTrimmerSettings(SPServiceContext serviceContext, bool enableTrimming)
- public static void SetTrimmerSettings(SPServiceContext serviceContext, string[] urlFoldersRequiringTrim, string[] urlFoldersToAlwaysAllow)
- New methods:
- Microsoft.Office.Server.UserProfiles.BusinessDataCatalogConnection
- New method:
- public void Delete()
- New method:
- Microsoft.Office.Server.UserProfiles.ConnectionManager
- New method:
- public DirectoryServiceConnection AddActiveDirectoryConnection(ConnectionType type, string displayName, string server, bool useSSL, string accountDomain, string accountUsername, SecureString accountPassword, List<DirectoryServiceNamingContext> namingContexts, string spsClaimProviderTypeValue, string spsClaimProviderIdValue, string adClaimIDMapAttribute)
- New method:
- Microsoft.Office.Server.UserProfiles.UserProfileManager
- New methods:
- public void AddLeader(string accountName)
- public Leader[] GetLeaders()
- public void RemoveLeader(string accountName)
- New methods:
- New classes:
- Microsoft.Office.Server.UserProfiles.Leader
- Microsoft.Office.Server.SocialData.PluggableSocialSecurityTrimmerManager
- Microsoft.Office.Server.Search.dll
- Microsoft.Office.Server.Search.Administration.CrawlTopologyState
- New enum values:
- ActiveToBeRemoved
- DeactivatingToBeRemoved
- New enum values:
- Microsoft.Office.Server.Search.Administration.SearchServiceApplication
- New property:
- public uint CrawlLogCleanupIntervalInDays { get; set; }
- New property:
- Microsoft.Office.Server.Search.Administration.SearchServiceApplicationProxy
- New property:
- public LocationConfigurationCollection LocationConfigurations { get; }
- New property:
- Microsoft.Office.Server.Search.Query.QueryInfo
- New property:
- public string CorrelationId { get; set; }
- New property:
- Microsoft.Office.Server.Search.Query.QueryManager
- New method:
- public System.Xml.XmlDocument GetResults()
- New method:
- Microsoft.Office.Server.Search.Administration.CrawlTopologyState
- Microsoft.SharePoint.PowerShell.dll
- New classes:
- Microsoft.SharePoint.PowerShell.SPDeletedSitePipeBind
- Microsoft.SharePoint.PowerShell.SPHealthAnalysisRuleInstancePipeBind
- New classes:
SharePoint Server 2010 Service Pack 1 PowerShell Changes
As most people know by now, Service Pack 1 for SharePoint 2010 was released to the public today. There’s already been a lot of hype over some of the new capabilities such as the site recycle bin and some folks have documented/demonstrated some of the new PowerShell cmdlets that are available to manage this new feature; but what about all the other new and changed PowerShell cmdlets – there’s a bunch! So, let’s take a look at what is new, and what has changed.
We’ll start with the new stuff – here’s a quick bulleted list of all the new cmdlets:
- Add-SPProfileLeader
- Get-SPProfileLeader
- Remove-SPProfileLeader
- Remove-SPProfileSyncConnection
- Add-SPProfileSyncConnection
- Disable-SPHealthAnalysisRule
- Enable-SPHealthAnalysisRule
- Get-SPHealthAnalysisRule
- Get-SPDeletedSite
- Remove-SPDeletedSite
- Restore-SPDeletedSite
- Move-SPSocialComments
I haven’t had a chance to try any of these out but I think there’s some cool new functionality here beyond just the site recycle bin. There’s absolutely no documentation for any of these but some of them are fairly straightforward based on the names. For instance, the Add-SPProfileSyncConnection cmdlet (and equivalent Remove cmdlet) are obviously for managing the synchronization connections for UPS. This was a big whole in RTM when it came to doing an end-to-end scripted installation as there was no practical way to add a synchronization connection using PowerShell. The health analysis rule cmdlets are also pretty obvious and, again, this goes a long way towards enabling administrators to script a deployment and enable or disable rules consistently across Farms.
I think the Move-SPSocialComments also has a lot of potential; if it does what I’m guessing it does then this could potentially solve the issue where comments and tags are stored with the absolute URL of the item that has been tagged/commented on – I’m *guessing* that running this command will effectively retarget those items, which is great in situations in which you’ve moved a list or site.
As for the *-SPProfileLeader cmdlets – I have no idea what those guys do so I’ll have to revisit them when I learn more. (The *-SPDeletedSite cmdlets have already been covered quite a bit by others so I’ll forgo any further discussion here).
Alright, so that’s the new stuff – what about the stuff that’s changed? Here’s a quick list with the changes:
- Mount-SPContentDatabase
- New Switch Parameter: ChangeSyncKnowledge (I’ve no idea what this does – it’s not yet documented)
- New-SPContentDatabase
- New Switch Parameter: ChangeSyncKnowledge (again, not yet documented)
- Move-SPSite
- New Parameter: RbsProviderMapping <Hashtable>
- From TechNet: “Used to move an RBS-enabled site collection from one RBS-enabled content database to another RBS-enabled content database without moving the underlying BLOB content. If the content database has more than one RBS provider associated with it, you must specify all providers. The same providers must be enabled on the target content database and the source content database.”
- New Parameter: RbsProviderMapping <Hashtable>
- New-SPPerformancePointServiceApplication
- New Parameter: AnalyticResultCacheMinimumHitCount <Int32> (not yet documented but I think it’s fairly obvious what it does)
- New Parameters: DatabaseServer <string>, DatabaseName <string>, DatabaseFailoverServer <string>, DatabaseSQLAuthenticationCredential <PSCredential>
- Can I get a hurray for this! This was the only Service Application that didn’t allow us to set the database information when we created it so we were left with this nasty GUID in the name. Hurray! We can finally get rid of the last database GUID! Woohoo!
- Set-SPPerformancePointServiceApplication
- New Parameter: AnalyticResultCacheMinimumHitCount <Int32> (not yet documented but I think it’s fairly obvious what it does)
- New Parameters: DatabaseServer <string>, DatabaseName <string>, DatabaseFailoverServer <string>, DatabaseSQLAuthenticationCredential <PSCredential>, DatabaseUseWindowsAuthentication
- Remove-SPWeb
- New Switch Parameter: Recycle
- That’s right, you can in fact cause an SPWeb to go to the new recycle bin by simply providing this switch parameter.
- New Switch Parameter: Recycle
- Update-SPProfilePhotoStore (I think this one is a bit of mess and may need a CU or two but I could just be reading the code wrong – it is kind of late right now)
- Update 6/29/2011: From Spence Harbar: “Update-SPProfilePhotoStore change is to address common bug/issue with resize and is for upgrade scenarios”
- New Switch Parameter: CreateThumbnailsForImportedPhotos
- I’m not entirely sure what this is supposed to do as thumbnails were created previously and will be created without this; however, I should note that they coded this wrong so both of the following syntaxes have the same affect as they are simply checking that the bool? type has a value and not what the value is:
- -CreateThumbnailsForImportedPhotos $true
- -CreateThumbnailsForImportedPhotos $false
- I’m not entirely sure what this is supposed to do as thumbnails were created previously and will be created without this; however, I should note that they coded this wrong so both of the following syntaxes have the same affect as they are simply checking that the bool? type has a value and not what the value is:
- New Switch Parameter: NoDelete
- I’m not 100% on this but I believe that the original behavior of this cmdlet was to copy the image and not actually move it (despite the name); they appear to have changed the behavior to delete the original images after the copy but you can preserve the original behavior by simply adding this switch parameter. However, this is *only* true when the CreateThumbnailsForImportedPhotos parameter is provided (in my opinion this is a bug – it should be irrelevant if that parameter is provided).
Well, that’s all I’ve been able to discover with the core SharePoint Server 2010 cmdlets – I may update this post to account for the Office Web Applications but I don’t currently have that installed on the server in which I just installed SP1 so it may take me a bit to do that analysis. At some point I may write something up to inspect the public classes and their members and do a similar post for the developers out there who want to know what API changes have occurred so keep an eye out for that.
So I think it’s pretty cool that we’ve got some improvements in the PowerShell cmdlets, especially in some of those that have frustrated me when it comes to automated deployments; the real frustrating thing, however, is that some of my just released book content is already out of date! Ugh! Maybe there’ll be a second edition ![]()
Happy PowerShelling!
-Gary