App_Offline – Patch, maintain & troubleshoot your SharePoint portal with class

This is pretty slick- we can add a file called App_offline.htm into the root folder of a specific SharePoint web app, and it will have the effect of trumping all other pages and processes with that Web Application. It will simply render the contents of that HTML page.

Good for planned outages e.g. patching, CU’s etc.

I came across this script from MSDN which automates the process. It spins through all the Web Applications in a given SharePoint farm and plops the App_offline.htm in their root folder. When you’re done whatever maintenance window you’re involved in, it will remove. Neato.

Credit to Brendan Griffin over at MS!:
http://blogs.technet.com/b/fromthefield/archive/2014/07/04/sharepoint-maintenance.aspx

#Load SharePoint assembly
$Assemblies = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

#Check if the script is running on MOSS 2007
If (Test-Path "C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions12"){$Mode="2007"}

#Grab all Web Apps
$WebApps = [Microsoft.SharePoint.Administration.SPWebService]::ContentService.WebApplications

#Retrieve Servers 
$Farm = [Microsoft.SharePoint.Administration.SPFarm]::Local
$SPServers = $Farm.Servers | Where {$_.Role -eq "Application"} | Foreach {$_.Name}

Foreach ($WebApp in $WebApps)
{
Foreach ($URL in $WebApp.AlternateUrls)
    {
    If ($Mode = "2007")
    {
    $WebRoot = ($WebApp.GetIisSettingsWithFallback($URL.URLZone)).Path.FullName -replace ":","$"
    }
    Else
    {
    $WebRoot = ($WebApp.GetIisSettingsWithFallback($URL.Zone)).Path.FullName -replace ":","$"
    }
    Write-Host "Setting the Holding Page for" $WebApp.Name "- Zone:" $Url.URLZone -ForegroundColor Green
    Foreach ($Server in $SPServers)
        {
        Write-Host "-Updating" $Server -ForegroundColor Green
        Copy-Item "app_offline.htm" "\$Server$Webroot"
        }
    }
}

Return SharePoint into Service

#Load SharePoint assembly
$Assemblies = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

#Check if the script is running on MOSS 2007
If (Test-Path "C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions12"){$Mode="2007"}

#Grab all Web Apps
$WebApps = [Microsoft.SharePoint.Administration.SPWebService]::ContentService.WebApplications

#Retrieve Servers 
$Farm = [Microsoft.SharePoint.Administration.SPFarm]::Local
$SPServers = $Farm.Servers | Where {$_.Role -eq "Application"} | Foreach {$_.Name}

Foreach ($WebApp in $WebApps)
{
Foreach ($URL in $WebApp.AlternateUrls)
    {
    If ($Mode = "2007")
    {
    $WebRoot = ($WebApp.GetIisSettingsWithFallback($URL.URLZone)).Path.FullName -replace ":","$"
    }
    Else
    {
    $WebRoot = ($WebApp.GetIisSettingsWithFallback($URL.Zone)).Path.FullName -replace ":","$"
    }
    Write-Host "Removing the Holding Page for" $WebApp.Name "- Zone:" $Url.URLZone -ForegroundColor Green
    Foreach ($Server in $SPServers)
        {
        Write-Host "-Updating" $Server -ForegroundColor Green
        Remove-Item "\$Server$Webrootapp_offline.htm"
        }
    }
}


PowerShell Enable Versioning in all Site Collection Lists & Libraries

Often it’s a requirement to have Versioning turned on in a SharePoint List or Library. Versioning is a list/library level attribute and there’s unfortunately no way via the Site Settings GUI to tell SharePoint at the Site Collection or Site level to always have versioning turned on when a new list or library is created..

Traditionally, If you want versioning to be turned on in each new list/library, you’d have to either:

  • Use your own library template (with versioning turned on)
  • Use feature + event handler to programmatically activate versioning on each new list

The easiest way out of those two options is probably to use your own template. To do this, create a new document library, activate versioning, then save this list as template.

When you create a new list, you will then be able to use your template and directly create a list with versioning activated.

