Monday, 1 November 2010

Change the content type set on files in SharePoint using PowerShell

If you have to make changes to a site content type architecture, the requirement may exist to change a batch of files in a document library from one content type to another. This is usually because you either need to reclassify existing documents to a new content type or move documents to another content type so that unwanted content types can be removed from the list.

The process to change the content type on multiple files using the browser UI is both time consuming and very monotonous. Fortunately, PowerShell can do it for you in a matter of seconds. The script below sets up a function which will look at a document library and modify all files (including those in folders) associated with a specified content type to a different one. Before you can start changing files, run the script below:

function Reset-SPFileContentType ($WebUrl, $ListName, $OldCTName, $NewCTName)
{
    #Get web, list and content type objects
    $web = Get-SPWeb $WebUrl
    $list = $web.Lists[$ListName]
    $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 "None")
                {
                    #Change the content type association for the item
                    $_.File.CheckOut()
                    write-host "Resetting content type for file" $_.Name "from" $oldCT.Name "to" $newCT.Name
                    $_["ContentTypeId"] = $newCTID
                    $_.Update()
                    $_.File.CheckIn("Content type changed to " + $newCT.Name, 1)
                }
                else
                {
                    write-host "File" $_.Name "is checked out to" $_.File.CheckedOutByUser.ToString() "and cannot be modified"
                }
            }
            else
            {
                write-host "File" $_.Name "is associated with the content type" $_.ContentType.Name "and shall not be modified"
            }
        }
    }
    else
    {
        write-host "One of the content types specified has not been attached to the list"$list.Title
    }
    $web.Dispose()
}

Once the script has been run, you can use it by typing the following command:

Reset-SPFileContentType –WebUrl <Site URL> –ListName <Document library display name> –OldCTName <Content type to be replaced> –NewCTName <Content type to replace it with>

For example, the following command will step through all files in a document library called “Shared Documents” from the site http://portal/team, and change all documents associated with the “Document” content type to one called “Sales Document”:

Reset-SPFileContentType –WebUrl “http://portal/team” –ListName “Shared Documents” –OldCTName “Document” –NewCTName “Sales Document”

Note that the new content type must be associated with the list before you run the command – the script will not attach it for you (I’ll be providing scripts for attaching and removing content types on lists in future posts).

A potential issue with performing this sort of change is that you may lose some column values during the content type move – even if the same columns exist on both the old and new content type. I did some simple testing with the standard “Title” column, a custom text column, and a choice column and values were successfully retained when I changed the content type – even on non-Microsoft Office documents. However, as I cannot guarantee this will be the case with all columns or column types, I strongly recommend that you attempt the move in a test document library or development environment prior to running the script for real.

image

