Have you ever found yourself in a situation where you needed to replace all occurrences of one web part type with another web part type? No? Consider this scenario: you are using the out of the box content query web part and you discover one of the numerous bugs with this web part or decide that you want to ensure that a specific XSLT file is always used or something like that, so you decide to create a custom content query web part by sub-classing the out of the box one; now you deploy your custom web part and remove the out of the box one from the web part gallery so that any new instance will now be based on your custom type. So this is great, you’ve accomplished your goals and have implemented one of my personal best practices (don’t use the out of the box content query web part and instead use a custom implementation). But now what do you do with the potentially hundreds of existing instances that are deployed on pages throughout your Farm? Well, you need to somehow replace those instances with instances of your new type. For this, PowerShell is your friend!

I’ve encountered this specific scenario as well as numerous other ones (replacing crappy web parts written by other consultants with new versions in different solutions, etc.) and have written lots of different scripts which accomplish this goal. But today I decided I was tired of creating and managing all these scripts so I went ahead and created a custom cmdlet that could achieve what I needed for a given SPFile with a single command: Replace-SPWebPartType.

The Replace-SPWebPartType cmdlet accepts an URL to a web part page (or an instance of an SPFile object) and a string or Type object representing the type of web part to replace and what to replace it with; you can further restrict what web parts are updated by providing a web part title to filter on and you can pass in additional properties to set via a Hashtable object (closed web parts are ignored). The full help for the cmdlet can be seen below:

NAME
    Replace-SPWebPartType

SYNOPSIS
    Replaces instances of one web part type with another web part type.

SYNTAX
    Replace-SPWebPartType [-File] <SPFilePipeBind> -OldType <TypePipeBind> -NewType <TypePipeBind> [-Title <String>] [-Properties <Hashtable>] [-Publish <SwitchParameter>] [-AssignmentCollection <SPAssignmentCollection>] [<CommonParameters>]

DESCRIPTION
    Replaces instances of one web part type with another web part type.

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

PARAMETERS
    -File <SPFilePipeBind>
        The URL to a web part page or an instance of an SPFile object.

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

    -OldType <TypePipeBind>
        The web part type to replace.

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

    -NewType <TypePipeBind>
        The web part type to replace the old type with.

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

    -Title [<String>]
        The web part title to restrict the replacement to.

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

    -Properties [<Hashtable>]
        Additional properties to set or override after copying the old web part properties.

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

    -Publish [<SwitchParameter>]
        If specified the page will be published after adjusting the Web Part.

        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 Replace-SPWebPartType -detailed". For technical information, type "Get-Help Replace-SPWebPartType -full".

    ——————EXAMPLE——————

    PS C:\> Replace-SPWebPartType -File "http://server_name/pages/default.aspx" -OldType "Microsoft.SharePoint.Publishing.WebControls.ContentByQueryWebPart, Microsoft.SharePoint.Publishing, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" -NewType "MyContentByQueryWebPart, MyCompany.SharePoint.WebParts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4ec4b9177b831752" -Publish

    This example replaces all instances of the web part who's class name is ContentByQueryWebPart with the web part who's class name is MyContentByQueryWebPart.

RELATED LINKS
    Get-SPFile

As previously stated, I’ve created a custom PipeBind object for the type parameters so that you can pass in either a string or an actual type object and you don’t always have to provide the full assembly details. So you could call the cmdlet like this (as opposed to using a string as shown in the example included with the help text):

1$oldType = [Microsoft.SharePoint.Publishing.WebControls.ContentByQueryWebPart]
2$newType = [Lapointe.SharePoint.MyContentByQueryWebPart]
3Replace-SPWebPartType -File http://demo/Pages/default.aspx -OldType $oldType -NewType $oldType

The preceding examples all work with a single file but you could of course wrap this in a loop to update all web parts in a specific Library, Site, Site Collection, Web Application or the entire Farm. Additionally, the cmdlet supports providing the –WhatIf parameter so you can see what changes would be made without it actually changing anything. And finally, it also has support for web parts in content fields so when it deletes the old web part it will update the content to make sure it points to the new web part. (Note that I’m simply using reflection to iterate through all the properties of the old web part and to set those same properties on the new web part – if the property doesn’t exist on the new web part then it is ignored).

So to wrap up a final example here is a short script which updates all publishing pages where appropriate:

 1$newType = [Lapointe.SharePoint.MyContentByQueryWebPart]
 2$oldType = [Microsoft.SharePoint.Publishing.WebControls.ContentByQueryWebPart]
 3foreach ($site in (Get-SPWebApplication).Sites) {
 4    foreach ($web in $site.AllWebs) {
 5        foreach ($page in (Get-SPPublishingPage -Web $web)) {
 6            $gc = Start-SPAssignment
 7            try {
 8                $mgr = $gc | Get-SPLimitedWebPartManager $page.Uri.ToString() -ErrorAction SilentlyContinue
 9            } catch {
10                Write-Warning "Error retrieving mgr: $($page.Uri.ToString())"
11                continue
12            }
13            if ($mgr -eq $null) { continue }
14            $changeNeeded = $false
15            foreach ($wp in $mgr.WebParts) {
16                if ($wp -eq $null) { continue }
17                if ($wp.GetType() eq $oldType) {
18                    Write-Host "Found CQWP => $($page.Uri.ToString())::$($wp.Title)"
19                    $changeNeeded = $true
20                }
21            }
22            if ($changeNeeded) {
23                Write-Host "About to make a change to $($page.Uri.ToString())" -ForegroundColor Green
24                Replace-SPWebPartType -File $page.Uri.ToString() -OldType $oldType -NewType $newType -Publish
25            }
26            
27            $gc | Stop-SPAssignment
28        }
29        $web.Dispose()
30    }
31    $site.Dispose()
32}