What about cases where we don’t want to/can’t use templates and we have admins spinning up new lists/libraries and jonesing for that versioning goodness?
The following PowerShell can be used to report on, and optionally enable Versioning on all Lists and Libraries in the site collection URL it is fed.
Minor Versioning, and Major/Minor Version quantity limit toggling is also in there but commented out. To turn on those options, simply remove the # symbol from the beginning of the lines.

PowerShell Script (save as file e.g. Enable-Versioning.ps1):

Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue
$siteURL = $args[0]
$execute = $args[1]
$site = Get-SPSite($siteURL)
foreach($web in $site.AllWebs) {
Write-Host "Inspecting " $web.Title
foreach ($list in $web.Lists) {
Write-Host "Versioning enabled: " $list.EnableVersioning
$host.UI.WriteLine()
Write-Host "MinorVersioning Enabled: " $list.EnableMinorVersions
$host.UI.WriteLine()
Write-Host "EnableModeration: " $list.EnableModeration
$host.UI.WriteLine()
Write-Host "Major Versions: " $list.MajorVersionLimit
$host.UI.WriteLine()
Write-Host "Minor Versions: " $list.MajorWithMinorVersionsLimit
$host.UI.WriteLine()
if($execute -eq "execute") {
$list.EnableVersioning = $true
#if($list.BaseType -eq "DocumentLibrary") {
#$list.EnableMinorVersions = $true
#}
#$list.MajorVersionLimit = 3
#$list.MajorWithMinorVersionsLimit = 3
$list.Update()
Write-Host $list.Title " is updated"
}
}
}

Usage:
Script takes two parameters:
1. Required: Site collection URL e.g. http://mysitecollection Specifies the site collection to operate on.
2. Optional: execute Script runs in report mode only unless you add the word execute
Example 1: Run the script in report mode only (no changes effected):
    c:usersadministratordesktop.Enable-Versioning.ps1 http://mysitecollection
Example 2: Run the script in execute mode:  c:usersadministratordesktop.Enable-Versioning.ps1 http://mysitecollection execute

This script could potentially be run on an automated basis via the Windows Task Scheduler – this would let you run it on a regular basis to ensure all lists/libraries in a site collection have Versioning turned on.

 

Print all Documents in SharePoint Library PowerShell

I put together the following script to help out someone on the internets, the requirement was to print all documents in a SP library. This PowerShell iterates through a library (folders included), downloads a local copy, then prints to the default printer on the machine it is executed on.

Swap $destination, $webURL and $listUrl parameters as needed.

Fun for the whole family and keeping our paper mill workers gainfully employed!

 

######################## Start Variables ########################
$destination = "C:"
$webUrl = "https://mysharepoint/sites/sitename/"
$listUrl = "https://mysharepoint/sites/sitename/Shared%20Documents/"
##############################################################
$web = Get-SPWeb -Identity $webUrl
$list = $web.GetList($listUrl)

function ProcessFolder {
    param($folderUrl)
    $folder = $web.GetFolder($folderUrl)
    foreach ($file in $folder.Files) {
        #Ensure destination directory
        $destinationfolder = $destination + "/" + $folder.Url 
        if (!(Test-Path -path $destinationfolder))
        {
            $dest = New-Item $destinationfolder -type directory 
        }
        #Download file
        $binary = $file.OpenBinary()
        $stream = New-Object System.IO.FileStream($destinationfolder + "/" + $file.Name), Create
        $writer = New-Object System.IO.BinaryWriter($stream)
        $writer.write($binary)
        $writer.Close()
		Start-Process -FilePath ($destinationfolder + "/" + $file.Name) -Verb Print
        }
}

#Download root files
ProcessFolder($list.RootFolder.Url)
#Download files in folders
foreach ($folder in $list.Folders) {
    ProcessFolder($folder.Url)
}

Delete a SharePoint 2010 service application database for a service application that was previously removed/deleted

In this post I will explain how to delete a SharePoint 2010 service application database for a service application that was previously removed/deleted.

When you remove your service application, you may see on on the page Central Administration > Management Databases Upgrade Status that the database is still visible even though it a) is not in use anymore and/or b) has been deleted from SSMS.

