Review SQL Server 2008 Administration with Windows Powershell

Microsoft SQL Server 2008 Administration with Windows PowerShell I recommend this book to all database administrators who still have not jumped in and executed their first PowerShell command.  I know of several DBAs who for one excuse reason or another, keep postponing their exposure to the next generation command line shell.  This volume makes a good first PowerShell book for DBAs.  It covers the basics of the language with enough examples to get you going and good coverage of what is possible when combined with MS SQL 2008.

The first ten chapters go over specifics of the language, programming syntax, and how to interact with different areas of the operating system.  The following eleven chapters demonstrate with code samples, how integrated are MS SQL 2008 and PowerShell.  I have found that many of the examples in this book also apply to MS SQL 2005.  My favorite chapter is 15 “Building SQL Server Inventory” because the authors provide a working solution to a common problems DBA have when managing many database servers.

To those DBAs who still have not jumped in, do yourself a favor and read this book.

Monitoring MS SQL Jobs with PowerShell

PROBLEM: You manage many MS SQL servers and need an easy way to review jobs that have failed.

SOLUTION: I will show you one way to accomplish this task with results displaying on the screen or to a file. To make your life easier, I recommend you download & install PowerGUI from Quest Software. This application comes with a script editor that will enhance your PowerShell development experience.

Go ahead and open a new session of PowerShell. You can type or copy and paste the code from our initial three lines of code. We will start by loading the SMO assembly & creating an instance of the server object. On the third and final line of code, we get a collection of all jobs by accessing the SQL Server agent on the server. We then pipe the resulting object and look for all jobs which are enabled that have failed.

[reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")|out-null
$srv=New-Object "Microsoft.SqlServer.Management.Smo.Server" "TUIRA"
$srv.jobserver.jobs|where-object {$_.IsEnabled -eq $TRUE -and `
    $_.LastRunOutcome -eq "Failed"
}

You will notice the result not being in a desirable format, especially when you have many jobs. We will use the information from one of the jobs to pick the specific properties we want in our report and display them in a table format. Lets pick the Parent, Category, Description, LastRunDate, LastRunOutcome, & Name properties for our next result.
On your PS session screen, hit the up key and you should get the last line of commands we executed. Hit the left arrow key to modify the command as follow

$srv.jobserver.jobs|where-object {$_.isenabled -eq $TRUE}|Format-Table `
    Parent, Category, Name, LastRunDate, LastRunOutcome, Description `
    -Autosize

Now we have a result we can save to a file or print. But before doing that, we’ll expand this script to retrieve the jobs from multiples servers. Lets go ahead and open a Notepad session and enter the name of a few MS SQL servers you manage, one name per line, and save it with the file name serverlist.txt. I saved mine in C: for simplicity. Now, we just need to enclose our previously executed commands in a loop.

[reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")|out-null
foreach($svr in get-content C:serverlist_prd.txt) {
    $srv=New-Object "Microsoft.SqlServer.Management.Smo.Server" "$svr"
    $srv.jobserver.jobs|where-object {$_.isenabled -eq $TRUE}| `
        Format-Table Parent, Category, Name, LastRunDate, `
        LastRunOutcome, Description -Autosize
}

I find this looping syntax very helpful whenever I need to execute code against multiple servers. The result from this modified version of the original code will leave a blank space between each server or iteration of the code. We’ll solve that with a variable in the next and final version of the script which includes the code to save the report to a file.

CLEAR
Set-Content -Path "C:TempMonitorJobs_LowerEnvironments.txt" -Value " "
[reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")|out-null

foreach($svr in get-content C:tempserverlist.txt) {
    $srv=New-Object "Microsoft.SqlServer.Management.Smo.Server" "$svr"
    $a += $srv.jobserver.jobs
}

$a|where-object {$_.isenabled -eq $TRUE -and $_.LastRunOutcome `
    -eq "Failed"}|Sort-Object -Descending LastRunDate| `
    Format-Table Parent, Category, Name, LastRunDate, `
    LastRunOutcome, Description -Autosize|Out-File `
    -FilePath C:TempMonitorJobs.txt -Append -Encoding ASCII


Scan network for instances of MS SQL with Powershell

PROBLEM: You need to find out which computers and servers in my network have an instance of MS SQL installed.

SOLUTION: In this solution we’ll create an instance of the Windows Management Instrumentation (WMI) for each computer in a list. We’ll then query the Win32_Service class for the existence of a service which name starts with “MSSQL”. Go ahead and open a Notepad session and enter the name of several computes you manage in your network, one name per line, and save it with the file name isSQLInstalled.txt. I saved mine in C: for simplicity.

foreach($svr in get-content "C:isSQLInstalled.txt") {
    $filter = "name LIKE 'MSSQL%'"
    $result = get-wmiobject win32_Service -f $filter -computername $svr
    $resulttxt = [bool] $result
    write-host "$svr`: $resulttxt"
}

