Restore a SQL Database Using SQL Server Management Objects (SMO) and PowerShell

At some point in your career with SQL, there may come a time to perform a restore of the database (and maybe transaction logs depending on your situation). Given that we covered how to back up a SQL database, we now need to take a look at performing a restore of the database to recover data which was deleted due to some craziness with a sysadmin.

What you will see in the following code examples will be some familiar things that I used when it came to performing a backup of the SQL database. So don’t be surprised if you see something and are thinking that this looks just like what I did with a backup!

So with that, lets load up those assemblies!

#region SQL Assemblies
add-type -AssemblyName "Microsoft.SqlServer.ConnectionInfo, 
Version=10.0.0.0,Culture=neutral, PublicKeyToken=89845dcd8080cc91" -ErrorAction Stop
add-type -AssemblyName "Microsoft.SqlServer.Smo, 
Version=10.0.0.0, Culture=neutral,PublicKeyToken=89845dcd8080cc91" -ErrorAction Stop
add-type -AssemblyName "Microsoft.SqlServer.SMOExtended, 
Version=10.0.0.0,Culture=neutral, PublicKeyToken=89845dcd8080cc91" -ErrorAction Stop
add-type -AssemblyName "Microsoft.SqlServer.SqlEnum, 
Version=10.0.0.0,Culture=neutral, PublicKeyToken=89845dcd8080cc91" -ErrorAction Stop
add-type -AssemblyName "Microsoft.SqlServer.Management.Sdk.Sfc, 
Version=10.0.0.0,Culture=neutral, PublicKeyToken=89845dcd8080cc91" -ErrorAction Stop
#endregion SQL Assemblies

Now we can connect to a SQL server and verify the connection is good by checking out the object and ensuring it actually has data in it.