You may notice in the event log:

SQL Database ‘db_name’ on SQL Server instance ‘sql_instance’ not found. Additional error information from SQL

Server is included below.

Cannot open database “db_name” requested by the login. The login failed.
Login failed for user ‘login’.

To overcome this error and remove the old DB reference, fill your zombie DB name into the following PowerShell and execute from the SharePoint PowerShell interface:

get-spdatabase | where {$_.name -eq 'db_name'} | foreach {$_.Delete()};

This will remove the DB from SharePoint’s frame of reference and clear up any related error messages. Don’t forget – if the physical DB is still in SQL Server, you will need to go into SSMS and archive/delete it as ye may so desire.

Monitor SharePoint (and general web pages) for changes with PowerShell

If you need to monitor SharePoint page content (or any other web page requiring authentication for that matter) for changes, you can consider running the following PowerShell on a periodic basis with Windows Task Scheduler. This PowerShell:

– Fires up the System.Net.WebClient object
– Uses the supplied $Username, $Password and $Domain credentials to login to the page specified in the $url parameter
– Parses the page looking for the string specified in the $Results.Contains(“my string”)
– If the string is not found, fire off an email using the the $subjectnew, $fromAddress, $smtpServerName and $toAddress parameters

         $url = "https://www.mydomain.org/default.aspx"
         $Username = "johnsmith"            
         $Password = "mypassword"   
         $Domain = "mydomain"
         $WebClient = New-Object System.Net.WebClient  
         $webclient.Headers.Add("user-agent", "Powershell webclient")
         $WebClient.credentials = New-Object System.Net.NetworkCredential -ArgumentList $Username, $Password, $Domain    
         $Results = $WebClient.DownloadString($url)
         $subjectnew = "String is missing from page $url"
         $fromAddress = "monitoring@mydomain.org"
         $smtpServerName = "smtp.mydomain.org"
         $toAddress = "admin@mydomain.org"
         $IsStringThere = $Results.Contains("my string")
                 If (!$IsStringThere){
                          # You could execute something here to log positive hit on string
                 }
                 Else{
                          Send-MailMessage –From $fromAddress –To $toAddress –Subject $subjectnew –Body "$(Get-Date) String was not found on page: $url" –SmtpServer smtp.mydomain.org 
                 }

Some notes:
– storing user credentials directly in PowerShell is generally a no-no. There’s better ways to pass in credentials but for the purpose of simplicity i’ve omitted them from this example. Use as-is at your own peril!
– this method parses the entire page HTML source output, which can be good or bad depending on what you’re trying to monitor. Carefully analyze what specific string you’re looking for before relying on this.
– clearly there is overhead to the operations involved in this. If you’re monitoring a page for defacement or such a 30 minute interval in the Windows Task Scheduler should be plenty. Use perfmon or whatever performance monitoring tool exists on your target server to ensure that you are not using up excess resources

SharePoint Content Type ID GUID’s – Parent and Child

If you are looking to work with Content Types in SharePoint programmatically, you should understand the naming conventions used to compose the ID’s.

A content type’s ID shows inheritance. This is based on string concatenation with ’00’ as the seperator. This is generally in the form ‘0x[baseID]00[GUID (new id)]00[and so on]‘.

As an example, the ID of the built-in content type Item is 0x01. When inheriting from it, an example custom content type would be 0x010100E0D3BD7003DA22419C52027ABF151.
You will notice the custom content type ID starts with the ID for Item (0x01) followed by the ’00’ separator and then the GUID assigned to this content type.To find the parent of any content type, all that is needed is to split that content types ID on the separator ’00’ and examine the inheritance chain.


Using this convention, you can determine not only what content types a content type inherits from, but at which point two content types have common ancestors.
The following figure shows the relationship of the four content types detailed in the previous diagram. In each content type, the unique portion of the content type ID is represented by blue text:

PowerShell can be used if you don’t have a development tool to look Content Type ID’s automatically. Below is a PowerShell script to get you the IDs of all content types on a site:

