Remove Drop Off Libraries from Every Site

Applies To: SharePoint 2010

The other day I came across a problem with some missing features on a few of our sites. Some quick searching told me I needed to enable all my sites to use the SharePoint Server Enterprise Features. This is a good thing to do, especially if you’ve just upgraded from 2007 to 2010 or you were using Foundation or Standard Server.

So, I went to Central Administration and clicked on Upgrade and Migration and chose Enable Features on Existing Sites. I was presented with this screen:

So, I checked the box and pressed OK. It took a few hours, but then everything was good to go! Almost…

Turns out I had people asking me what this new Drop Off Library link was on their sites. A quick check showed that EVERY SITE in EVERY SITE COLLECTION in EVERY WEB APPLICATION now had the Content Organizer feature enabled and a Drop Off Library added.

So, I go to Manage Site Features I deactivate the Content Organizer and go to delete the Drop Off Library. No delete option in Library settings. Turns out you need to use something like SharePoint Manager or Powershell to allow the library to be deleted before that link will show up. Regardless, we have hundreds of sites and my sites – All of which now have an unremovable library and unnecessary feature activated.

So, time for some Powershell! I wrote a script (below) that will cycle through all the sites in all the site collections for a given Web Application and disable the DocumentRouting feature (Content Organizer) and delete the Drop Off Library. I was inspired by this forum thread and this blog post.

Additionally, I was also faced with the complication that I had actually activated this feature previously for a few sites and wanted to make sure they weren’t stripped along with everybody else. So I added an ExclusionURLs parameter. I’ll explain more about that and how the rest of the script works in a minute.

The Script

Param(
	[parameter(position=0)]
	[String]
		$WebApplicationURL,
    [parameter(position=1)]
    [Boolean]
        $AnalysisOnly = $true,
	[parameter(position=2)]
	[String[]]
		$ExclusionURLs
)

#Display Exclusion URL information
if($ExclusionURLs -and $ExclusionURLs.Count -gt 0) {
    Write-Host "Excluded URLs:" -foregroundcolor green
    $ExclusionURLs | ForEach-Object {
        Write-Host "     $_" -foregroundcolor green
    }
} else {
    Write-Host "No URL Exclusions" -foreground cyan
}

#Display Feature Information
$feature = Get-SPFeature “DocumentRouting”
Write-Host “Feature ID for Content Organizer is called $($feature.DisplayName)" -foregroundcolor cyan

if($AnalysisOnly) {
    Write-Host "ANALYSIS ONLY" -foregroundcolor red
}

#Go Through Every Site
Get-SPWebApplication $WebApplicationURL | Get-SPSite -Limit ALL | Get-SPWeb -Limit ALL | ForEach-Object {

    #Check for Exclusion
    if(!($ExclusionURLs -contains $_.URL)) {
        Write-Host "$_ | $($_.URL)" -foregroundcolor DarkCyan

        #Disable Feature if found
        if ($_.Features[$feature.ID]) {
            Write-Host “  Feature $($feature.DisplayName) Found" -foreground green
            if(!$AnalysisOnly){
                Disable-SPFeature $feature -Url $_.Url -Force -Confirm:$false
                Write-Host “  Feature $($feature.DisplayName) Disabled” -foreground magenta
            }
        } else {
            Write-Host "  Feature $($feature.DisplayName) NOT Found" -foreground yellow
        }

        #Delete Drop Off Library if found
        $list = $_.Lists["DROP OFF LIBRARY"]
        if ($list) {
            Write-Host “  List $list Found” -foregroundcolor green
            if(!$AnalysisOnly){
                $list.AllowDeletion = $true;
                $list.Update()
                $list.Delete()
                Write-Host “  List $list Deleted” -foreground magenta
            }
        } else {
            Write-Host “  Drop Off Library NOT found” -foregroundcolor yellow
        }
    }

}
Write-Host " "
Write-Host "All Done!" -foregroundcolor yellow

You can copy the above script, save it in a text file with a ps1 extension and run it from the console. Assuming you’ve named the file RemoveDropOffLibraries.ps1 you can run it in a couple of different ways:

Analysis Only:

Since I’m the cautious type, I want to know which sites are going to be affected before I actually pull the trigger. So running it with just the Web Application URL will provide you with a list of all sites. Additionally, you’ll be told if a given site has the DocumentRouting feature enabled and if a Drop Off Library was found.

Perform Actions:

If you’re comfortable with the results above, just pass the Web Application URL and $false for the AnalysisOnly parameter. This will do the same list of sites and indicate if the DocumentRouting feature is enabled and if a Drop Off Library was found. Each time the feature is found activated, it gets disabled and you’ll see a message. Additionally, each time a Drop Off Library is found, it gets deleted and you’ll see a message.

Analysis Only with Exclusions:

