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

22Dec/1112

Updating SharePoint 2010 User Information

One of my clients recently had an issue where a particularly high profile user (CEO) had their title spelled incorrectly in Active Directory; unfortunately the error wasn’t noticed right away and now, despite changing the information in Active Directory, SharePoint was still showing the wrong title in the People Picker when granting the user rights to a Site Collection. Fortunately I had a partial PowerShell script to fix the issue and just needed to only slightly modify it – you can see the original script on pages 299 and 300 of my book. So before I show the modified script it’s first important to understand the problem and why I needed to use a script and why what I had in the book is somewhat incomplete.

Whenever you grant a user rights to a Site Collection or when that user creates/updates/deletes any item within a Site Collection, an entry for the user will be added to a hidden user information list, if not already there. This “User Information List” is located at http://<SiteCollectionUrl>/_catalogs/users/detail.aspx:

SNAGHTMLa064e71

By looking at this list you can see that several key pieces of information are stored here – unfortunately, when you change this information in Active Directory the information stored here is not updated (even after running a full or incremental import via UPS). To complicate matters there is no way to edit the information via the browser, thus the need for a PowerShell script. If you click the user’s name you’ll see the additional properties, including an “Edit Item” option, however, the edit dialog is simply a read-only display of the username, helpful right?:

SNAGHTMLa089b49

So let’s first consider the scenario that my book addresses and assume that a user had had their name and/or email address changed. To accommodate this scenario we simply use the Set-SPUser cmdlet along with the -SyncFromAD parameter. The following script is taken directly from my book and simply iterates through all Site Collections and calls the Set-SPUser cmdlet for the provided user:

function Sync-SPUser([string]$userName) {
  Get-SPSite -Limit All | foreach {
    $web = $_.RootWeb
    if ($_.WebApplication.UseClaimsAuthentication) {
      $claim = New-SPClaimsPrincipal $userName -IdentityType WindowsSamAccountName
      $user = $web | Get-SPUser -Identity $claim -ErrorAction SilentlyContinue
    } else {
      $user = $web | Get-SPUser -Identity $userName -ErrorAction SilentlyContinue
    }
    if ($user -ne $null) {
      $web | Set-SPUser -Identity $user -SyncFromAD
    }
    $web.Dispose()
    $_.Dispose()
  }
}

 

Before I make any changes to demonstrate this script and the modifications we’ll make to it, let’s first see how my user is currently set in the Site Collection:

image

And as shown in the People Picker:

SNAGHTMLa14e91b

Note the “Name”/”Display Name”, “Work e-mail”/”E-Mail”, and “Title” fields.

Now I’ll change these values in Active Directory (make the “p” in my last name capitalized, change the title, and set the email) and then run the script (I saved the script as Sync-SPUser.ps1):

SNAGHTMLa17239b

(Note that lowercase “p” is the correct spelling for my name, just in case you were wondering Smile). Now if we look at the user details in the Site Collection and the People Picker we should see the following:

image

SNAGHTMLa1a344d

Notice that the the “Name” / “Display Name” and “Work e-mail” / “E-Mail” fields were updated but not the “Title” field. This is because the Set-SPUser cmdlet and -SyncFromAD parameter only updates these two fields. So how do you update the remaining fields? We simply need to add some code to our function which will grab the SPListItem corresponding to the user from the hidden “User Information List” and then update the corresponding fields manually. The following modified script does this for the “Title” field (note that I’ve changed the function signature to take the title in as a parameter):

function Sync-SPUser([string]$userName, [string]$title) {
  Get-SPSite -Limit All | foreach {
    $web = $_.RootWeb
    if ($_.WebApplication.UseClaimsAuthentication) {
      $claim = New-SPClaimsPrincipal $userName -IdentityType WindowsSamAccountName
      $user = $web | Get-SPUser -Identity $claim -ErrorAction SilentlyContinue
    } else {
      $user = $web | Get-SPUser -Identity $userName -ErrorAction SilentlyContinue
    }
    if ($user -ne $null) {
      $web | Set-SPUser -Identity $user -SyncFromAD
      
      $list = $web.Lists["User Information List"]
      $query = New-Object Microsoft.SharePoint.SPQuery
      $query.Query = "<Where><Eq><FieldRef Name='Name' /><Value Type='Text'>$userName</Value></Eq></Where>"
      foreach ($item in $list.GetItems($query)) {
        $item["JobTitle"] = $title
        $item.SystemUpdate()
      }
    }
    $web.Dispose()
    $_.Dispose()
  }
}

The changes to the original function have been highlighted. Note that the internal field name for the “Title” field is “JobTitle” and that is what we are using to set the Title. Now if we run this modified script we should see the Title field updated:

SNAGHTMLa21bc70

SNAGHTMLa236af7

Okay, so what about the other fields (Department, Mobile Number, etc.)? You can see what fields are available to edit by running the following:

SNAGHTMLa265249

In the preceding example I’m grabbing a specific item (in this case the item corresponding to my user) so that I can see the internal field names in context with the data stored by the field – this helps to make sure that I grab the correct field name (i.e., “JobTitle” vs. “Title”). Now you can just add additional fields to update right before the call to SystemUpdate() – simply follow the pattern established for the title field.

So, add this guy to your script library and you’ll be good to go next time someone changes their name, email, or job title.

-Gary

19Nov/110

SharePoint Saturday Denver 2011 Slide Decks

Last weekend I had a great time at SharePoint Friday/Saturday Denver 2011 – all the folks who helped organize the event did a fantastic job (and I have to say, it was nice this year not being one of the organizers as I was able to just enjoy the event for once which makes me appreciate their efforts even more). So, at the event I presented two talks, one on PowerShell (of course) and the other was the presentation I gave at the SharePoint Conference in Anaheim last month. The PowerShell talk was a new talk that I’d never done before and it was basically just a bunch of random tips that I’ve found useful over the years. My apologies to those who attended my sessions last weekend for not making these available sooner but I figure better late than never. Anyways, here’s the links to the decks – enjoy!

20Aug/113

Resetting SharePoint 2010 Themes – Part 2, the Reset-SPTheme cmdlet

Yesterday I threw up a quick post showing how to reset a SharePoint 2010 theme using a reasonably simple Windows PowerShell script. In that post I promised that I’d convert the script to a cmdlet and make it part of my downloadable extensions. Well, as promised I’ve updated my extensions so that they now include a Reset-SPTheme cmdlet. I added on minor enhancement over the previously shown script in that I allow you to pass in either an SPSite or an SPWeb object and by default it will not force all child webs to inherit from the relevant SPWeb object. This way, if you have a child Site with it’s own theme it won’t wipe out that theme. If you have multiple Sites with a custom theme setting within a Site Collection then you’ll want to provide the -Site parameter and pass in an SPSite reference – this will result in all Sites with custom themes within the Site Collection to be reset. If you only wish to reset a single Site then use the -Web parameter and pass in a SPWeb reference.