$site = Get-SPSite http://mysite.myfarm.com
$web = $site.RootWeb
ForEach($ctype in $web.ContentTypes){write-host $ctype.Name": "$ctype.ID}
Sample Output:

References:
Content Type ID’s – MSDN:
http://msdn.microsoft.com/en-us/library/aa543822.aspx
Content Type Element (ContentType) – Technet:
http://msdn.microsoft.com/en-us/library/aa544268.aspx
Standardize Data Management with Content Types:
http://technet.microsoft.com/en-us/magazine/2008.02.contenttypes.aspx

PowerShell – Delete all “deleted” site collections in a web application

When you delete a site collection, it actually stays kicking around for a while, as explained at http://blogs.msdn.com/b/chaks/archive/2011/06/30/sharepoint-2010-sp1-site-recycle-bin-ui-experience.aspx.

As I happened to have a lot of deleted site collections I wanted to permanently remove, I was not satisfied with having to manually grab the site collection ID’s and plunk them into the Remove-SPDeletedSite PowerShell command one-by-one.

So, below is the method to delete ALL the “deleted” site collections under a specified web application. In this case, the web application URL is http://sharepoint – replace with your own desired web app URL:

Get-SPDeletedSite -webapplication http://sharepoint | Remove-SPDeletedSite

You will be prompted to delete them one by one, if you want it to run through them all without further prompts just enter the letter “A”.

Check SharePoint 2010 anonymous permissions

Great PowerShell for checking the state of SharePoint anonymous permissions from Max Ruswell at Microsoft:

SharePoint PowerShell Script Series Part 6 – Is Anonymous Access Enabled?

Note:  This PowerShell script is tested only on SharePoint 2010

Instructions for running the script:

1. Copy the below script and save it in notepad
2. Save it with a anyfilename.ps1 extension
3. To run, copy the file to a SharePoint Server
4. Select StartMicrosoft SharePoint 2010 ProductsSharePoint 2010 Management Shell
5. Browse to directory holding the copied script file
6. Run the script: .anyfilename.ps1 (assuming anyfilename is the name of the file)

