Here’s another blog post to file in the “I’ll probably never need it, but you never know” bucket of things you’ve seen from me.
Admittedly, I don’t get to spend as much time as I’d like playing with PowerShell and assembling scripts. So when the opportunity to whip-up a “quick hit” script comes along, I usually jump at it.
The Situation
I feel very fortunate to have made so many friends in the SharePoint community over the last several years. One friend who has been with me since the beginning (i.e., since my first presentation at the original SharePoint Saturday Ozarks) is Kirk Talbot. Kirk has become something of a “regular” on the SharePoint Saturday circuit, and many of you may have seen him at a SharePoint Saturday event someplace in the continental United States. To tell you the truth, I’ve seen Kirk as far north as Michigan and as far south as New Orleans. Yes, he really gets around.
Kirk and I keep up fairly regular correspondence, and he recently found himself in a situation where he needed to determine which objects (in a SharePoint site collection) were associated with a handful of GUIDs. Put a different way: Kirk had a GUID (for example, 89b66b71-afc8-463f-b5ed-9770168996a6) and wanted to know – was it a web? A list? A list item? And what was the identity of the item?
PowerShell to the Rescue
I pointed Kirk to a script I had previously written (in my Finding Duplicate GUIDs in Your SharePoint Site Collection post) and indicated that it could probably be adapted for his purpose. Kirk was up to the challenge, but like so many other SharePoint administrators was short on time.
I happened to find myself with a bit of free time in the last week and was due to run into Kirk at SharePoint Saturday Louisville last weekend, so I figured “what the heck?” I took a crack at modifying the script I had written earlier so that it might address Kirk’s need. By the time I was done, I had basically thrown out my original script and started over. So much for following my own advice.
The Script
The PowerShell script that follows is relatively straightforward in its operation. You supply it with a site collection URL and a target object GUID. The script then searches through the webs, lists/libraries, and list items of the site collection for an object with an ID that matches the GUID specified. If it finds a match, it reports some information about the matching object.
A sample run of the script appears below. In the case of this example, a list item match was found in the target site collection for the supplied GUID.
This script leverages the SharePoint object model directly, so it can be used with either SharePoint 2007 or SharePoint 2010. Its search algorithm is relatively efficient, as well, so match results should be obtained in seconds to maybe minutes – not hours.
<# .SYNOPSIS FindObjectByGuid.ps1 .DESCRIPTION This script attempts to locate a SharePoint object by its unique ID (GUID) within a site collection. The script first attempts to locate a match by examining webs; following webs, lists/libraries are examined. Finally, individual items within lists and libraries are examined. If an object with the ID is found, information about the object is reported back. .NOTES Author: Sean McDonough Last Revision: 27-July-2012 .PARAMETER SiteUrl The URL of the site collection that will be searched .PARAMETER ObjectGuid The GUID that identifies the object to be located .EXAMPLE FindObjectByGuid -SiteUrl http://mysitecollection.com -ObjectGuid 91ce5bbf-eebb-4988-9964-79905576969c #> param ( [string]$SiteUrl = "$(Read-Host 'The URL of the site collection to search [e.g. http://mysitecollection.com]')", [Guid]$ObjectGuid = "$(Read-Host 'The GUID of the object you are trying to find [e.g. 91ce5bbf-eebb-4988-9964-79905576969c]')" ) function FindObject($startingUrl, $targetGuid) { # To work with SP2007, we need to go directly against the object model Add-Type -AssemblyName "Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" # Grab the site collection and all webs associated with it to start $targetSite = New-Object Microsoft.SharePoint.SPSite($startingUrl) $matchObject = $false $itemsTotal = 0 $listsTotal = 0 $searchStart = Get-Date Clear-Host Write-Host ("INITIATING SEARCH FOR GUID: {0}" -f $targetGuid) # Step 1: see if we can find a matching web. $allWebs = $targetSite.AllWebs Write-Host ("`nPhase 1: Examining all webs ({0} total)" -f $allWebs.Count) foreach ($spWeb in $allWebs) { $listsTotal += $spWeb.Lists.Count if ($spWeb.ID -eq $targetGuid) { Write-Host "`nMATCH FOUND: Web" Write-Host ("- Web Title: {0}" -f $spWeb.Title) Write-Host ("- Web URL: {0}" -f $spWeb.Url) $matchObject = $true break } $spWeb.Dispose() } # If we don't yet have match, we'll continue with list iteration if ($matchObject -eq $false) { Write-Host ("Phase 2: Examining all lists and libraries ({0} total)" -f $listsTotal) $allWebs = $targetSite.AllWebs foreach ($spWeb in $allWebs) { $allLists = $spWeb.Lists foreach ($spList in $allLists) { $itemsTotal += $spList.Items.Count if ($spList.ID -eq $targetGuid) { Write-Host "`nMATCH FOUND: List/Library" Write-Host ("- List Title: {0}" -f $spList.Title) Write-Host ("- List Default View URL: {0}" -f $spList.DefaultViewUrl) Write-Host ("- Parent Web Title: {0}" -f $spWeb.Title) Write-Host ("- Parent Web URL: {0}" -f $spWeb.Url) $matchObject = $true break } } if ($matchObject -eq $true) { break } } $spWeb.Dispose() } # No match yet? Look at list items (which includes folders) if ($matchObject -eq $false) { Write-Host ("Phase 3: Examining all list and library items ({0} total)" -f $itemsTotal) $allWebs = $targetSite.AllWebs foreach ($spWeb in $allWebs) { $allLists = $spWeb.Lists foreach ($spList in $allLists) { try { $listItem = $spList.GetItemByUniqueId($targetGuid) } catch { $listItem = $null } if ($listItem -ne $null) { Write-Host "`nMATCH FOUND: List/Library Item" Write-Host ("- Item Name: {0}" -f $listItem.Name) Write-Host ("- Item Type: {0}" -f $listItem.FileSystemObjectType) Write-Host ("- Site-Relative Item URL: {0}" -f $listItem.Url) Write-Host ("- Parent List Title: {0}" -f $spList.Title) Write-Host ("- Parent List Default View URL: {0}" -f $spList.DefaultViewUrl) Write-Host ("- Parent Web Title: {0}" -f $spWeb.Title) Write-Host ("- Parent Web URL: {0}" -f $spWeb.Url) $matchObject = $true break } } if ($matchObject -eq $true) { break } } $spWeb.Dispose() } # No match yet? Too bad; we're done. if ($matchObject -eq $false) { Write-Host ("`nNO MATCH FOUND FOR GUID: {0}" -f $targetGuid) } # Dispose of the site collection $targetSite.Dispose() Write-Host ("`nTotal seconds to execute search: {0}`n" -f ((Get-Date) - $searchStart).TotalSeconds) # Abort script processing in the event an exception occurs. trap { Write-Warning "`n*** Script execution aborting. See below for problem encountered during execution. ***" $_.Message break } } # Launch script FindObject $SiteUrl $ObjectGuid
Conclusion
Again, I don’t envision this being something that everyone needs. I want to share it anyway. One thing I learned with the “duplicate GUID” script I referenced earlier is that I generally underestimate the number of people who might find something like this useful.
Have fun with it, and please feel free to share your feedback!
Additional Reading and Resources
- Event: SharePoint Saturday Ozarks
- Twitter: Kirk Talbot (@kctElgin)
- Post: Finding Duplicate GUIDs in Your SharePoint Site Collection
- Event: SharePoint Saturday Louisville