Here’s the full help for the Reset-SPTheme cmdlet:

NAME
    Reset-SPTheme

SYNOPSIS
    Resets a theme by applying all user specified theme configuration settings to the original source files. This is particularly helpful when the original source files have changed to a Feature upgrade.

SYNTAX
    Reset-SPTheme [-Web] <SPWebPipeBind> [-SetSubWebsToInherit <SwitchParameter>] [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]

    Reset-SPTheme [-Site] <SPSitePipeBind> [-SetSubWebsToInherit <SwitchParameter>] [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]

DESCRIPTION
    Resets a theme by applying all user specified theme configuration settings to the original source files. This is particularly helpful when the original source files have changed to a Feature upgrade.

    Copyright 2011 Falchion Consulting, LLC
    > For more information on this cmdlet and others:
    >
http://blog.falchionconsulting.com/
    > Use of this cmdlet is at your own risk.
    > Gary Lapointe assumes no liability.

PARAMETERS
    -Web <SPWebPipeBind>
        Specifies the URL or GUID of the Web containing the theme to reset.

        The type must be a valid GUID, in the form 12345678-90ab-cdef-1234-567890bcdefgh; a valid name of Microsoft SharePoint Foundation 2010 Web site (for example, MySPSite1); or an instance of a valid SPWeb object.

        Required?                    true
        Position?                    1
        Default value
        Accept pipeline input?       true (ByValue, ByPropertyName)
        Accept wildcard characters?  false

    -Site <SPSitePipeBind>
        The site containing the theme to reset.

        The type must be a valid GUID, in the form 12345678-90ab-cdef-1234-567890bcdefgh; a valid URL, in the form http://server_name; or an instance of a valid SPSite object.

        Required?                    true
        Position?                    1
        Default value
        Accept pipeline input?       true (ByValue, ByPropertyName)
        Accept wildcard characters?  false

    -SetSubWebsToInherit [<SwitchParameter>]
        If specified, all child webs will be reset to inherit the theme of the specified web or root web.

        Required?                    false
        Position?                    named
        Default value
        Accept pipeline input?       false
        Accept wildcard characters?  false

    -AssignmentCollection [<SPAssignmentCollection>]
        Manages objects for the purpose of proper disposal. Use of objects, such as SPWeb or SPSite, can use large amounts of memory and use of these objects in Windows PowerShell scripts requires proper memory management. Using the SPAssignment object, you can assign objects to a variable and dispose of the objects after they are needed to free up memory. When SPWeb, SPSite, or SPSiteAdministration objects are used, the objects are automatically disposed of if an assignment collection or the Global parameter is not used.

        When the Global parameter is used, all objects are contained in the global store. If objects are not immediately used, or disposed of by using the Stop-SPAssignment command, an out-of-memory scenario can occur.

        Required?                    false
        Position?                    named
        Default value
        Accept pipeline input?       true (ByValue)
        Accept wildcard characters?  false

    <CommonParameters>
        This cmdlet supports the common parameters: Verbose, Debug,
        ErrorAction, ErrorVariable, WarningAction, WarningVariable,
        OutBuffer and OutVariable. For more information, type,
        "get-help about_commonparameters".

INPUTS

OUTPUTS

NOTES

        For more information, type "Get-Help Reset-SPTheme -detailed". For technical information, type "Get-Help Reset-SPTheme -full".

    ------------------EXAMPLE 1-----------------------

    PS C:\> Get-SPSite http://server_name | Reset-SPTheme -SetSubWebsToInherit

    This example resets the theme for the site collection http://server_name and resets all child webs to inherit from the root web.

    ------------------EXAMPLE 2-----------------------

    PS C:\> Get-SPWeb http://server_name/sub-web | Reset-SPTheme

    This example resets the theme for the web http://server_name/sub-web.

RELATED LINKS
    Get-SPWeb
    Get-SPSite

 

In the following example I’m resetting the theme(s) for an entire Site Collection. If one any child Sites within the Site Collection have a custom theme then they’ll be updated, not just the root (inheritance will not be changed):

PS C:\> Reset-SPTheme -Site http://example.com

In this next example I’m resetting all child Sites to inherit whatever theme has been specified for the root Site and I’m updating the root Site’s theme with changes to the source files:

PS C:\> Reset-SPTheme -Site http://example.com -SetSubWebsToInherit

For this last example I’m resetting the theme of a specific sub-Site:

PS C:\> Reset-SPTheme -Web http://example.com

As you can see, this is pretty easy to use and, if you’re deploying your branding via Features and you have theme support then a cmdlet like this can be quite critical when you need to push out updates to that brand.

19Aug/112

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:

ThemedFolder

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.

