I came across a need to change all existing documents in a Site Collection to another ContentType, but without changing data like, “modified by” or “modified date”.

Why?

I need to attach a column to all documents and it’s just not good practise to add columns to the default “Document” ContentType. I need to add the ContentType to the Document library, attach all documents with the ContentType “Document” to the new ContentType and then delete the ContentType “Document”. Users need not think about ContentTypes and how to use the correct one, so this needs to run once a day to catch new document libraries and change the documents without the users noticing anything.

The plan for each document library:

  1. Add ContentType “MyCustomDocument”
  2. Enable versioning (major versions and no limits)
  3. Attach all documents to the ContentType “MyCustomDocument”
  4. Remove the standard ContentType “Document”
  5. Create Scheduled tasks for the whole process

I have created two PowerShell scripts in order for this to complete. One script takes care of the documentlibrary and another script takes care of all the documents in those libraries. If you run the scripts manually, you need to run the first script twice, as it will only run, when all documents in the library has changed their ContentType to the new one.

Check out the scripts below or download the files, including bat-files to start the scripts. Download PowerShell files and batch files to start them up.

CleanUpDocLibs.ps1

[ps]
<#
Name: CleanUpDocLibs.ps1
Title: Clean Up Document Libraries
Author: Ulrich Gerting Bojko (ulrich@getinthesky.com)

Description: Go through all Libraries (execpt the ones in the forbidden list)
and do the following:
1. Allow Content Types
2. Enable Versioning (major versions, no limit)
3. Attach Content Type "MyCustomDocument"
4. Delete Content Type "Document"
#>
#Fill ind the url of the sitecollection you wish to run through
$url = "http://intranet.domain.com"

#Fill in the Content Type you wish to add to the library
$lookForCT = "MyCustomDocument"

#Fill in the Content Type you wish to delete
$lookForCTDel = "Document"

#Fill out the names of those documentlibraries that should be excluded below
$forbidden = @("Style Library", "FormServerTemplates", "SiteCollectionDocuments", "SiteAssets")

#Do not edit below this line and blame me for anything gone wrong
#——————————————————————————

#Add the SharePoint snapin and continue
Add-PSSnapin Microsoft.SharePoint.Powershell -ea SilentlyContinue

$site = Get-SPSite $url

#Walk through each site in the site collection
$site | Get-SPWeb -Limit all | ForEach-Object {
$web = $_.Url

#Go through each document library in the site
$_.Lists | where { $_.BaseTemplate -eq &quot;DocumentLibrary&quot;} | ForEach-Object { 

    $docLibrary = $_.Lists[$_.Title]

    #Check if List is forbidden
    if ($forbidden -contains $_.Title ){

    }
    else
    {

        if (($_.ContentTypes | where { $_.Name -eq $lookForCT }) -eq $null)
        {
            write-host &quot;Adding content type &quot; $lookForCT &quot;on list&quot; $docLibrary.Title
            $docLibrary.ContentTypesEnabled = $true
                        $docLibrary.EnableVersioning = $true
            $docLibrary.Update()

            #Add site content types to the list
            $ctToAdd = $site.RootWeb.ContentTypes[$lookForCT]
            $ct = $docLibrary.ContentTypes.Add($ctToAdd)
            write-host &quot;Content type&quot; $ct.Name &quot;added to list&quot; $docLibrary.Title
            $docLibrary.Update()
        }

        #Delete Content Type
        if (($_.ContentTypes | where { $_.Name -eq $lookForCTDel }) -eq $null)
        {
            #write-host &quot;No content type exists with the name&quot; $lookForCTDel &quot;on list&quot; $_.Title
        }
        else
        {
            $ctToRemove = $_.ContentTypes[$lookForCTDel]
            write-host &quot;Removing content type&quot; $ctToRemove.Name &quot;from list&quot; $web &quot;/&quot; $_.Title
            $_.ContentTypes.Delete($ctToRemove.Id)
            $_.Update()
        }
    }
}

}
#Dispose of the site object
$site.Dispose()
[/ps]

CleanUpItems.ps1

[ps]
<#
Name: CleanUpItems.ps1
Title: Clean Up Files in Document Libraries
Author: Ulrich Gerting Bojko (ulrich@getinthesky.com)

Description: Go through all files in all Documentlibraries, that
have the new Content Type attached and do the following:
1. Change the Content Type to the new one
2. Preserve the "Modified" and "Editor" metadata

#>
#Fill ind the url of the sitecollection you wish to run through
$url = "http://intranet.domain.com"

#Fill in the name of the Content Tpe you wish to replace from
$OldCTName = "Document"

#Fill in the name of the Content Tpe you wish to replace to
$NewCTName = "MyCustomDocument"

#Do not edit below this line and blame me for anything gone wrong
#——————————————————————————

#Add the SharePoint snapin and continue
Add-PSSnapin Microsoft.SharePoint.Powershell -ea SilentlyContinue

$site = Get-SPSite $url

#Walk through each site in the site collection
$site | Get-SPWeb -Limit all | ForEach-Object {

$web = $_.Url       

#Go through each document library in the site
$_.Lists | where { $_.BaseTemplate -eq &quot;DocumentLibrary&quot;} | ForEach-Object {
$list = $_
$oldCT = $list.ContentTypes[$OldCTName]
$newCT = $list.ContentTypes[$NewCTName]
$newCTID = $newCT.ID

    #Check if the values specified for the content types actually exist on the list
    if (($oldCT -ne $null) -and ($newCT -ne $null))
    {
        #Go through each item in the list
        $list.Items | ForEach-Object {

            #Check if the item content type currently equals the old content type specified
            if ($_.ContentType.Name -eq $oldCT.Name)
            {
                #Check the check out status of the file
                if ($_.File.CheckOutType -eq &quot;None&quot;)
                {
                    #Change the content type association for the item
                    $item = $_
                    $Editor = $item[&quot;Editor&quot;]
                    $Modified = $item[&quot;Modified&quot;]
                    $_.File.CheckOut()
                    write-host &quot;Resetting content type for file&quot; $web &quot;/&quot; $_.Url &quot;from&quot; $oldCT.Name &quot;to&quot; $newCT.Name
                    $_[&quot;ContentTypeId&quot;] = $newCTID
                    $item[&quot;Editor&quot;] = $Editor
                    $item[&quot;Modified&quot;] = $Modified
                    $_.Update()
                    $_.File.CheckIn(&quot;Content type changed to &quot; + $newCT.Name, 1)
                }
                else
                {
                    write-host &quot;File&quot; $web &quot;/&quot; $_.Url &quot;is checked out to&quot; $_.File.CheckedOutByUser.ToString() &quot;and cannot be modified&quot;
                }
            }
            else
            {
                write-host &quot;File&quot; $web &quot;/&quot; $_.Url &quot;is associated with the content type&quot; $_.ContentType.Name &quot;and shall not be modified&quot;

            }
        }
    }
    else
    {
        #write-host &quot;One of the content types specified has not been attached to the list&quot;$web $list.Title
    }

}

}
#Dispose of the site object
$site.Dispose()
[/ps]