#SQL Connection
$sqlServer = New-Object Microsoft.SqlServer.Management.Smo.Server `
-ArgumentList 'boe-pc\shire'
$sqlServer

image

I also want to make it easier to get some specific types that will be used with the restores.

#Frequently used types
$Action = 'Microsoft.SqlServer.Management.Smo.RestoreActionType' -as [type]
$DeviceType = 'Microsoft.SqlServer.Management.Smo.DeviceType' -as [type]

The next step is to determine the backup directory on the SQL server. This way I have a good idea as to where the files are at.

#Find backup directory
$backupDir = $sqlServer.BackupDirectory

image

Perfect, now we can see what exists in the backup directory and can use one of those files in the restore process.

image

Let’s find a table to ‘accidently’ wipe out. This one (Store) looks good to me.

$sqlServer.Databases['AdventureWorks'].Tables | Where {
    $_.Name -eq 'Store'
} | Format-Table Name, ID,State -AutoSize

image

Now time to kiss it goodbye!

($sqlServer.Databases['AdventureWorks'].Tables | Where {
    $_.Name -eq 'Store'
}).Drop()

image

I actually had issues dropping this due to a Foreign Key Constraints on this table. In order to accomplish this, I had to run the following TSQL statement:

ALTER TABLE Sales.Customer DROP CONSTRAINT FK_Customer_Store_StoreID

Double check that the table has been removed.

image

Now lets get the full paths to each of the backup files.

$DBBackup = Get-Item ("{0}\AdventureWorks_20131009.bak" -f $backupDir)
$TLogBackup = Get-Item ("{0}\AdventureWorks_20131009.trn" -f $backupDir)

Note: If running this against a remote SQL server, you will first need the UNC path to actually get the files, but then you must revert back to a local path as the restore process will throw an error if specifying UNC paths.

Now I will create a SMO.Restore object and reference some extra properties that will be used in the restoral of the database.

$restore = New-Object Microsoft.SQLServer.Management.Smo.Restore -Property @{
    Action = $Action::Database
    Database = 'AdventureWorks'
    ReplaceDatabase = $True
    NoRecovery = $False
}

 

Notice in this case that I set NoRecovery to $False. This means that after I restore this database file, it will be ready for use and will not allow me to restore the transaction log backup.

Like before with the backup, I have to created a device object that will be used as part of the restoral process.

$Device = New-Object Microsoft.SQLServer.Management.Smo.BackupDeviceItem -ArgumentList $DBBackup.fullname,'File'
$restore.Devices.Add($Device)

Now it is time for the restore. I actually had an error occur during my restore attempt stating that the database was still in use. To get around this, I made sure to kill all processes to that database.

$sqlServer.KillAllProcesses('AdventureWorks')

And now I can make the restore happen!

$restore.SQLRestore($sqlServer)

I need to refresh the list of tables and then I can verify if the Store table exists again.

$sqlServer.Databases['AdventureWorks'].Tables.Refresh()
$sqlServer.Databases['AdventureWorks'].Tables | Where {
    $_.Name -eq 'DatabaseLog'
} | Format-Table Name, ID,State -AutoSize

image

Now I will repeat this process to restore the database but instead set the NoRecovery property to $True to allow the restoral of the transaction log backup.

#Find backup directory
$backupDir = $sqlServer.BackupDirectory
# If working remotely, get UNC path to locate file; but then revert back to local path as errors may occur during restore!
$DBBackup = Get-Item ("{0}\AdventureWorks_20131009.bak" -f $backupDir)
$TLogBackup = Get-Item ("{0}\AdventureWorks_20131009_tlog.trn" -f $backupDir)

## Database Restore
#Create the Restore object
# http://technet.microsoft.com/en-us/library/microsoft.sqlserver.management.smo.restore.aspx
$restore = New-Object Microsoft.SQLServer.Management.Smo.Restore -Property @{
    Action = $Action::Database
    Database = 'AdventureWorks'
    ReplaceDatabase = $True
    NoRecovery = $True
}

#Create the Device that will be used for Restore
# http://technet.microsoft.com/en-us/library/microsoft.sqlserver.management.smo.backupdeviceitem.aspx
$Device = New-Object Microsoft.SQLServer.Management.Smo.BackupDeviceItem -ArgumentList $DBBackup.fullname,'File'
$restore.Devices.Add($Device)
$restore.SQLRestore($sqlServer)

Now the AdventureWorks database is in a ‘Restoring’ State. In order to get an accurate representation of the database, I use the following line of code to refresh the object.

$sqlServer.Databases['AdventureWorks'].Refresh()

image

image

This is where we can now proceed with the transaction log restore and making sure that the NoRecovery property is set to $False.

## T-Log Restore
$restore = New-Object Microsoft.SQLServer.Management.Smo.Restore -Property @{
    Action = $Action::Log
    Database = 'AdventureWorks'
    ReplaceDatabase = $True
    NoRecovery = $False
}

#Create the Device that will be used for Restore
$Device = New-Object Microsoft.SQLServer.Management.Smo.BackupDeviceItem -ArgumentList $TLogBackup.fullname,$DeviceType::File
$restore.Devices.Add($Device)
$restore.SQLRestore($sqlServer)

And the database is now back and available to use!

image

image

There you have it! I was able to do a restore of my database as well as performing a restore on both a database and its transaction log backup without much issue at all!

Posted in powershell, SQL | Tagged , , , , | 1 Comment

PowerShell 4.0 Now Available for Download

That’s right, Windows Management Framework 4.0 is now available to download for down-level OS’s. Some important things to know regarding this:

New Features and Updated Versions

  • Windows PowerShell
  • Windows PowerShell Integrated Scripting Environment (ISE)
  • Windows PowerShell Web Services (Management OData IIS Extension)
  • Windows Remote Management (WinRM)
  • Windows Management Infrastructure (WMI)
  • Windows PowerShell Desired State Configuration (DSC)

Supported Down-level Operating Systems (Already available with Windows 8/8.1 and Windows Server 2012 R2)

  • Windows 7 SP1
  • Windows 7 Embedded
  • Windows 2008 R2 SP1
  • Windows Server 2012

Unsupported Platforms (Installing on these platforms could cause serious issues)

  • System Center 2012 Configuration Manager (not including SP1)
  • System Center Virtual Machine Manager 2008 R2 (including SP1)
  • Microsoft Exchange Server 2013, Microsoft Exchange Server 2010 and Microsoft Exchange Server 2007
  • Microsoft SharePoint 2013 and Microsoft SharePoint 2010
  • Windows Small Business Server 2011Standard

.Net 4.5 Needs to be installed!!!!

There are issues that if you do not have .Net 4.5 installed on your system and attempt to load WMF 4.0, it will silently fail and will still continue to load 3.0 instead (you can verify by running $PSVersionTable to see.

Download Here

http://go.microsoft.com/fwlink/?LinkId=293881

Enjoy!

Posted in News, powershell | Tagged , | Leave a comment

Using the ESPN API with PowerShell

Being a sports fan, I wanted to see what the ESPN API (just started in March 2012) had to offer (not much unfortunately unless you are a premium member) and make use of what PowerShell has to offer to pull back some data from those APIs. Using what useful APIs are available, I will show you how you can simply pull some data from ESPN and return it into a UI that you can then select from and open via your default web browser.

Get Your API!

The ESPN API is only available to those who have an API key available. First go out to http://developer.espn.com/ and register for the API.

After a minute or so you should have access to your API key.

image

Now we can start playing around with what we can actually query.

I mentioned before the lack of things you can query for because this is just for public use. Unless you have bigger aspirations, this is as good as it is going to get. You will be able to locate specific IDs for teams, athletes, etc… but will not be able to generate rosters, stats or anything else of the sort.

You can find the possible things to query here: http://developer.espn.com/docs and dig deeper into each area to actually see what methods are usable as well as the URI Parameters.

You can even build out your own web request string here: http://developer.espn.com/io-docs which will allow you to add your own parameters and then just copy that string and use it in your own request!

Moving on from that, I am going to take a look at the headlines from the day in the Green Bay Packers. But before I can do that, I need to figure out what their team ID is. So with that I will perform a query to get all of the NFL teams IDs.

#First figure out the team IDs
$team = Invoke-RestMethod `
'http://api.espn.com/v1/sports/football/nfl/teams/?apikey=<insert your own API>'

