A customer of mine has the problem that he wants to remove a Web Content Type but SharePoint says the content type is still in use.
Therefore I created a tool for enumerating all web and list content types of all sites.
The following script scans the SharePoint farm and creates a Windows form with a Treeview like this:
(Web) = Web Content Types
(List) = List Content Types
The tool show the content type inheritence:
Here you see the List Content Type “Image” that based on the Web Content Type “Image” that based on the Web Content Type “Rich Media Asset” that based on Web Content Type “Document” that is inherited from the “System” Content Type.
It’s possible to open the content type management site by clicking “_open management site” or open the related list or web by clicking “_open list” or “_open web”.
This is the script:
#region Init Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") | Out-Null [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null cls #endregion #region Form $form = New-Object System.Windows.Forms.Form $button = New-Object System.Windows.Forms.Button $treeview = New-Object System.Windows.Forms.TreeView $form.SuspendLayout() $button.DialogResult = [System.Windows.Forms.DialogResult]::Cancel $button.Dock = [System.Windows.Forms.DockStyle]::Bottom $button.Location = (new-object System.Drawing.Point(0, 250)) $button.Name = "button1" $button.Size = (new-object System.Drawing.Size(292, 23)) $button.TabIndex = 0 $button.Text = "Close" $button.UseVisualStyleBackColor = $true $treeview.Dock = [System.Windows.Forms.DockStyle]::Fill $treeview.Location = (new-object System.Drawing.Point(0, 0)) $treeview.Name = "treeView1" $treeview.Size = (new-object System.Drawing.Size(292, 250)) $treeview.TabIndex = 1 $form.AutoScaleDimensions = new-object System.Drawing.SizeF(6.0, 13.0) $form.AutoScaleMode = [System.Windows.Forms.AutoScaleMode]::Font $form.ClientSize = (new-object System.Drawing.Size(292, 273)) $form.Controls.Add($button) $form.Controls.Add($treeview) $form.Name = "Content Type Usage " $form.Text = "Content Type Usage / https://blog.kenaro.com" $form.ResumeLayout($false) #endregion $list = @{} $treeview.add_NodeMouseDoubleClick({ param($sender, $eventArgs) if($eventArgs.Node.Tag -ne $null ) { [System.Diagnostics.Process]::Start($eventArgs.Node.Tag) } }); function analyseWeb { param([Microsoft.SharePoint.SPWeb]$web) $web.ContentTypes | % { $ct = $_ $global:list += @{"$($ct.Id)"=$ct} } $web.lists | % { $_.ContentTypes | % { $ct = $_ $global:list += @{"$($ct.Id)"=$ct} } } $web.Webs | % { analyseWeb -web $_ } } function reorder { param([Microsoft.SharePoint.SPContentType]$p = $null, [int]$intend, [System.Windows.Forms.TreeNode]$parentNode) if( $p -eq $null ) { $ct = $list["0x"] $tn = New-Object System.Windows.Forms.TreeNode("System") $tn.ToolTipText = "0x" $parentNode.Nodes.Add($tn) | Out-Null reorder -p $ct -intend 0 -parentNode $tn } else { ($list.Values | ? {$_.Id.IsChildOf($p.Id) -and $_ -ne $p} | sort @{Expression={$_.Id.ToString().Length}}, $_.Id.ToString() ) | % { $ct = $_ $type="" $url="" $tn = $null if( $ct.ParentList -ne $null ) { $type="(List) $($ct.Name) / List: $($ct.ParentList.Title) / Id: $($ct.Id.ToString())" $url = $ct.parentweb.url + "/_layouts/ManageContentType.aspx?ctype=" + $ct.Id.ToString()+"&List="+$ct.ParentList.Id.ToString() #http://<domain>/sites/<web>/_layouts/ManageContentType.aspx?List=%7B111963EB%2DF504%2D49EC%2DA21B%2D814319718684%7D&ctype=0x010100644EE9F5F657474B92A2716207BB5DE2 $tn = New-Object System.Windows.Forms.TreeNode($type) $tn1 = New-Object System.Windows.Forms.TreeNode("_open management site") $tn1.Tag = $url $tn.Nodes.Add($tn1) | Out-Null $tn2 = New-Object System.Windows.Forms.TreeNode("_open list") $tn2.Tag = $ct.ParentWeb.Site.MakeFullUrl($ct.ParentList.DefaultViewUrl) $tn.Nodes.Add($tn2) | Out-Null }else { $type="(Web) $($ct.Name) / Id: $($ct.Id.ToString())" $url = $ct.parentweb.url + "/_layouts/ManageContentType.aspx?ctype=" + $ct.Id.ToString() #http://<domain>/sites/<web>/_layouts/ManageContentType.aspx?ctype=0x0100CF8FCF53E9FA451CB145093F830B1762 $tn = New-Object System.Windows.Forms.TreeNode($type) $tn1 = New-Object System.Windows.Forms.TreeNode("_open management site") $tn1.Tag = $url $tn.Nodes.Add($tn1) | Out-Null $tn2 = New-Object System.Windows.Forms.TreeNode("_open web") $tn2.Tag = $ct.ParentWeb.Url $tn.Nodes.Add($tn2) | Out-Null } $parentNode.Nodes.Add($tn) | Out-Null reorder -p $ct -intend ($intend+1) -parentNode $tn } } } if($fileName -ne $null ) { Remove-Item -Path $fileName -Confirm:$false -ErrorAction SilentlyContinue } #you can filter the processed site collections in the following line Get-SPSite -Limit all <#| select -first 1 -Skip 10#> | % { $site = $_ $tn = New-Object System.Windows.Forms.TreeNode("Site: $($site.Url)") $treeview.Nodes.Add($tn) $rootWeb = $site.RootWeb analyseWeb -web $rootWeb reorder -parentNode $tn $rootWeb.Dispose() $site.Dispose() } $form.ShowDialog() | out-null
Creating a whole windows forms application from Powershell? Crazy!
Why not just use the SharePoint Manager 2010 from Codeplex? http://spm.codeplex.com/ It has this function OOTB plus many more.
Hi!
Because SPM does not show me the inheritance structure of the content type. It just shows me the content types. – Correct me if I am wrong!
regards
ingo
100% correct Ikarstein…thanks for the effort! Much appreciated.
hi Ingo,
i am trying to run your script against a sharepoint solution however it `keeps failing with the below error, have ou seen this before?
The ‘+=’ operator failed: Item has already been added. Key in dictionary: ‘0x01
2004’ Key being added: ‘0x012004’.
At line:55 char:24
+ $global:list += <<<< @{"$($ct.Id)"=$ct}
+ CategoryInfo : InvalidOperation: (System.Collections.Hashtable:
Hashtable) [], RuntimeException
+ FullyQualifiedErrorId : OperatorFailed