7Jul/112

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
    • Microsoft.SharePoint.SPWeb
      • New method:
        • public void Recycle()
    • 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
    • Microsoft.SharePoint.Administration.SPAce<T>
      • New properties:
        • public Byte[] BinaryId() { get; }
        • public Microsoft.SharePoint.Administration.SPIdentifierType BinaryIdType() { get; }
    • Microsoft.SharePoint.Administration.SPAcl<T>
      • New method:
        • public SPAce<T> Add(string principalName, string displayName, SPIdentifierType identifierType, byte[] identifier, T grantRightsMask, T denyRightsMask)
    • 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)
    • 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)
    • Microsoft.SharePoint.Administration.SPDatabase
      • New method:
        • public void ChangeDatabaseInstance(string databaseServiceInstance)
    • Microsoft.SharePoint.Administration.SPIncomingEmailService
      • New property:
        • public int RetryDeliveryInterval { get; set; }
    • Microsoft.SharePoint.Administration.SPPolicy
      • New method:
        • protected Void OnDeserialization()
    • Microsoft.SharePoint.Administration.SPSiteLookupProvider
      • Changed method (breaking change!)
        • public Void RenameHostHeaderSite(Guid siteId, string newHostHeader) => public Void RenameHostHeaderSite(Guid siteId, Uri newHostHeaderSiteUri)
    • Microsoft.SharePoint.Administration.SPUsageApplication
      • New property:
        • public int UsageInsertionTimeOut { get; set; }
    • Microsoft.SharePoint.Administration.SPUserCodeExecutionTier
      • New property:
        • public int PriorityPerProcess { get; set; }
    • 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)
    • Microsoft.SharePoint.Administration.SPWebService
      • New properties:
        • public int ImagingDownloadSizeLimit { get; set; }
        • public bool EnableHostHeaderSiteBasedSchemeSelection { get; set; }
    • Microsoft.SharePoint.Administration.Claims.SPActiveDirectoryClaimProvider
      • New method:
        • protected override void FillDefaultLocalizedDisplayName(CultureInfo culture, out string localizedName)
    • Microsoft.SharePoint.Administration.Claims.SPAllUserClaimProvider
      • New method:
        • protected override void FillDefaultLocalizedDisplayName(CultureInfo culture, out string localizedName)
    • Microsoft.SharePoint.Administration.Claims.SPClaimHierarchyProvider
      • New methods:
        • protected override void FillDefaultLocalizedDisplayName(CultureInfo culture, out string localizedName)
        • public string GetLocalizedDisplayName()
    • 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)
    • Microsoft.SharePoint.Administration.Claims.SPClaimProviderDefinition
      • New property:
        • public bool IsVisible { get; set; }
    • Microsoft.SharePoint.Administration.Claims.SPClaimProviderOperationOptions
      • New enum value:
        • OverrideVisibleFlag
    • Microsoft.SharePoint.Administration.Claims.SPFormsClaimProvider
      • New method:
        • protected override void FillDefaultLocalizedDisplayName(CultureInfo culture, out string localizedName)
    • Microsoft.SharePoint.Administration.Claims.SPSystemClaimProvider
      • New method:
        • protected override void FillDefaultLocalizedDisplayName(CultureInfo culture, out string localizedName)
    • Microsoft.SharePoint.BusinessData.Administration.LobSystem
      • New static method:
        • public static LobSystem MergeXml(string xml, out string[] errors, PackageContents packageContents, AdministrationMetadataCatalog metadataCatalog, string settingId)
    • 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)
    • Microsoft.SharePoint.BusinessData.SharedService.BdcServiceApplicationProxy
      • New methods:
        • public bool IsSystemTypeEnabled(SystemType systemType)
        • public void EnableSystemType(SystemType systemType, bool value)
    • Microsoft.SharePoint.JSGrid.GridSerializer
      • New method:
        • public void ApplyPostViewIncrementalInsertsAndDeletes(IEnumerable changes, Func> fnGetDefaultValuesForPostViewInserts)
    • Microsoft.SharePoint.JSGrid.HierarchyNode
      • New property:
        • public HierarchyNode Parent { get; set; }
    • 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)
    • Microsoft.SharePoint.WebPartPages.ListFormWebPart
      • New method:
        • public bool ShouldSerializeTemplateName()
    • 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.Publishing.dll
    • Microsoft.SharePoint.Publishing.Internal.CodeBehind
      • New property:
        • protected bool IsCurrentUserSiteAdmin { get; }
    • Microsoft.SharePoint.Publishing.WebControls.SpellCheckV4Action
      • New method:
        • protected bool ShouldRenderWithoutTabs()
    • Microsoft.SharePoint.Publishing.WebControls.EditingMenuActions.ConsoleAction
      • New method:
        • protected bool ShouldRenderWithoutTabs()
  • Microsoft.SharePoint.Taxonomy.dll
    • Microsoft.SharePoint.Taxonomy.TermStore
      • New method:
        • public Group GetSiteCollectionGroup(SPSite currentSite)
  • Microsoft.SharePoint.Portal.dll
    • Microsoft.Office.Server.UserProfiles.UserProfileService
      • New methods:
        • public void AddLeader(string accountName)
        • public Leader[] GetLeaders()
        • public void RemoveLeader(string accountName)
  • 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)
    • Microsoft.Office.Server.UserProfiles.BusinessDataCatalogConnection
      • New method:
        • public void Delete()
    • 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)
    • Microsoft.Office.Server.UserProfiles.UserProfileManager
      • New methods:
        • public void AddLeader(string accountName)
        • public Leader[] GetLeaders()
        • public void RemoveLeader(string accountName)
    • New classes:
      • Microsoft.Office.Server.UserProfiles.Leader
  • Microsoft.Office.Server.Search.dll
    • Microsoft.Office.Server.Search.Administration.CrawlTopologyState
      • New enum values:
        • ActiveToBeRemoved
        • DeactivatingToBeRemoved
    • Microsoft.Office.Server.Search.Administration.SearchServiceApplication
      • New property:
        • public uint CrawlLogCleanupIntervalInDays { get; set; }
    • Microsoft.Office.Server.Search.Administration.SearchServiceApplicationProxy
      • New property:
        • public LocationConfigurationCollection LocationConfigurations { get; }
    • Microsoft.Office.Server.Search.Query.QueryInfo
      • New property:
        • public string CorrelationId { get; set; }
    • Microsoft.Office.Server.Search.Query.QueryManager
      • New method:
        • public System.Xml.XmlDocument GetResults()
  • Microsoft.SharePoint.PowerShell.dll
    • New classes:
      • Microsoft.SharePoint.PowerShell.SPDeletedSitePipeBind
      • Microsoft.SharePoint.PowerShell.SPHealthAnalysisRuleInstancePipeBind
28Jun/110

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-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.
  • 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
    • 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 Smile

Happy PowerShelling!

-Gary

26Jun/112

Getting (and taking ownership of) Checked Out Files using Windows PowerShell

Often when I’m working on a project I need to generate a list of all checked out files and provide that to my client just prior to release to production. Sometimes the client will manually inspect each of them and act as they see fit and other times they’ll ask me to just batch publish all of them (for which I use my Publish-SPListItems cmdlet). So, how do I generate the report for the client? It’s actually pretty easy using PowerShell and a couple of quick loops. Here’s an example that loops through every Site Collection in the Farm and generates a nice report:

function Get-CheckedOutFiles() {
    foreach ($web in (Get-SPSite -Limit All | Get-SPWeb -Limit All)) {
        Write-Host "Processing Web: $($web.Url)..."
        foreach ($list in ($web.Lists | ? {$_ -is [Microsoft.SharePoint.SPDocumentLibrary]})) {
            Write-Host "`tProcessing List: $($list.RootFolder.ServerRelativeUrl)..."
            foreach ($item in $list.CheckedOutFiles) {
                if (!$item.Url.EndsWith(".aspx")) { continue }
                $hash = @{
                    "URL"=$web.Site.MakeFullUrl("$($web.ServerRelativeUrl.TrimEnd('/'))/$($item.Url)");
                    "CheckedOutBy"=$item.CheckedOutBy;
                    "CheckedOutByEmail"=$item.CheckedOutByEmail
                }
                New-Object PSObject -Property $hash
            }
            foreach ($item in $list.Items) {
                if ($item.File.CheckOutStatus -ne "None") {
                    if (($list.CheckedOutFiles | where {$_.ListItemId -eq $item.ID}) -ne $null) { continue }
                    $hash = @{
                        "URL"=$web.Site.MakeFullUrl("$($web.ServerRelativeUrl.TrimEnd('/'))/$($item.Url)");
                        "CheckedOutBy"=$item.File.CheckedOutByUser;
                        "CheckedOutByEmail"=$item.File.CheckedOutByUser.Email
                    }
                    New-Object PSObject -Property $hash
                }
            }
        }
        $web.Dispose()
    }
}
Get-CheckedOutFiles | Out-GridView

