Get a document from an unattached SharePoint content database

Retrieving a lost document in SharePoint is easy. You go to the recycle bin and you restore it. That is, if it hasn’t been deleted more than 60 days ago. But what do you do when you need to retrieve a specific document which has been overwritten with an older version and yes, Murphy is in town… you don’t have versioning enabled?

In that case you better be having backups of the content database which contains the site where the document is stored because you need to retrieve the document directly from a backup of the content database.

Now, restoring a backup of a content database is probably not something you want to do to get a specific document because you will restore all sites in that content database to a previous state. 1 happy user vs. hundreds of angry ones… ouch! But if you don’t restore it, how are you going to get a good copy of the document?

Well, you need to restore the content database under a different name. Once it has been restored, you can use PowerShell to access it as an “unattached content database” where you can access the content as if it was attached to your web application.

The Get-SPContentDatabase cmdlet has a -ConnectAsUnattachedDatabase parameter which gives you a reference to an unattached content database.

$db = Get-SPContentDatabase -ConnectAsUnattachedDatabase -DatabaseServer SHPDB -DatabaseName "SHP_PRD_Content_MySite_RestoredCopy"

Once you have the database reference, you can use the Get-SPSite cmdlet to get your site reference from that database.

$site = Get-SPSite -ContentDatabase $db | ? {$_.Url -eq $SiteURL}

From there on, you need the web and the list where the document is stored and offcourse, the document name. With all of this information, you can get a reference to the document item in the database. Only thing left to do is to extract this item as a document.

$binary = $item.File.OpenBinary()
$stream = New-Object System.IO.FileStream(($SaveLocation + $DocName), [System.IO.FileMode]::Create)
$writer = New-Object System.IO.BinaryWriter($stream)
$writer.Write($binary)
$writer.Close()
Write-Host -ForegroundColor DarkGreen "Document succesfully retrieved and saved under $SaveLocation$DocName"

I combined everything into one convenient script which takes a number of parameters and get you the item from the database.

<#
.SYNOPSIS
    Retrieve a document from an unattached content database.

.DESCRIPTION
    Retrieve a document from an unattached content database.
	
.NOTES
    File Name: Get-DocFromUnattachedContentDB.ps1
    Author   : Bart Kuppens
    Version  : 1.1
	
.PARAMETER DBServer
    Specifies the database server where the content database is located.
	
.PARAMETER DBName
    Specifies the name of the content database.
	
.PARAMETER SiteURL
    Specifies the URL of the site collection where the document is located.

.PARAMETER WebURL
    Specifies the URL of the web where the document is located. Leave empty if the web is the root site of the site collection.

.PARAMETER ListTitle
    Specifies the title of the list where the document is located.

.PARAMETER DocName
    Specifies the name of the document.

.PARAMETER SaveLocation
    Specifies the location where the document needs to be saved.
	
.EXAMPLE
    PS > .\Get-DocFromUnattachedContentDB.ps1 -DBServer SHPDB -DBName "SHP_Temp_Mysite" -SiteURL "http://HDVWSVVS03:26100/personal/mysite" 
         -ListTitle "Documents" -DocName "MyDoc.pptx" -SaveLocation "c:\temp\"
#>
[CmdletBinding()]
param(
    [parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false,HelpMessage="Specifies the database server where the content database is located.")]
    [string]$DBServer,
    [parameter(Position=1,Mandatory=$true,ValueFromPipeline=$false,HelpMessage="Specifies the name of the content database.")]
    [string]$DBName,
    [parameter(Position=2,Mandatory=$true,ValueFromPipeline=$false,HelpMessage="Specifies the URL of the site collection where the document is located.")]
    [string]$SiteURL,
    [parameter(Position=3,Mandatory=$true,ValueFromPipeline=$false,HelpMessage="Specifies the URL of the web where the document is located.")]
    [string]$WebURL,
    [parameter(Position=4,Mandatory=$false,ValueFromPipeline=$false,HelpMessage="Specifies the title of the list where the document is located.")]
    [string]$ListTitle,
    [parameter(Position=5,Mandatory=$true,ValueFromPipeline=$false,HelpMessage="Specifies the name of the document.")]
    [string]$DocName,
    [parameter(Position=6,Mandatory=$true,ValueFromPipeline=$false,HelpMessage="Specifies the location where the document needs to be saved.")]
    [string]$SaveLocation
)

if ((Get-PSSnapin -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue) -eq $null)
{
    Write-Host "Loading SharePoint cmdlets..."
    Add-PSSnapin Microsoft.SharePoint.PowerShell
}

# Connect to the unattached content database
$db = Get-SPContentDatabase -ConnectAsUnattachedDatabase -DatabaseServer $DBServer -DatabaseName $DBName

# Get a reference to the site in the DB where the document is stored
$site = Get-SPSite -ContentDatabase $db | ? {$_.Url -eq $SiteURL}
if ($site -eq $null)
{
    Write-Host -ForegroundColor Red "Site $SiteURL was not found in the database"
    break
}

# Get a reference to the web in the site where the document is stored
if ($WebURL -eq $null)
{
    # WebUrl parameter was empty. The document will be on the rootweb of the site collection.
    $web = $site.RootWeb
}
else
{
    $web = $site.AllWebs | ? {$_.Url -eq $WebURL}
    if ($web -eq $null)
    {
        Write-Host -ForegroundColor Red "Web $WebURL was not found in the database"
        break
    }
}

# Get the list where the document is stored
$list = $web.Lists[$ListTitle]
if ($list -eq $null)
{
    Write-Host -ForegroundColor Red "List $ListTitle was not found on the web $webURL"
    break
}

# Get the document from the list
$item = $list.Items | ? {$_.Name -eq $DocName}
if ($item -eq $null)
{
    Write-Host -ForegroundColor Red "A document with the name $DocName was not found in the $ListTitle list"
    break
}

# Extract the actual document and save it to disk
$binary = $item.File.OpenBinary()
$stream = New-Object System.IO.FileStream(($SaveLocation + $DocName), [System.IO.FileMode]::Create)
$writer = New-Object System.IO.BinaryWriter($stream)
$writer.Write($binary)
$writer.Close()
Write-Host -ForegroundColor DarkGreen "Document succesfully retrieved and saved under $SaveLocation$DocName"

By Bart

Bart is a certified SharePoint consultant / architect at CTG Belgium NV with a broad professional experience in IT, a background in software development with a specialisation in Microsoft products and technologies and a solid knowledge and experience in Microsoft SharePoint Products and Technologies. He started as a COBOL developer on a mainframe environment and grew into software development for Windows platforms. Participated in projects varying from migrations of existing applications to development of Web applications and Windows applications. Became fascinated by the SharePoint 2007 platform and strongly believed in the added business value of this platform. Is since then fully committed to SharePoint and focuses on SharePoint implementations, migrations, integrations, design and coaching. Stays on top of new developments within the SharePoint technology stack and related technologies.