<# ==============================================================
//
// Microsoft provides programming examples for illustration only,
// without warranty either expressed or implied, including, but not
// limited to, the implied warranties of merchantability and/or
// fitness for a particular purpose.
//
// This sample assumes that you are familiar with the programming
// language being demonstrated and the tools used to create and debug
// procedures. Microsoft support professionals can help explain the
// functionality of a particular procedure, but they will not modify
// these examples to provide added functionality or construct
// procedures to meet your specific needs. If you have limited
// programming experience, you may want to contact a Microsoft
// Certified Partner or the Microsoft fee-based consulting line at
// (800) 936-5200.
//
// For more information about Microsoft Certified Partners, please
// visit the following Microsoft Web site:
// </span><a href="https://partner.microsoft.com/global/30000104"><span style="font-size: x-small;">https://partner.microsoft.com/global/30000104</span></a>
<span style="font-size: x-small;">//
// Author: Russ Maxwell (russmax@microsoft.com)
//
// ---------------------------------------------------------- #></span>
<h3></h3>
<span style="font-size: x-small;">[Void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") </span>
<h3></h3>
<span style="font-size: x-small;">Start-SPAssignment -Global</span>
<h3></h3>
<span style="font-size: x-small;">######################################
##Creating and Returning a DataTable##
######################################
function createDT()
{
###Creating a new DataTable###
$tempTable = New-Object System.Data.DataTable

##Creating Columns for DataTable##
$col1 = New-Object System.Data.DataColumn("Anonymous Access")
$col2 = New-Object System.Data.DataColumn("Level")
$col3 = New-Object System.Data.DataColumn("URL")
$col4 = New-Object System.Data.DataColumn("Configured ListLib")

###Adding Columns for DataTable###
$tempTable.columns.Add($col1)
$tempTable.columns.Add($col2)
$tempTable.columns.Add($col3)
$tempTable.columns.Add($col4)

return ,$tempTable
}</span>
<h3></h3>
<span style="font-size: x-small;">#####################################
##Check WebApp for Anonymous Access##
#####################################
function checkwebappAnon()
{
$webAnon = $site.IISAllowsAnonymous.tostring()
$tempanonCheck = 0;
if ($webAnon -eq "true")
{
#Add a row to DataTable
$row = $dTable.NewRow()
$row["Anonymous Access"] = "Enabled"
$row["Level"] = "WebApplication"
$row["URL"] = $site.WebApplication.Name
$dTable.rows.Add($row)
}

}</span>
<h3></h3>
<span style="font-size: x-small;">######################################
##Check the Site for Anonymous Access#
######################################
function checksiteAnon()
{
$tempanonCheck = 0
$checkWeb = $web.AllowAnonymousAccess.tostring()
$checkWebState = $web.AnonymousState.tostring()
$webMask = $web.AnonymousPermMask64.tostring()
Write-Host
Write-Host "Checking how Anonymous is set up on site: " $web.Url -ForegroundColor Magenta

if(($checkWeb -eq "True") -and ($checkWebState -eq "On"))
{
#Add a row to DataTable#
$row = $dTable.NewRow()
$row["Anonymous Access"] = "Enabled"
$row["Level"] = "Site Level: Entire WebSite"
$row["URL"] = $web.Url.tostring()
$dTable.rows.Add($row)
$tempResult = 1
}

elseif(($checkWeb -eq "False") -and ($checkWebState -eq "Enabled") -and ($webMask -eq "Open"))
{
#Add a row to DataTable#
$row = $dTable.NewRow()
$row["Anonymous Access"] = "Enabled"
$row["Level"] = "Site Level: Lists and Libraries"
$row["URL"] = $web.Url.tostring()
$dTable.rows.Add($row)
$tempResult = 2
}

else
{
$tempResult = 3
}

return $tempResult
}</span>
<h3></h3>
<span style="font-size: x-small;">############################################
##Check ListLibraries for Anonymous Access#
############################################
function checklistAnon()
{
###Checking each list and library for anonymous access###
$lists = $web.lists
$count1 = $lists.count
$hasAnon = 0

Write-Host "Checking " $lists.count " listslibaries for Anonymous Access" -ForegroundColor Magenta

###Setting String Vars###
$defMask1 = "OpenWeb"
$defMask2 = "EmptyMask"
$defTax = "TaxonomyHiddenList"

foreach($list in $lists)
{
$listUrl = $web.url + "/" + $list.Title
$listMask = $list.AnonymousPermMask.tostring()
$tax = $list.Title.ToString()

##Checking List eventhough Anonymous Access was disabled at SPWeb Level##
if(($webResult -eq '3') -and ($defTax.CompareTo($tax) -ne '0'))
{
if($listMask.CompareTo($defMask2) -ne '0')
{
if($listMask.CompareTo($defMask1) -eq '0')
{
#Anonymous Access is Enabled but not Configured on listlibrary#
$row = $dTable.NewRow()
$row["Anonymous Access"] = "Enabled"
$row["Level"] = "ListLibrary"
$row["URL"] = $listUrl
$row["Configured ListLib"] = "No"
$dTable.rows.Add($row)
$hasAnon++
}
else
{
#Anonymous Access Enabled and Configured on listlibrary#
$row = $dTable.NewRow()
$row["Anonymous Access"] = "Enabled"
$row["Level"] = "ListLibrary"
$row["URL"] = $listUrl
$row["Configured ListLib"] = "Yes"
$dTable.rows.Add($row)
$hasAnon++
}
}
}

elseif(($webResult -eq '2') -and ($defTax.CompareTo($tax) -ne '0'))
{
if(($listMask.CompareTo($defMask2) -ne '0') -and ($listMask.CompareTo($defMask1) -ne '0'))
{
#Anonymous Access Enabled and Configured on listlibrary#
$row = $dTable.NewRow()
$row["Anonymous Access"] = "Enabled"
$row["Level"] = "ListLibrary"
$row["URL"] = $listURL
$row["Configured ListLib"] = "Yes"
$dTable.rows.Add($row)
$hasAnon++
}
}
$count1--
if($count1 % '10' -eq '0')
{
Write-Host "Total # of listslibraries left to check: " $count1 -ForegroundColor DarkYellow
}
}
Write-Host
Write-Host "Total # of listslibraries with Anonymous Access Enabled: " $hasAnon -ForegroundColor Cyan
}
</span>
<h3></h3>
<span style="font-size: x-small;">########################
###Script Starts Here###
########################
$output = Read-Host "Enter a location for the output file (For Example: c:logs)"
$filename = Read-Host "Enter a filename"
$url = Read-Host "Please enter the URL of desired site collection and press enter"</span>
<h3></h3>
<span style="font-size: x-small;">###Getting a new DataTable###
[System.Data.DataTable]$dTable = createDT</span>
<h3></h3>
<span style="font-size: x-small;">###Getting Site Collection###
$site = Get-SPSite $url</span>
<h3></h3>
<span style="font-size: x-small;">###Checking if WebApp has Anonymous set###
checkwebappAnon</span>
<h3></h3>
<span style="font-size: x-small;">###Gathering web collection###
$webs = $site.Allwebs
$count = $webs.Count
Write-Host "Checking for Anonymous Access on " $count " Sites" -ForegroundColor Magenta</span>
<h3></h3>
<span style="font-size: x-small;">foreach($web in $webs)
{
$webResult = 0
###calling function to check anonymons on spweb###
$webResult = checksiteAnon

if(($webResult -eq '2') -or ($webResult -eq '3'))
{
Write-Host "Checking for Anonymous Access on List and Libraries" -ForegroundColor Magenta
###calling function to check anonymons on lists and libs###
checklistAnon
}

$count--

if($count -ne '0')
{
Write-Host
Write-Host "Total # of sites left to check: " $count -ForegroundColor DarkYellow
}

else{Write-Host "Operation Completed" -ForegroundColor DarkYellow}
}</span>
<h3></h3>
<span style="font-size: x-small;">if($dTable -ne $null)
{
$name = $output + "" + $filename + ".csv"
$dTable | Export-Csv $name -NoTypeInformation
Write-Host "Anonymous Access was detected" -ForegroundColor Green
Write-Host "Log File Created: " $name
}
else
{
Write-Host "Anonymous Access is Disabled for the entire Site Collection" -ForegroundColor Green
Write-Host "No Log File Created" -ForegroundColor Green
}

Stop-SPAssignment -Global

Delete All Items from a SharePoint List – PowerShell

In experimenting with the upper limit thresholds of just how many items you can create in a list, I ran into a little problem in that the web UI went mental and would cause IE to crash (this was with 21,000 list items). Trying to access the files via Webdav was equally non-workable. I needed to get rid of these list items to even be able to roll back the crazy test.

PowerShell to the rescue. Just replace the “http://serverurl” and “ENTER LIST NAME HERE” values with your web URL and List Name.

[System.Reflection.Assembly]::Load("Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c")
[System.Reflection.Assembly]::Load("Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c")
[System.Reflection.Assembly]::Load("Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c")
[System.Reflection.Assembly]::Load("System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")

# "Enter your site URL here"
$SITEURL = "http://serverurl"

$site = new-object Microsoft.SharePoint.SPSite ( $SITEURL )
$web = $site.OpenWeb()
"Web is : " + $web.Title

# Enter name of the List below
$oList = $web.Lists["ENTER LIST NAME HERE"];

"List is :" + $oList.Title + " with item count " + $oList.ItemCount

$collListItems = $oList.Items;
$count = $collListItems.Count - 1

for($intIndex = $count; $intIndex -gt -1; $intIndex--)
{
        "Deleting : " + $intIndex
        $collListItems.Delete($intIndex);
} 

Note that the assembly references at the top refer to SharePoint 2007 assemblies – not to worry, settings in the out-of-the-box SP 2010 Web.config will automagically bump up the references to the current SharePoint 2010 versions – there’s no burning need to go around adjusting assembly references if you come across PoweShell examples like this.

  • 1
  • 2