#Create a hash table to associate ID with Team
$teams = @{}
$team.sports.leagues.teams | ForEach {
    $teams[$_.Name] = $_.id
}

#Look for the Green Bay Packers
$teams['Packers']

image

image

Knowing that the team ID for the Packers is 9, I can now look at their latest headlines.

$packers = Invoke-RestMethod `
'http://api.espn.com/v1/now/?leagues=nfl&teams=9&apikey='<insert api>'
$packers.feed | ForEach {
    [pscustomobject]@{
        Headline = $_.headline
        Description = $_.description
        Modified = [datetime]$_.lastModified
        Type = $_.type
        Source = $_.source
        Link = $_.links.web.href
    }
} | Out-GridView -PassThru | ForEach {Start-Process $_.link}

 

I make use of Out-Gridview with the –PassThru parameter which will allow me to select one item from the UI and then output the object into the pipeline which then will open of the link in my default browser.

image

image

I have to use a ForEach because Start-Process doesn’t know how to handle the pipeline input of the Link property of the PSObject custom object.

The last thing is that I want to check out the current 25 news events going on in the NFL using the same approach as before.

#Get the latest news across the NFL
$news = Invoke-RestMethod `
'http://api.espn.com/v1/sports/football/nfl/news/headlines/top/?insider=no&limit=25&apikey=<insert api>'
$news.headlines | ForEach {
    [pscustomobject]@{
        Headline = $_.headline
        Description = $_.description
        Modified = [datetime]$_.lastModified
        Type = $_.type
        Source = $_.source
        Link = $_.links.web.href
    }
} | Out-GridView -PassThru | ForEach {Start-Process $_.link}