Running the above will generate a fairly nice report with URLs and usernames and whatnot; you could also use the Export-Csv cmdlet to dump the results to a CSV file that you can then hand off to your end-users. One cool thing to point out about this is that it will also show you files that you normally can’t see – that is files that have been created by other users but have never had a check in. This is actually pretty cool and I stumbled upon this when trying to fine tune my Publish-SPListItems cmdlet. You see, if the file has never been checked in then iterating through the SPListItemCollection object will not reveal the item (or file I should say); this meant that my cmdlet, as it was previously written, was missing a bunch of files. So to work around this all I had to do was add an additional loop to iterate over the collection returned by the SPDocumentLibrary’s CheckedOutFiles property. For each SPCheckedOutFile object in that collection I then call TakeOverCheckOut() to grab the checked out file so that I can then publish.

I use this enough that I decided to turn it into a cmdlet that is now part of my custom extensions. Like the above script, I return back a custom object that contains the full URLs and other  useful information (such as the List, Site, and Site Collection identifiers). I also exposed a TakeOverCheckOut() and Delete() method which simply calls Microsoft’s implementation of those methods.

I called this cmdlet Get-SPCheckedOutFiles (note that I’d previously released this cmdlet under the name Get-SPFilesCheckedOut but have since reworked and renamed that original implementation).

Here’s the full help for the cmdlet:

PS C:\Users\spadmin> help Get-SPCheckedOutFiles -full

NAME
Get-SPCheckedOutFiles

SYNOPSIS
Retrieves check out details for a given List, Web, or Site.

SYNTAX
Get-SPCheckedOutFiles [-Site] <SPSitePipeBind> [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]

Get-SPCheckedOutFiles [-Web] <SPWebPipeBind> [-ExcludeChildWebs <SwitchParameter>] [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]

Get-SPCheckedOutFiles [[-Web] <SPWebPipeBind>] [-List] <SPListPipeBind> [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]


DESCRIPTION
Retrieves check out details for a given List, Web, or Site.

Copyright 2010 Falchion Consulting, LLC
> For more information on this cmdlet and others:
>
http://blog.falchionconsulting.com/
> Use of this cmdlet is at your own risk.
> Gary Lapointe assumes no liability.

PARAMETERS
-Site <SPSitePipeBind>
Specifies the URL or GUID of the Site to inspect.

The type must be a valid GUID, in the form 12345678-90ab-cdef-1234-567890bcdefgh; a valid URL, in the form
http://server_name; or an instance of a valid SPSite object.

Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false

-Web <SPWebPipeBind>
Specifies the URL or GUID of the Web to inspect.

The type must be a valid GUID, in the form 12345678-90ab-cdef-1234-567890bcdefgh; a valid URL, in the form
http://server_name; or an instance of a valid SPWeb object.

Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false

-List <SPListPipeBind>
The list whose checked out files are to be returned.

The value must be a valid URL in the form
http://server_name/lists/listname or /lists/listname. If a server relative URL is provided then the Web parameter must be provided.

Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false

-ExcludeChildWebs [<SwitchParameter>]
Excludes all child sites and only considers the specified site.

Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false

-AssignmentCollection [<SPAssignmentCollection>]
Manages objects for the purpose of proper disposal. Use of objects, such as SPWeb or SPSite, can use large amounts of memory and use of these objects in Windows PowerShell scripts requires proper memory management. Using the SPAssignment object, you can assign objects to a variable and dispose of the objects after they are needed to free up memory. When SPWeb, SPSite, or SPSiteAdministration objects are used, the objects are automatically disposed of if an assignment collection or the Global parameter is not used.

When the Global parameter is used, all objects are contained in the global store. If objects are not immediately used, or disposed of by using the Stop-SPAssignment command, an out-of-memory scenario can occur.

Required? false
Position? named
Default value
Accept pipeline input? true (ByValue)
Accept wildcard characters? false

<CommonParameters>
This cmdlet supports the common parameters: Verbose, Debug, ErrorAction, ErrorVariable, WarningAction, WarningVariable, OutBuffer and OutVariable. For more information, type, "get-help about_commonparameters".

INPUTS

OUTPUTS

NOTES

For more information, type "Get-Help Get-SPCheckedOutFiles -detailed". For technical information, type "Get-Help Get-SPCheckedOutFiles -full".

------------------EXAMPLE------------------

PS C:\> Get-SPCheckedOutFiles -Site "
http://server_name/"


This example outputs a list of files that are checked out for the given Site Collection


RELATED LINKS
Get-SPFile

 

In the following example I’m retrieving pages from the root Pages library that are checked out:

image

In this example I am running the cmdlet as the aptillon\spadmin user and I’m now able to see the checkout by the user aptillon\glapointe. I ran the cmdlet twice so you could see the default tabular view as well as the more detailed view. Again, you could easily use the Export-Csv cmdlet to dump this information to a file that you can provide your end-users.

I hope you find this cmdlet useful – it personally has proven invaluable to me, particularly when working on anonymous access internet sites as end-users are notorious about creating pages and not getting them checked in.

P.S. With this release the Publish-SPListItems cmdlet has been updated to now consider files that don’t have any existing check-ins.

25Jun/1125

Programmatically Setting SharePoint 2010 Calendar Overlays

I recently did a project where my client needed several calendars provisioned via a Feature Receiver when a particular type of Site Collection was created; they had one primary calendar and they wanted all the other calendars to be overlaid onto the primary one using SharePoint 2010’s Calendar overlay capabilities.

Here’s a quick summary of this feature if you’re not familiar with it. When you are looking at a calendar you should notice that there is a ribbon button titled “Calendar Overlay”:

image

Clicking this button brings you to the Calendar Overlay Settings page; from this page you can add or edit the overlay calendars. Clicking “New Calendar” brings you to an application page where you can define what calendar to overlay:

image

As you can see from the above screenshot, you can add not just a SharePoint calendar as an overlay but also an Exchange calendar. After configuring calendar overlays you will see overlaid items when looking at the month view for the calendar:

SNAGHTML16503622

In this example, the pink item is coming from the overlay calendar. Overlay items are added dynamically after the page loads (some JavaScript and Ajax take care of loading the items and rendering them on the page).

So that’s the basics from the end-users perspective. Now what about the technical details? Well, there’s not a lot of information out there that describes how this is done but here’s the gist of it – there’s a simple XML structure that is stored in the SPView’s CalendarSettings property; this property defines the overlays. Once you know that the rest is just a matter of figuring out what that structure looks like. The easiest way to start is to simply go through the browser and set up one or two overlays and then use some simple PowerShell to dump out that XML:

SNAGHTML16554e82[4]

Here’s a better view of what that XML looks like:

<AggregationCalendars>
<AggregationCalendar Id="{26ddb82c-9e2b-4c5d-9b7e-4ee25cf5c357}"
Type="SharePoint"
Name="My Overlay Calendar"
Description=""
Color="5"
AlwaysShow="False"
CalendarUrl="/Lists/MyOverlayCalendar/calendar.aspx">
<Settings WebUrl="http://demo"
ListId="{428bd2cb-a32d-4867-b658-6498158636a8}"
ViewId="{09928cd4-9a5e-44ed-9bf2-dfe1fc85661b}"
ListFormUrl="/Lists/MyOverlayCalendar/DispForm.aspx" />
</AggregationCalendar>
</AggregationCalendars>