You need to be member of the Administrator role in each computer in the list for this script to execute successfully. This is a very basic way to search for instances of MS SQL installed in your network. One way you can expand this solution is by using a variable to capture the computer names in your network via Active Directory. You can then use this variable in the loop instead of reading the computer names from a file as we did in this solution.

How to Script Database Tables with PowerShell

PROBLEM: I need an easy way to script out all the tables from a database in MS SQL 2000 and above.

SOLUTION: Like anything in programming, there are a thousand ways to skin a cat. Here, I’ll show you the simplest way I found to meet this request.

Go ahead and open a new session of PowerShell. You can type or copy and paste in your PS session window all the code in this solution. We will start by loading the SMO assembly.

[system.reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO")|out-null

Next, we’ll create an instance of SMO server object, database object, and scripter object

$srv = new-object "Microsoft.SqlServer.Management.SMO.Server" "."
$db = new-object("Microsoft.SqlServer.Management.SMO.Database")
$scr = new-object("Microsoft.SqlServer.Management.SMO.Scripter")

We then assign the instance of MS SQL Server we want the scripter to use. We wrap it up by calling the Script() method with an SQL SMO collection of objects to be script out –in this case, all tables.

$scr.Server = $srv
$scr.Script($srv.Databases["AdventureWorks"].tables)

That’s it! The simplest way to script out all tables from a database with PowerShell. In a future article, I’ll expand from this solution by writing a script that will take parameters, use SMO Scripter Options, filter tables to be script out, and then some.

WMI Date Conversion

USE: To convert the GMT data returned from error logs to a readable date time value.

CLEAR

$sHostName = "TUIRA"
$aLogName = "Application"
$FromDate = [datetime]::today
$WMIQuery = "LogFile='$aLogName' and Type='Error' and TimeGenerated>='$FromDate'"
 
Get-WmiObject Win32_NTLogEvent -ComputerName $sHostName `
                               -Filter "$WMIQuery" `
							   -ErrorAction SilentlyContinue | `
							    SELECT SourceName, `
 @{Name = "TimeGenerated"; EXPRESSION = {$_.ConvertToDateTime($_.TimeGenerated)}}, `
							    Message

 

PowerShell and Outlook

This script was written by ed wilson at Use PowerShell to Data Mine Your Outlook Inbox

CLEAR

Function Get-OutlookInBox {
 Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null
 $olFolders = "Microsoft.Office.Interop.Outlook.olDefaultFolders" -as [type]
 
 $outlook = new-object -comobject outlook.application
 $namespace = $outlook.GetNameSpace("MAPI")
 $folder = ($namespace.getDefaultFolder($olFolders::olFolderInBox)).folders|WHERE {$_.Name -eq "DDUMP"}
 $folder.items | Select-Object -Property Subject, ReceivedTime, Importance, SenderName
} #end function Get-OutlookInbox

Get-OutlookInBox |where { $_.ReceivedTime -gt [datetime]"6/25/12"} | sort importance

 

Script Out All Indexes and Primary Keys from a Database

USE: To generate T-SQL code for all indexes and PK constraints from a database.

CLEAR 

$sSRCServer = "TPW520"
$sSRCDatabase = "iSQLPS" 

$oSO = New-SqlScriptingOptions
$oSO.ClusteredIndexes = $true
$oSO.Indexes = $true
$oSO.NonClusteredIndexes = $true
$oSO.IncludeIfNotExists = $true

$oTables = Get-SqlDatabase $sSRCServer $sSRCDatabase|Get-SqlTable

foreach ($oTable in $oTables){
    $oT = $oTable.Indexes
    
	foreach ($oIndex in $oT) {
		$DDL = Get-SqlScripter $oIndex -scriptingOptions $oSO
	    
		"$DDL `nGO `n`n"
	}
}