Exclusions allow you to pass site URLs in a comma separated list. Doing the above command ensures your exclusions are working. Just specify the Web Application URL, $true for AnalysisOnly and then 1 or more exclusion URLs separated only by a comma.

Perform Actions with Exclusions:

This uses the same rules for exclusions as above, but instead of just analyzing, it actually does the work.

Quick Tip:

If you have a lot of sites and want to be able to see the output easily, use the start-transcript and stop-transcript cmdlets like so:

start-transcript -path SomeFile.rtf
...Commands and Output...
stop-transcript

Just replace line 2 with one of the command examples from above.

 

Surely no one else will ever end up in this situation, but just in case – there ya go!

Extract Timer Job History Using PowerShell

Applies To: SharePoint 2010, PowerShell

I was tasked with finding all timer jobs that ran in a given time period. Some quick searching turned up a pretty cool solution by Glyn Clough using PowerShell. I took his script and modified it some to account for UTC times and it works great. Although I’m presenting my modified script, the bulk of the work was done by Glyn and I’m really just tweaking it a little.

The Script

Param(
	[parameter(position=0)]
	[DateTime]
		$StartTime,
	[parameter(position=1)]
	[DateTime]
		$EndTime
)

if(!$StartTime) {$StartTime = (Get-Date).Date}
if(!$EndTime) {$EndTime = (Get-Date).AddDays(1).Date}

$StartTime = $StartTime.ToUniversalTime()
$EndTime = $EndTime.ToUniversalTime()

$TZ = [System.TimeZoneInfo]::FindSystemTimeZoneById(((Get-WmiObject win32_timezone).StandardName))

Get-SPWebApplication | foreach {
	$_.JobHistoryEntries |
		where{	($StartTime -le $_.StartTime -and $_.StartTime -le $EndTime) -or
			($StartTime -le $_.EndTime -and $_.EndTime -le $EndTime) } |
		sort StartTime |
		select	JobDefinitionTitle,
			WebApplicationName,
			ServerName,
			Status,
			@{Expression={[System.TimeZoneInfo]::ConvertTimeFromUtc($_.StartTime, $TZ)};Label="Start Time"},
			@{Expression={[System.TimeZoneInfo]::ConvertTimeFromUtc($_.EndTime, $TZ)};Label="End Time"},
			@{Expression={($_.EndTime - $_.StartTime).TotalSeconds};Label="Duration (secs)"}
} | Out-GridView -Title "Timer Job History"

You can copy the above script save it in a text file with a ps1 extension and run it from the console. Assuming you’ve named the file JobHistory.ps1 you can run it in a couple of different ways:

No Parameters:

Running it this way will return the entire history for the current day starting at midnight.

Specify Start Time:

This is especially helpful if you’re just trying to find the most recent history since this will give you the full history starting at the specified date/time to now.

Specify Range:

Doing this will return all history entries for the given range. The date/time parameters can be entered in a variety of ways since powershell is converting the string to a date you can enter the date/time in a format that matches your culture/locale.

The Output

The results are funneled to a GridView which requires the Windows PowerShell Integrated Scripting Environment (ISE) to be installed. On a server this is as simple as opening Server Manager, selecting features, Add Features, then choosing the Windows PowerShell Integrated Scripting Environment and installing (This did not require a restart).

There are many benefits to using the GridView. The best is the filtering, but I also like the sorting and copy/paste functionality. I often filter on job status or sort by duration to catch problem jobs. Then I can copy those rows and paste them directly into Excel if needed.

The above script also outputs histories for every web application (And will immediately show the GridView when the first is done and then slowly add the remaining ones). This could be changed by modifying the above script and adding a parameter, but this was unnecessary for me. You can also use the GridView filter to show only the web application you need.

Obviously yours will show the WebApplicationName and ServerName without my sloppy black bars

Renaming a Web Application in SharePoint 2010

Applies To: SharePoint 2010

In getting ready to create a new web application for our SharePoint farm I realized the default web application name of “SharePoint – 80” wasn’t very descriptive and I’d like to change it. If you’re reading this, then you probably already went through all the possible settings in Central Admin just like I did only to find this isn’t an option.

Fortunately, this can all be done through Powershell very quickly:

$wapp = Get-SPWebApplication "SharePoint - 80"
$wapp.Name = "Magical Web App"
$wapp.Update()

This can be written up in a script, or you can just type the lines just like above changing the names as makes sense. To verify the update was successful just use this command:

Get-SPWebApplication "Magical Web App"

You should see your new name listed with the url of your web application:

You can also check this in Central Administration under Application Management > Manage web applications:

Everything is good to go. However, this will not change the IIS website names or application pools. This takes more work than I was willing to do and I didn’t really care about that, so you’ll have to find that information elsewhere. But if you’re like me, this should be all you need!