I want to call particular attention to the WebUrl attribute of the Settings element; this value *must* be the full URL of the SPWeb object that contains the overlay calendar list. Okay, you’re thinking, not a huge deal, SharePoint stores the full URL for lots of things and it doesn’t really pose issues right? WRONG! Think about a scenario where you have an extended web application. So in my example I have an authoring site located at http://demo and I’ve extended this site for anonymous access under the URL http://demo.aptillon.com. Due to what I consider a design flaw with the overlays, the overlay feature will only work when the web application you are accessing the site as matches the web application defined for the WebUrl attribute. So if I were to try and access my overlay using the anonymous site I’d get the following error:

image

And of course, due to this error, the overlays will not show up. So even if I’ve only changed the protocol (http to https) I’d still get this same error. This means that, effectively, calendar overlays using SharePoint lists will only work under the context of the Web Application (and protocol) from which the overlay was defined. (I’ve torn through the code that does this and it’s something that Microsoft should be very embarrassed about – very poor performance and just flat out horribly implemented. Okay, I digress, let’s get back to the details.

Another thing you’ll want to do to understand this XML structure is to look at the code that constructs it. There’s two places to look and both require Reflector or some equivalent disassembler; the first is the SerializeAccessors() method of the Microsoft.SharePoint.ApplicationPages.Calendar.CalendarAccessorManagerImpl class. This method takes the properties provided to it and constructs the XML structure shown above. So where are these properties set? For that we need to look at the BtnOk_Click() method of the Microsoft.SharePoint.ApplicationPages.AggregationCustomizePage class. I’m not going to show the details of these methods here but suffice it to say these methods have everything you need to understand this structure.

As I previously noted, for my particular client I needed to set several overlays within a Feature Activated event; to make this easier (because there was technically several places I had to do this) I created a simple method that I could call; this method took in my target list and the list I wanted to overlay as well as several other properties. For this post I’ve taken that code and created a modified version of it which supports adding Exchange-based calendars. Here’s that code:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml;
using Microsoft.SharePoint;

namespace Lapointe.SharePoint2010.Automation.Common.Lists
{
    public enum CalendarOverlayColor
    {
        LightYellow = 1,
        LightGreen = 2,
        Orange = 3,
        LightTurquise = 4,
        Pink = 5,
        LightBlue = 6,
        IceBlue1 = 7,
        IceBlue2 = 8,
        White = 9
    }

    public class SetListOverlay
    {
        public static void AddCalendarOverlay(SPList targetList, string viewName, string owaUrl, string exchangeUrl, string overlayName, string overlayDescription, CalendarOverlayColor color, bool alwaysShow, bool clearExisting)
        {
            AddCalendarOverlay(targetList, viewName, owaUrl, exchangeUrl, null, overlayName, overlayDescription, color, alwaysShow, clearExisting);
        }
        public static void AddCalendarOverlay(SPList targetList, string viewName, SPList overlayList, string overlayName, string overlayDescription, CalendarOverlayColor color, bool alwaysShow, bool clearExisting)
        {
            AddCalendarOverlay(targetList, viewName, null, null, overlayList, overlayName, overlayDescription, color, alwaysShow, clearExisting);
        }
        private static void AddCalendarOverlay(SPList targetList, string viewName, string owaUrl, string exchangeUrl, SPList overlayList, string overlayName, string overlayDescription, CalendarOverlayColor color, bool alwaysShow, bool clearExisting)
        {
            bool sharePoint = overlayList != null;
            string linkUrl = owaUrl;
            if (sharePoint)
                linkUrl = overlayList.DefaultViewUrl;

            SPView targetView = targetList.DefaultView;
            if (!string.IsNullOrEmpty(viewName))
                targetView = targetList.Views[viewName];

            XmlDocument xml = new XmlDocument();
            XmlElement aggregationElement = null;
            int count = 0;
            if (string.IsNullOrEmpty(targetView.CalendarSettings) || clearExisting)
            {
                xml.AppendChild(xml.CreateElement("AggregationCalendars"));
                aggregationElement = xml.CreateElement("AggregationCalendar");
                xml.DocumentElement.AppendChild(aggregationElement);
            }
            else
            {
                xml.LoadXml(targetView.CalendarSettings);
                XmlNodeList calendars = xml.SelectNodes("/AggregationCalendars/AggregationCalendar");
                if (calendars != null)
                    count = calendars.Count;
                aggregationElement = xml.SelectSingleNode(string.Format("/AggregationCalendars/AggregationCalendar[@CalendarUrl='{0}']", linkUrl)) as XmlElement;
                if (aggregationElement == null)
                {
                    if (count >= 10)
                        throw new SPException(string.Format("10 calendar ovarlays already exist for the calendar {0}.",targetList.RootFolder.ServerRelativeUrl));
                    aggregationElement = xml.CreateElement("AggregationCalendar");
                    xml.DocumentElement.AppendChild(aggregationElement);
                }
            }
            if (!aggregationElement.HasAttribute("Id"))
                aggregationElement.SetAttribute("Id", Guid.NewGuid().ToString("B", CultureInfo.InvariantCulture));

            aggregationElement.SetAttribute("Type", sharePoint ? "SharePoint" : "Exchange");
            aggregationElement.SetAttribute("Name", !string.IsNullOrEmpty(overlayName) ? overlayName : (overlayList == null ? "" : overlayList.Title));
            aggregationElement.SetAttribute("Description", !string.IsNullOrEmpty(overlayDescription) ? overlayDescription : (overlayList == null ? "" : overlayList.Description));
            aggregationElement.SetAttribute("Color", ((int)color).ToString());
            aggregationElement.SetAttribute("AlwaysShow", alwaysShow.ToString());
            aggregationElement.SetAttribute("CalendarUrl", linkUrl);

            XmlElement settingsElement = aggregationElement.SelectSingleNode("./Settings") as XmlElement;
            if (settingsElement == null)
            {
                settingsElement = xml.CreateElement("Settings");
                aggregationElement.AppendChild(settingsElement);
            }
            if (sharePoint)
            {
                settingsElement.SetAttribute("WebUrl", overlayList.ParentWeb.Site.MakeFullUrl(overlayList.ParentWebUrl));
                settingsElement.SetAttribute("ListId", overlayList.ID.ToString("B", CultureInfo.InvariantCulture));
                settingsElement.SetAttribute("ViewId", overlayList.DefaultView.ID.ToString("B", CultureInfo.InvariantCulture));
                settingsElement.SetAttribute("ListFormUrl", overlayList.Forms[PAGETYPE.PAGE_DISPLAYFORM].ServerRelativeUrl);
            }
            else
            {
                settingsElement.SetAttribute("ServiceUrl", exchangeUrl);
            }
            targetView.CalendarSettings = xml.OuterXml;
            targetView.Update();
            /*
            <AggregationCalendars>
                <AggregationCalendar 
                    Id="{cfc22c0b-688e-4555-b1d0-784081a91464}" 
                    Type="SharePoint" 
                    Name="My Overlay Calendar"
                    Description="" 
                    Color="1" 
                    AlwaysShow="True" 
                    CalendarUrl="/Lists/MyOverlayCalendar/calendar.aspx">
                    <Settings 
                        WebUrl="http://demo" 
                        ListId="{4a15e596-674f-4af7-a548-0b01470e8d75}" 
                        ViewId="{594c2916-14e7-4b08-ba36-1126b825bf45}" 
                        ListFormUrl="/Lists/MyOverlayCalendar/DispForm.aspx" />
                </AggregationCalendar>
                <AggregationCalendar 
                    Id="{cfc22c0b-688e-4555-b1d0-784081a91465}" 
                    Type="Exchange" 
                    Name="My Overlay Calendar"
                    Description="" 
                    Color="1" 
                    AlwaysShow="True" 
                    CalendarUrl="<url>">
                    <Settings ServiceUrl="<url>" />
                </AggregationCalendar>
            </AggregationCalendars>
            */
        }
    }
}

I’m not going to bore you with the details of this code as all I’m doing is basic XML manipulation. I created a couple of method overloads to allow for creating SharePoint or Exchange-based overlays. So, did you notice the namespace? Yup, no point in releasing code here if I’m not going to turn it into a cmdlet Smile

I’m not sure how useful this cmdlet will be in everyday use but imagine the scenario in which you have a primary calendar on your company portal and you want to add it as an overlay on every calendar throughout portal – you could easily do this using this cmdlet. Before we get to that, let’s see the full help for the cmdlet, which I called Set-SPListOverlay:

PS C:\Users\spadmin> help Set-SPListOverlay -full

NAME
    Set-SPListOverlay
    
SYNOPSIS
    Sets calendar overlays for the given list.
    
SYNTAX
    Set-SPListOverlay -Color  -OverlayTitle  [-OverlayDescription ] -OwaUrl  -WebServiceUrl  [-TargetList]  [-ViewName ] [-DoNotAlwaysShow ] [-ClearExisting ] [-AssignmentCollection ] []
    
    Set-SPListOverlay -Color  [-OverlayList]  [-OverlayTitle ] [-OverlayDescription ] [-TargetList]  [-ViewName ] [-DoNotAlwaysShow ] [-ClearExisting ] [-AssignmentCollection ] []
    
    Set-SPListOverlay [-OverlayLists]  [-TargetList]  [-ViewName ] [-DoNotAlwaysShow ] [-ClearExisting ] [-AssignmentCollection ] []
    
    
DESCRIPTION
    Sets calendar overlays for the given list.
    
    Copyright 2010 Falchion Consulting, LLC
    > For more information on this cmdlet and others:
    > http://blog.falchionconsulting.com/
    > Use of this cmdlet is at your own risk.
    > Gary Lapointe assumes no liability.
    

PARAMETERS
    -Color 
        The color to use for the overlay calendar.
        
        Required?                    true
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -TargetList 
        The calendar list to add the overlays to.
        
        Required?                    true
        Position?                    1
        Default value                
        Accept pipeline input?       true (ByValue)
        Accept wildcard characters?  false
        
    -ViewName []
        The name of the view to add the overlays to. If not specified the default view will be used.
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -OverlayList 
        The calendar list to add as an overlay.
        
        Required?                    true
        Position?                    2
        Default value                
        Accept pipeline input?       true (ByValue)
        Accept wildcard characters?  false
        
    -OverlayLists 
        The calendar lists to add as an overlay.
        
        Required?                    true
        Position?                    2
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -OverlayTitle []
        The title to give the overlay calendar when viewed in the target calendar.
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -OverlayDescription []
        The description to give the overlay calendar when viewed in the target calendar.
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -OwaUrl 
        Outlook Web Access URL.
        
        Required?                    true
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -WebServiceUrl 
        Exchange Web Service URL.
        
        Required?                    true
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -DoNotAlwaysShow []
        Don't always show the calendar overlay.
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -ClearExisting []
        Clear existing overlays. If not specified then all overlays will be appended to the list of existing over        lays (up until 10 - anything after 10 will be ignored)
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  false
        
    -AssignmentCollection []
        Manages objects for the purpose of proper disposal. Use of objects, such as SPWeb or SPSite, can use large amounts of memory and use of these objects in Windows PowerShell scripts requires proper memory management. Using the SPAssignment object, you can assign objects to a variable and dispose of the objects after they are needed to free up memory. When SPWeb, SPSite, or SPSiteAdministration objects are used, the objects are automatically disposed of if an assignment collection or the Global parameter is not used.
        
        When the Global parameter is used, all objects are contained in the global store. If objects are not immediately used, or disposed of by using the Stop-SPAssignment command, an out-of-memory scenario can occur.
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       true (ByValue)
        Accept wildcard characters?  false
        
    
        This cmdlet supports the common parameters: Verbose, Debug,
        ErrorAction, ErrorVariable, WarningAction, WarningVariable,
        OutBuffer and OutVariable. For more information, type,
        "get-help about_commonparameters".
    
INPUTS
    
    
OUTPUTS
    
    
NOTES
    
    
        For more information, type "Get-Help Set-SPListOverlay -detailed". For technical information, type "Get-Help Set-SPListOverlay -full".
    
    ------------------EXAMPLE------------------
    
    PS C:\> Get-SPList "http://server_name/lists/MyCalendar" | Set-SPListOverlay -TargetList "http://server_name/lists/MyOverlayCalendar" -Color "Pink" -ClearExisting
    
    
    This example adds the MyOverlayCalendar calendar as an overlay to the MyCalendar list.
    
    
RELATED LINKS
    Get-SPList 

You can see from the different parameter sets that I’ve made provisions for setting the overlay as a SharePoint list or an Exchange calendar; additionally, I’ve made it so that if you have an array of lists that you wish to add as an overlay you can easily pass that array in as well. So now let’s look at that example:

$mainList = Get-SPList http://demo/lists/myCalendar
foreach ($site in (Get-SPSite http://demo -Limit All)) {
    foreach ($web in $site.AllWebs) {
        foreach ($list in ($web.Lists | ? {$_.BaseTemplate -eq "Events"})) {
            if ($list.ID -eq $mainList.ID) { continue }
            Set-SPListOverlay -TargetList $list `
                -OverlayList $mainList `
                -Color "Pink" `
                -OverlayTitle "Main Portal Calendar" `
                -ClearExisting
        }
        $web.Dispose()
    }
    $site.Dispose()
}

Pretty simple huh? I’m just grabbing the primary list and then I’m looping through all my Site Collections and Sites and then grabbing all the lists that have a base template of “Events”. Once I have the list then I simply call my cmdlet – that’s it – easy right?

Okay, so what if you have a calendar with a bunch of overlays and you need to grab those calendars and do something to them? Well, I threw in a bonus cmdlet called Get-SPListOverlays. This one is really simple – it merely takes in the primary list and then calls a simple helper method that parses the XML structure and grabs each list. I’m not going to bother showing the code as it’s real basic and this post is long enough (just download the source if you’d like to see it) but I will show the cmdlet help:

PS C:\Users\spadmin> help Get-SPListOverlays -Full
NAME
    Get-SPListOverlays
    
SYNOPSIS
    Retrieve all SPList objects set as a calendar overlay on the given list.
    
SYNTAX
    Get-SPListOverlays [-Identity]  [-Web ] [-AssignmentCollection ] []
    
    
DESCRIPTION
    Retrieve all SPList objects set as a calendar overlay on the given list.
    
    Copyright 2010 Falchion Consulting, LLC
    > For more information on this cmdlet and others:
    > http://blog.falchionconsulting.com/
    > Use of this cmdlet is at your own risk.
    > Gary Lapointe assumes no liability.
    

PARAMETERS
    -Identity 
        The calendar whose calendar overlays will be retrieved.
        
        The value must be a valid URL in the form http://server_name/lists/listname or /lists/listname. If a server relative URL is provided then the Web parameter must be provided.
        
        Required?                    true
        Position?                    1
        Default value                
        Accept pipeline input?       true (ByValue)
        Accept wildcard characters?  false
        
    -Web []
        Specifies the URL or GUID of the Web containing the calendar whose overlays will be retrieved.
        
        The type must be a valid GUID, in the form 12345678-90ab-cdef-1234-567890bcdefgh; a valid name of Microsoft SharePoint Foundation 2010 Web site (for example, MySPSite1); or an instance of a valid SPWeb object.
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       true (ByValue)
        Accept wildcard characters?  false
        
    -AssignmentCollection []
        Manages objects for the purpose of proper disposal. Use of objects, such as SPWeb or SPSite, can use large amounts of memory and use of these objects in Windows PowerShell scripts requires proper memory management. Using the SPAssignment object, you can assign objects to a variable and dispose of the objects after they are needed to free up memory. When SPWeb, SPSite, or SPSiteAdministration objects are used, the objects are automatically disposed of if an assignment collection or the Global parameter is not used.
        
        When the Global parameter is used, all objects are contained in the global store. If objects are not immediately used, or disposed of by using the Stop-SPAssignment command, an out-of-memory scenario can occur.
        
        Required?                    false
        Position?                    named
        Default value                
        Accept pipeline input?       true (ByValue)
        Accept wildcard characters?  false
        
    
        This cmdlet supports the common parameters: Verbose, Debug,
        ErrorAction, ErrorVariable, WarningAction, WarningVariable,
        OutBuffer and OutVariable. For more information, type,
        "get-help about_commonparameters".
    
INPUTS
    
    
OUTPUTS
    
    
NOTES
    
    
        For more information, type "Get-Help Get-SPListOverlays -detailed". For technical information, type "Get-Help Get-SPListOverlays -full".
    
    ------------------EXAMPLE------------------
    
    PS C:\> $lists = Get-SPListOverlays "http://server_name/lists/mylist"
    
    
    This example retrieves the calendar overlays for the calendar at http://server_name/lists/mycalendar.
    
    
RELATED LINKS
    Get-SPList 
    Set-SPListOverlay 
    Get-SPWeb 

In the end this turned out to all be pretty simple to do but it was certainly a challenge trying to figure it all out as there’s no documentation (official or otherwise) that I’ve been able to find.

18Jun/116

“Automating SharePoint 2010 with Windows PowerShell 2.0” Now Available (and the Bruins win the Cup!)

Boston Bruins - 2011 Stanley Cup Champions!This week was a particularly good week – one that I’ve been waiting to have for a *very* long time. Many who know me know that I’m a huge Boston Bruins fan – I grew up in New Hampshire and have bled black and gold my whole life (even  during those late ‘90s and early ‘00 years when many were ashamed to admit they were Bruins fans); well this past Wednesday, after 39 years, the Bruins finally brought Lord Stanley’s Cup home to Boston! For those that don’t follow hockey this probably doesn’t mean much – but to a true hockey fan this is way greater than the Super Bowl or the World Cup or anything like that – and for someone from Boston, the first US based NHL team, it’s that much greater. So with that win my week was looking pretty good – and then Thursday came and, still high from the win, I finally got my own physical copy of the book which I (and my co-author, Shannon Bray) spent so much time working on over the last year. And that brings me to the real purpose of this post – to officially announce the release of the book!

The book actually released earlier last week but due to a minor miscommunication I didn’t get my author copy of the book until just this Thursday – and I didn’t want to put this together until I actually had the thing in my hands. Before I say anything else I want to first thank my co-author, Shannon Bray – I can get pretty nit-picky with technical stuff like this and Shannon was great in how receptive he was to any feedback I had with his chapters. I also want to thank Spencer Harbar for helping with the technical reviews of the book – Spence wasn’t able to review everything we wrote due to the way the edit process works with Sybex but I believe that the book is greatly improved due to his contributions (if there’s an error in the book you can assume that’s something Spence didn’t get to review Smile). And of course I need to thank the whole Sybex team for making the book possible.

Okay, enough of that – let’s talk about what’s in the book. Let me first provide you with some helpful links to where you can purchase the book or download the supporting materials and preview chapters and whatnot:

There’s also supposed to be a ton of sample scripts available for download but for some reason those haven’t made it up on the book’s site yet (I’ve got an inquiry into Sybex to see what’s up – as soon as they are posted I’ll send out a tweet with the download link – follow me on twitter for updates: @glapointe). Also, from the Amazon site you can use the “Look Inside” feature (just click the book logo) to view some additional content as well as the first few pages of most chapters.

One note about Appendix A – this particular chapter is actually my favorite chapter – it was the most fun to write and includes a *ton* of information that is not documented anywhere. When Shannon and I put the original chapter outline together we did not have this chapter included as the original target audience was supposed to be IT administrators – as a result, Sybex did not budget for the additional page count and the chapter got dropped (I was upset that it got labeled as an Appendix and then more upset that it got dropped, but Sybex is running a business and I respect their decision, I’m just bummed that I couldn’t see it in print).

Also, those of you that pay close attention to details might note that the book title changed slightly (I didn’t know this until I got it in my hands). The book was originally “Automating SharePoint 2010 with Windows PowerShell 2.0” but it got changed to “Automating SharePoint 2010 Administration with Windows PowerShell 2.0” (I know, it’s verbose). It’s a subtle change meant to bring the title in line with other books that Sybex is releasing. However, what I want to be clear about is that this book is not just meant for IT administrators – true, they will benefit from it the most, but remember, I’m a developer, that’s where my passion is, and as such I tried to include as many nuggets as I could to make this book a value to both IT administrators and developers (heck, just the first three chapters on Windows PowerShell in general should be a must read for both audiences).

Now let’s take a look at what is in the book. I’ve pasted below the chapter details as found in the front section of the book; one thing I added is who was responsible for each chapter. I should note that, in order to help enforce a sense of consistency and technical accuracy, I did provide Shannon with a lot of assistance on his chapters, so though I’ve only called out the chapters that I was primarily responsible for, I was in fact a major contributor on all chapters.

Part 1 - Getting Started With Windows PowerShell Basics

  • Chapter 1, “Windows PowerShell 101,” begins with a basic understanding of Windows PowerShell: the shell, cmdlets, variables, and types and how to work with and output data. (Gary)
  • Chapter 2, “Filtering and Iterating Your Data,” expands on the concepts of Chapter 1 by showing how to add structure and logic to commands. (Gary)
  • Chapter 3, “Making Your PowerShell Reusable,” completes the basic Windows PowerShell run-through by explaining how to turn a series of commands into functions, scripts, and modules. (Gary)

Part 2 - Installing and Configuring a SharePoint 2010 Environment

  • Chapter 4, “Deploying New Installations and Upgrades,” details how to create an installation script for new Farm installations and presents upgrade scenarios and scripts that can ease the upgrade process. (Gary)
  • Chapter 5, “Configuring Server Communications,” builds on the information learned in Chapter 4 by detailing the various settings that affect the communication of SharePoint with and through dependent resources, such as network adapters, the firewall, and Active Directory. (Shannon)
  • Chapter 6, “Configuring Farm Application Settings,” shows how to use Windows PowerShell to configure some of the core configuration options available on the General Application Settings page of the Central Administration site. (Shannon)

Part 3 - Deploying and Managing Applications

  • Chapter 7, “Managing Web Applications,” covers the creation and manipulation of Web Applications and the various configurable properties that are scoped to the Web Application level. (Shannon)
  • Chapter 8, “Managing Site Collections and Sites,” continues where Chapter 7 left off by covering the creation and manipulation of Site Collections and Sites and the various configurable properties that are scoped the Site Collection or Site level. (Shannon)
  • Chapter 9, “Understanding Authentication,” builds on the information from Chapter 7 by detailing the Classic and Claims authentication modes that must be taken into account when provisioning and working with Web Applications. (Shannon)
  • Chapter 10, “Managing Features and Solutions,” details how to manage SharePoint Solution Packages and Features, including those deployed to the Solutions Gallery (Sandbox Solutions). (Shannon)

Part 4 - Services and Service Applications

  • Chapter 11, “Managing Service Applications,” introduces the Service Application concepts and foundational information necessary to understand the subsequent chapters that focus on provisioning individual Service Applications. (Gary)
  • Chapter 12, “Provisioning Support Services,” covers the provisioning of the core Service Applications that are necessary for SharePoint and/or other Service Applications to function properly, including: Web Analytics Services, State Services, Secure Store Services, User Code Services, Claims to Windows Token Services, and the Usage and Health Data Collection Services. (Shannon)
  • Chapter 13, “Provisioning Business Intelligence, Business Connectivity, and Word Automation Services,” continues the Service Application provisioning with the Business Intelligence–focused Service Applications (Excel, Access, Visio, and PerformancePoint) and the Business Connectivity Services (BCS) and Word Automation Services Applications. (Gary)
  • Chapter 14, “Provisioning Search Services,” tackles what is undoubtedly the most complex Service Application, the Enterprise Search Services Service Application, and it concludes with the Foundation Search, the only place where STSADM will be used in the book. (Shannon)
  • Chapter 15, “Provisioning Metadata and User Profile Services,” completes the Service Application provisioning story with the Managed Metadata Services Service Application and the User Profile Services Service Application, including coverage of the many issues oft en experienced with the User Profile Synchronization Service. (Gary)

Part 5 - Managing and Maintaining a SharePoint Environment

  • Chapter 16, “Managing Operational Settings,” covers monitoring SharePoint, including how to work with Unified Logging Service (ULS) logs and the Health Analyzer, and Timer Jobs, and concludes with coverage of the Developer Dashboard. (Shannon)
  • Chapter 17, “Back Up and Restore a SharePoint Environment,” details the various backup and restore cmdlets available for backing up the Farm, Site Collections, Sites, and lists. (Shannon)
  • Chapter 18, “Optimizing the Performance of a SharePoint Environment,” walks through the most common areas where performance gains can be had, including resource throttling, caching, and remote binary large object (BLOB) storage. (Shannon)

Part 6 - Advanced Administration

  • Chapter 19, “Remote Administration,” shows how to connect remotely to and work with a SharePoint Farm using Windows PowerShell, thus reducing the need for direct server access. (Gary)
  • Chapter 20, “Multi-Tenancy,” builds on the previous chapters by demonstrating how to build a SharePoint hosting Farm. (Gary)
  • Appendix A, “Creating Custom Cmdlets,” takes the SharePoint PowerShell story to the next level by showing how to extend the
    out-of-the-box capabilities by adding new cmdlets, views, and extensions. (Gary)

The book came in at 737 pages - for my first attempt at writing a book this was rather immense (it will make a great doorstop some day Smile). Shannon and I did our best to make the book informative and technically accurate – hopefully readers of the book will agree – that said, if you find something you disagree with or that is simply wrong/inaccurate/incomplete/total bullsh**/whatever, please let us know (just please be kind Smile). You can either fill out the errata form on the Sybex site or post a comment here (there were many, *many* late nights and weekends involved with the writing of this book and, as such, it’s quite possible that I brain farted a thing or two).

Shannon and I hope you enjoy the book – if you do, please tell a friend, if you don’t, well, um, the book’s already printed so not much I can do to fix it but maybe I can do some more blogging to make up for it Smile.

-Gary

Tagged as: 6 Comments
7May/110

Monitor SharePoint User Profile Changes

Today I got my copy of the May 2011 edition of SharePoint Pro magazine and was pleased to find the “Monitor SharePoint User Profile Changes” article that I co-wrote with my buddy Matthew McDermott! The cool thing for me is that this is my first ever magazine article so I’m very excited! You can find the article online at the SharePoint Pro site: http://www.sharepointpromag.com/article/sharepoint/monitor-sharepoint-user-profile-changes-129846.

Note that for some reason the online version of the article only shows my picture for the authors and you have to look closely to see Matt’s name which makes it look, at first glance, like there was just one author, me – I’m really bummed about this for if it wasn’t for Matt I wouldn’t even have gotten the opportunity to write this article – fortunately, the print version gives better props to both of us; so, Matt, if you’re reading this, thanks for helping me to achieve this long standing goal!

-Gary