Same output as before with the UI made from Out-GridView and then opening up the same site (if I chose something to view).

image

So that is really that for working with the ESPN API unless you have a better account. For what its worth, you at least get some access to the headlines so you could have your own feed going. But all of the stuff that I really would like such as teams and accounts is just not available.

Posted in powershell | Tagged , , | 1 Comment

Guest Post on Hey, Scripting Guy! Talking PInvoke and PowerShell

Today my Hey, Scripting Guy! guest blog goes live. I am talking about using Pinvoke with PowerShell to handle the removal of files which may be locked by a process.

Check it out and let me know what you think!

Weekend Scripter: Use PowerShell and Pinvoke to Remove Stubborn Files

Posted in News, powershell | Tagged , , , | Leave a comment

Fix Duplicate WSUS ClientIDs Using PowerShell

A common issue when using a ‘template’ or an OS image that hasn’t been sysprepped is that each client that has the same clientID will appear and disappear from the WSUS console (only 1 client will appear at a time).

A solution to this involves stopping the windows update service (wuauserv), then proceed to remove some Windows Update registry keys such as the following:

HKLM\Software\Microsoft\Windows\CurrentVersion\WindowsUpdate

  • SusClientId
  • SusClientIdValidation
  • PingID
  • AccountDomainSid

HKLM\Software\Microsoft\Windows\CurrentVersion\WindowsUpdate

  • LastWaitTimeout
  • DetectionStartTimeout
  • NextDetectionTime
  • AUState

Following that, you can remove the SoftwareDistribution folder on the system and then restart the Windows Update service.

Once that has been completed, you need to run the following command to force a check-in to the WSUS server and receive a new clientID and download required updates.

wuauclt /resetauthorization /detectnow command

In reviewing some of my old scripts and functions, I found this function that I have been wanting to put out to the community and always forgot to do so.

Invoke-WSUSClientIDFix allows you to run all of these fix actions against any system, local or remote.  This function will first use Stop-Service to stop the Windows Update service on the local or remote system.

Because Remoting may not be enabled in a given environment yet, the registry modifications (local or remote) is done via the [Microsoft.Win32.Registry] type that utilizes the OpenRemoteBaseKey() method to make the connection and then proceeds to remove the wsus client registry values.

Write-Verbose ("{0}: Making remote registry connection to {1} hive"`
 -f $Computer, $reghive)
$remotereg = [microsoft.win32.registrykey]::OpenRemoteBaseKey(`
$reghive,$Computer)
Write-Verbose ("{0}: `
Connection to WSUS Client registry keys" -f $Computer)
$wsusreg1 = $remotereg.OpenSubKey(`
'Software\Microsoft\Windows\CurrentVersion\WindowsUpdate',$True)
$wsusreg2 = $remotereg.OpenSubKey(`
'Software\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update',$True)

#...

If (-Not [string]::IsNullOrEmpty($wsusreg1.GetValue('SusClientId'))) {
    If ($PScmdlet.ShouldProcess("SusClientId","Delete Registry Value")) {
        $wsusreg1.DeleteValue('SusClientId')
    }
}

#...

Following that, I use Remove-Item to clean out the SoftwareDistribution folder. I use Start-Service to start up the Windows Update service prior to the last command.  I then make use of the Win32_Process WMI class and its Create() method to spawn a remote process to run the wuauclt /detectnow /resetauthoriation command to check back into the WSUS server.

After dot sourcing the function, I can run it against a system/s to perform the client ID fix on the client so it will communicate properly with the WSUS server.

Invoke-WSUSClientIDFix -Verbose

image

Download Invoke-WSUSClientIDFix

http://gallery.technet.microsoft.com/scriptcenter/Invoke-WSUSClientFix-fd29e1a8/file/98072/1/Invoke-WSUSClientFixID.ps1

Give it a run and let me know what you think!

Posted in powershell, scripts, WSUS | Tagged , , , , | 6 Comments