34 comments:

  1. Thank you! You just saved me several hours of tedious work!

    http://practicalsharepoint.blogspot.com

    ReplyDelete
  2. i couldnt run the Above code to change the content type of KPI list,

    ReplyDelete
  3. Is that also possible for document libraries?
    Thx

    ReplyDelete
  4. Great Script! i just tested it, and it works awesome! thank you!

    ReplyDelete
  5. Will this also work in MOSS 2007? Is there any easy way to loop through all document libraries of a specific library type definition (not just the name of one library) - and provide it a site collection URL where it does this for all sites and libraries within the collection?

    ReplyDelete
    Replies
    1. Nope. The SharePoint PowerShell snap-in was built and released for SharePoint 2010. It is not compatible with MOSS 2007 and MS makes no cmdlets available for that SharePoint versions older than 2010.

      You may still be able to use PowerShell with MOSS 2007, but have to write your own cmdlets that use STSADM or the SharePoint Object Model directly. Phil Child's Reset-SPFileContentTypes script above will not work as-is.

      Delete
    2. Martin is correct. I have attempted to provide some guidance on using PowerShell with MOSS 2007 in this article: http://get-spscripts.com/2011/03/using-powershell-scripts-with-wss-30.html. So, you could try and replace some of the built-in cmdlets with the examples in this article.

      Delete
    3. We can mimic PowerShell cmdlets for SharePoint 2010 or 2013 in MOSS 2007: How to use PowerShell with SharePoint 2007

      Delete
  6. Thank you Phil! this is a very useful script for me.
    Do you have an idea how could i read the TaxonomyFieldValue from OldCTName and put in same column in newCTName? You will help me very much if you have an idea about that :-)

    thx

    ReplyDelete
  7. This is a cool script !
    Thanks .

    ReplyDelete
  8. Hi,

    I have used exact your script. but it does not work. What I mistaking is maybe the files are new. The files added to the list (document library) and then I tried your script.
    I think it works only if files have been created for a while.

    ReplyDelete
  9. Hi - I have a site with over 50 sites under it, each with a correspondence document library that has an Email and Document content type. I would like to change the default content type from Document to Email. Would you have a suggestion on an easy way of doing this through powershell?

    thanks you so much.

    ReplyDelete
  10. Thank you! Just what I needed!

    ReplyDelete
  11. Thank you for the script, very much appreciated. After executing the .ps1 file on powershell it jumps to a new line which means that the script has been executed but when i run the Reset command that calls the function it gives an error "command not recognised as cmdlet"

    ReplyDelete
    Replies
    1. Hello,
      I also experienced this behavior. Did you ever get it to work?

      Stowe

      Delete
    2. I have the same problem. Did you find a solution?

      Delete
  12. Worked like a charm. Thanks!

    ReplyDelete
  13. This works great, but is it possible to amend so that it changes content type by file extension using {$_.Name -Like $Filetype}?

    ReplyDelete
  14. This works great but is there a way to reset the Content type without impacting the metadate i.e modified date/modified by information . I need to reset the content type for multiple records and it changes the metadata to current which i dont want. Thanks in advance!

    ReplyDelete
  15. Amrita, to reset Content Type without updating the metadata, call the $_.SystemUpdate($false) method instead of $_.Update()

    ReplyDelete
  16. As always Phil, your an animal! Thanks!@

    ReplyDelete
  17. Good day,

    I am trying use this function on one of my SharePoint Online (Office 365) sites, but cannot seem to get PowerShell to create the Reset-SPFileContentType CmdLet using the script. I am logged onto the correct site and can run other commands provided by the SharePoint Online CmdLet library, but cannot add this one. The script seems to run fine as I have the execution policy set to RemoteSigned. When I run the script, PS just goes back to the prompt ... no errors, no nothing.

    Any ideas? This would be incredibly valuable as I have well over 1,000 documents that I need to change the content type.

    Thank you,

    Richard Sauerbrun
    Richard@levredgetech.com
    Scottsdale, AZ USA
    1-480-766-2814

    ReplyDelete
  18. Hello

    I tested your change script, it works perfect on document library. I noticed that if you change the content type on document library level but on site level it will not get updated. How can I make it like if if we change content type on document library so on site level it should automatically get updated, Is it possible?

    Avian

    ReplyDelete
  19. Hello,

    I'm trying to change the content type of folders in a library, this is what I have so far but I cant get it to work, can anyone help.

    Cheers

    Tom

    $WebUrl = "http://intranet/sites/dev/test"
    $ListName = "test"
    $OldCTName = "Folder"
    $NewCTName = "Enhanced Folder"
    $web = Get-SPWeb $WebUrl
    $list = $web.Lists[$ListName]
    $oldCT = $list.ContentTypes[$OldCTName]
    $newCT = $list.ContentTypes[$NewCTName]
    $newCTID = $newCT.ID

    if (($oldCT -ne $null) -and ($newCT -ne $null))
    {
    foreach($folder in $list.Folders)
    {
    if ($_.ContentType.Name -eq $oldCT.Name)
    {
    write-host "Resetting content type for folder" $_.Name "from" $oldCT.Name "to" $newCT.Name
    $_["ContentTypeId"] = $newCTID
    $_.Update()
    }
    }
    }
    $web.Dispose()

    ReplyDelete
    Replies
    1. Its okay I got it working.

      $web = Get-SPWeb http://intranet/sites/dev/test
      $list = $web.Lists["test"]
      $oldCT = $list.ContentTypes["Folder"]
      $newCT = $list.ContentTypes["Enhanced Folder"]
      $newCTID = $newCT.ID

      for($i=0; $i -le $web.Lists.Count; $i++)
      {
      foreach($folder in $list.folders[$i])
      {
      if ($folder.ContentType.Name -eq $oldCT.Name)
      {
      $folder["ContentTypeId"] = $newCTID
      $folder.Update()
      }

      }
      }
      $web.Dispose()

      Delete
  20. So is there any way to run this to hit every 'documents' library in a site collection or subsite?

    ReplyDelete