SQLvariations: SQL Server, a little PowerShell, maybe some Hyper-V Rotating Header Image

SQL Server

My First MSSQLTip!

imageToday my first ever MSSQLTip was published.  Before you ask: Yes, it talked about PowerShell.

It came about because some of the SQL MVPs were trying to figure out the best way to download a VM that had been split up into 36 different equal-sized files.  I’m sure there’s a better way than this but at the same time it took me about 4 minutes to write.  Write is the wrong term, more like copy/paste/change a few things.

Give it a whirl and let me know what you think!  Smile

Resources for my SQL Server PowerShell Extensions webcast

imageI did another webcast for the Secrets of SQL Server webcast series today.  In the today’s webcast we built on some things I had demoed in a prior webcast and showed how PowerShell in conjunction with SQLPSX can really help you solve some common problems DBAs face.

I showed how you could pull size and free space information from all of your data files, then used the same technique to pull size information from all of your tables across every database on an instance.  Later we created a database and some tables, and then showed how to do some basic login comparisons, all with SQLPSX.

In addition, we stored the results of the frees pace and table size information in a database using the Out-DataTable and Write-DataTable functions.  Finally we wrapped up with a quick demo on how the new SQL Server cmdlets inside of the SQLPS Module in Denali combined with some new functionality in PowerShell v3 CTP1 can really make backing up a database with PowerShell a lot easier.

Here’s what you’ll need to recreate today’s demos;

I hope I see you next week at the PASS Summit or next month during another webcast, this time on customizing your own functions to work with the SMO.

New PowerShell Cmdlets in SQL Denali CTP3

CTP3 of SQL Denali is finally publicly available!

I woke up at 5 am this morning to kick off my download.  I’ve finished the install and I’m happy that I can finally report that we have new cmdlets for SQL Server. 

First off, after running Get-Module -ListAvailable I saw:

Manifest   SQLASCMDLETS
Manifest   SQLPS

This means that SQLPS inside of SQL Agent should finally allow you to import a module during your job step. 

There is now a Function called SQLServer that, from what I can tell, is the SQLServer Provider.  When under PS SQLSERVER:\> if you do a dir | Select pschildname you will find the following list:

PSChildName
———–
SQL
SQLPolicy
SQLRegistration
DataCollection
XEvent
Utility
DAC
IntegrationServices
SQLAS

From my notes it looks like XEvent, IntegrationServices, and SQLAS are the directories that have been added here.  Can’t wait to try out the IntegrationServices portion!  [Update]: Apparently I may need a defaul instance install for this to work.

I also noticed that Tab-Completion appears to be fixed!!  :-)   Also, SQL Registrations > ‘Database Engine Server Group’ are split up into instances like CMS was.  Not sure what that’s all about just yet.  In fact when I try to use it, it doesn’t seem to work.  Maybe I should read the help files.  But I think they may have just gotten CMS & RS reversed.  CMS isn’t working for me either yet.

When you drill down under XEvents and go to your Denali instaince you will see: Packages, & Sessions.  I guess this means that I finally need to read Jonathat’s blog series on X-Events.

When I imported the SQLPS module I received a warning about unapproved verbs.  Oh well, hopefully they’ll work that out soon.  Next I ran Get-Command -Module “SQLPS” and found the following list of cmdlets.

Name Module
Add-SqlAvailabilityDatabase SQLPS
Add-SqlAvailabilityGroupListenerStaticIp SQLPS
Backup-SqlDatabase SQLPS
Convert-UrnToPath SQLPS
Decode-SqlName SQLPS
Disable-SqlHADRService SQLPS
Enable-SqlHADRService SQLPS
Encode-SqlName SQLPS
Invoke-PolicyEvaluation SQLPS
Invoke-Sqlcmd SQLPS
Join-SqlAvailabilityGroup SQLPS
New-SqlAvailabilityGroup SQLPS
New-SqlAvailabilityGroupListener SQLPS
New-SqlAvailabilityReplica SQLPS
New-SqlHADREndpoint SQLPS
Remove-SqlAvailabilityDatabase SQLPS
Remove-SqlAvailabilityGroup SQLPS
Remove-SqlAvailabilityReplica SQLPS
Restore-SqlDatabase SQLPS
Resume-SqlAvailabilityDatabase SQLPS
Set-SqlAvailabilityGroup SQLPS
Set-SqlAvailabilityGroupListener SQLPS
Set-SqlAvailabilityReplica SQLPS
Set-SqlHADREndpoint SQLPS
SQLSERVER SQLPS
Suspend-SqlAvailabilityDatabase SQLPS
Switch-SqlAvailabilityGroup SQLPS
Test-SqlAvailabilityGroup SQLPS
Test-SqlAvailabilityReplica SQLPS
Test-SqlDatabaseReplicaState SQLPS

Analysis Services got some love too in the form of 11 cmdlets!  After inporting the SQLASCMDLETS module I ran this Get-Command -Module “SQLASCMDLETS” and found the following.

Name Module
Add-RoleMember SQLASCMDLETS
Backup-ASDatabase SQLASCMDLETS
Invoke-ASCmd SQLASCMDLETS
Invoke-ProcessCube SQLASCMDLETS
Invoke-ProcessDimension SQLASCMDLETS
Invoke-ProcessPartition SQLASCMDLETS
Merge-Partition SQLASCMDLETS
New-RestoreFolder SQLASCMDLETS
New-RestoreLocation SQLASCMDLETS
Remove-RoleMember SQLASCMDLETS
Restore-ASDatabase SQLASCMDLETS

More news to follow soon!

Why I Need a Week of SQLskills Immersion

SQLskills is giving back to the community with a free seat to their training class in Dallas next month (Feb. 21st – 25th)

To answer Paul Randal’s question of why I should get to win a week of training from SQLskills this is what I have to say:

Plain and Simple.  I’m a Second Generation DBA with over a decade of experience with SQL Server.  I want some deep level ideas for some new PowerShell scripts to simply tasks for DBAs everywhere.  I’ll also spend countless hours telling all my fellow DBAs here in Atlanta what all I learned until they can take it no more and demand this level of top-notch training for themselves!  Open-mouthed smile

I’ll get started with the PowerShell scripts right now even.  This little script will search twitter for a giver hashtag, in this case: #SQLskills.  It will then save everything it finds off to an XML file and then query it:

$SearchHashtag = "sqlskills"            

$wc = new-object net.webclient
$url = "http://search.twitter.com/search.atom?q=%23$SearchHashtag"
$OutFile = "c:\temp\Download_$($SearchHashtag)_$([DateTime]::Now.ToString('yyyyMMddHHmmss')).xml"
$wc.DownloadString($url) | add-content $OutFile;            

[xml]$tweetxml = get-content $OutFile            

$tweetxml.feed.entry | Format-List            

($tweetxml.feed.entry).count            

Is the Connect Feed for SQL Server in Your Reader?

Last week Nicolas Cain ( blog | twitter ) Rob Farley ( blog | twitter ) Aaron Bertrand ( blog | twitter ) and I were all working together on a small skunk-works project to read in all of of the items on the SQL-Connect website (more in that project in a later post).  A few hours into this process I realized “hey, I don’t even have this RSS feed in my Reader!”  I’m not sure why I didn’t; maybe I was lulled into safety by Aaron Bertrand’s “Connect Digests” but unfortunately he doesn’t do those any more. Crying face

So I just wanted to encourage everyone who makes their living off of SQL Server to take a minute to add these two RSS feeds to your favorite feed-reader. 

https://connect.microsoft.com/rss/68/RecentFeedbackForConnection.xml

https://connect.microsoft.com/rss/68/RecentlyModifiedFeedbackForConnection.xml

If you haven’t been on Connect for a while and wonder what’s out there, well I’ve got a PowerShell script for you Open-mouthed smile 

Invoke-Sqlcmd -ServerInstance denali.db.5026258.hostedresource.com `
-Database denali -Username denaliconnect -Password Wide0pen -Query "
SELECT ID
        , Title
        , ItemStatus
        , UpVoteCount
        , DownVoteCount
        , ItemDescription
        , Author
        , Modified
        , ValidationCount
        , WorkAroundCount
        , URL
        , OpenedDate
  FROM denali.dbo.ConnectItems" | out-gridview

OK, you can totally take that login info and use your SQL Management Studio to connect to this database too but I wanted to show you a REALLY cool use for the Out-GridView command.  When run the PowerShell script and the window pops up Just Click on + Add Criteria > ItemDescription > Add.

Like this:

image

Then just type in a search term like “SSIS” and see what you get back…

image

Rob has also put together a way to search the data that is much better and where we hope to ultimately go with it.  Again, that’s all for another post.

Guest Posts for Hey Scripting Guy Blog on TechNet

imageLate last year I contributed three guest blogger posts to a full week of posts about PowerShell and SQL Server. The posts were published a week before the PASS Summit. In them I tried to not only cover how useful PowerShell is for automating your every day SQL tasks but also the different approaches you have for accomplishing them: PowerShell cmdlet, WMI, SMO, SQL Provider, and .Net.

It’s a huge honor to get the chance to be a guest blogger on Hey Scripting Guy! and I hope these posts were able to make some people’s (o.k. A Lot of People’s) lives easier. Given the number of people checking out PowerShell for the first time based on the comments to my MCM Videos download script I figured I’d call these out today:

Use PowerShell to Obtain SQL Server Database Sizes

Use PowerShell to Change SQL Server Service Accounts

Use PowerShell to Script SQL Database Objects

image

I know that the Hey Scripting Guy! blog is the #1 blog on TechNet but I’m not allowed to know any specifics beyond that. I did however catch this in yesterday’s post: “In general, the articles we published on SQL Server and on SharePoint have been really popular.” So hopefully that means we’ll get to hear some more SQL voices there in the near future. Maybe even in time for SQL Rally, who knows? Winking smile

Quick Blog: What’s Missing From SQLPS

imageLast week Norm Kelm ( blog | twitter ) asked me on twitter ‘What cmdlets/features are missing from SQLPS.exe? Get-Snapin, etc. Where’s a doc that explains?’   To get the cmdlet half of this answer is somewhat easy in PowerShell using Compare-Object but it made me realize this is one of the many PowerShell tips that I have failed to blog about yet!  I plan to fix that next year with a deluge of blog posts but why wait until next year right?

To get a very fast answer to this answer I opened up PowerShell.exe because while I normally demo in PowerShell_ISE.exe, I don’t use a profile in PowerShell.exe (more on that in a later post).  I ran this command to get the count of just the cmdlets.

(get-command -CommandType Cmdlet).count

image

Then I fired up SQLPS.exe (typically found in C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn) and ran the same command (after switching out of SQL Server and over to the C drive; no idea why that was necessary).

image

The only problem here is that it’s not really 236 – 130 = 106 because SQLPS.exe adds 5 cmdlets that I made sure to exclude (along with everything else I normally use) from PowerShell.exe. 

To get a more accurate list of the cmdlets and which one has what I decided to write a script that everyone con run on their own machine.  One of the many cool features of PowerShell is that you call call it’s executable and pass it a -command or even a –file.  I went ahead and threw together this simple command below so that you can see the differences yourself.

Note: I assume you are running Windows 7 which comes with PowerShell 2.0

$SQLPS=SQLPS.exe -command "CD C:\; get-command -CommandType Cmdlet | select CommandType, Name; exit";
$PSTwo=powershell.exe -command "get-command -CommandType Cmdlet | select CommandType, Name; exit";

Compare-Object -ReferenceObject $SQLPS -DifferenceObject $PSTwo|
Export-CSV C:\temp\SQLPSCommandDifferences.csv -NoTypeInformation

Now all that you have to do is open up that csv file that was just created (C:\temp\SQLPSCommandDifferences.csv) and have a look. 

Note: I could have just displayed the info inside of my PowerShell window by leaving off the last line and the pipe but then I would have needed to do something to format the output so I went with the CSV file instead.

For more information on this topic be sure to check out Chad Miller’s post on it.

SQL Source Control, PowerShell, and TFS FTW!

imageA few weeks back I wrote a post for the Hey Scripting Guy Blog on TechNet on scripting out databases with PowerShell. The post was inspired by an issue I had using Red-Gate’s SQL Source Control tool. (If you aren’t familiar with SQL Source Control then check it out. The tool is so full of awesome that I wrote code to get around the only problem I found with it. )

imageWhile using the product I ran into a single small problem. When I check a database into Team Foundation Server via SQL Source Control it doesn’t include the drop statements. The deployment procedures at my company just go smoother with DROP statements in each of the stored procedures. Similarly, for databases that haven’t been deployed outside of the Development environment it was better for us to drop and re-create the tables from scratch. It isn’t the kind of thing you’d ever do in production, but given the length of some development projects it is very useful if you can do this when needed.

The version of SQL Source Control I used doesn’t script drops or permissions by default. If there is an option to change this I can’t find it. Rather than switch tools I used this as an excuse to learn how to work with the different scripting options available inside the SMO exposed by PowerShell. Find your options this way:

$dbname="AdventureWorks"
$server="WIN7NetBook"

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
$SMOserver = New-Object (’Microsoft.SqlServer.Management.Smo.Server’) -argumentlist $server
$db = $SMOserver.databases[$dbname]

$Scriptr = new-object ('Microsoft.SqlServer.Management.Smo.Scripter') ($SMOserver)
$Scriptr.Options | Get-Member

To work around this problem I linked my database to my TFS server (from SQL Source Control inside of SSMS). I committed all the changes to TFS so that everything was checked in. Then I opened Visual Studio, checked out out all the objects on to my local machine, generated the scripts with PowerShell just the way I wanted them, overwrote the local TFS code with the code I had just generated, and finally, I checked everything back in to TFS. Doing all this was pretty quick, worked great, and SQL Source Control didn’t care that the scripts weren’t the ones that it had generated.

Be forewarned, when you include the ScriptDrops option it only generates the drop statement. To work around this see my tips here. Now all that is left is to add the Permissions option.

The resulting code also does some cool things like divide objects into folders by type; put everything under a folder structure that includes the name of the database; and another folder that is simply datatime so that you can run it multiple times as you tweak the code to fit your environment, or, just keep old versions of the code laying around in case someone dropped something that hadn’t been checked into TFS yet. I’ve also included the portion of code that only adds the drop statements to objects like stored procedures but not tables.

You can download the script here. Or just take a look at it here. When/if you run the script, it creates a PowerShell function. To call it all you have to do is something like this:

Script-DBObjectsIntoFolders "AdventureWorks" "WIN7NetBook"

And you could even call it in a loop to script out all of your user databases:

foreach ($dbn in invoke-sqlcmd -query "SELECT name
  FROM sys.databases WHERE owner_sid !=0x01"`
 -database master -serverinstance WIN7NetBook )

{ #Begin Loop
$dbn;
Script-DBObjectsIntoFolders  $($dbn.name) "WIN7NetBook"
} #End Loop

Script-DBObjectsIntoFolders

function global:Script-DBObjectsIntoFolders([string]$dbname, [string]$server){
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
$SMOserver = New-Object (’Microsoft.SqlServer.Management.Smo.Server’) -argumentlist $server
$db = $SMOserver.databases[$dbname]

$Objects = $db.Tables
$Objects += $db.Views
$Objects += $db.StoredProcedures
$Objects += $db.UserDefinedFunctions

#Build this portion of the directory structure out here in case scripting takes more than one minute.
$SavePath = "C:\TEMP\Databases\" + $($dbname)
$DateFolder = get-date -format yyyyMMddHHmm
new-item -type directory -name "$DateFolder"-path "$SavePath"

foreach ($ScriptThis in $Objects | where {!($_.IsSystemObject)}) {
#Need to Add Some mkDirs for the different $Fldr=$ScriptThis.GetType().Name 
$scriptr = new-object ('Microsoft.SqlServer.Management.Smo.Scripter') ($SMOserver)
$scriptr.Options.AppendToFile = $True
$scriptr.Options.AllowSystemObjects = $False
$scriptr.Options.ClusteredIndexes = $True
$scriptr.Options.DriAll = $True
$scriptr.Options.ScriptDrops = $False
$scriptr.Options.IncludeHeaders = $True
$scriptr.Options.ToFileOnly = $True
$scriptr.Options.Indexes = $True
$scriptr.Options.Permissions = $True
$scriptr.Options.WithDependencies = $False
<#Script the Drop too#>
$ScriptDrop = new-object ('Microsoft.SqlServer.Management.Smo.Scripter') ($SMOserver)
$ScriptDrop.Options.AppendToFile = $True
$ScriptDrop.Options.AllowSystemObjects = $False
$ScriptDrop.Options.ClusteredIndexes = $True
$ScriptDrop.Options.DriAll = $True
$ScriptDrop.Options.ScriptDrops = $True
$ScriptDrop.Options.IncludeHeaders = $True
$ScriptDrop.Options.ToFileOnly = $True
$ScriptDrop.Options.Indexes = $True
$ScriptDrop.Options.WithDependencies = $False

<#This section builds folder structures.  Remove the date folder if you want to overwrite#>
$TypeFolder=$ScriptThis.GetType().Name
if ((Test-Path -Path "$SavePath\$DateFolder\$TypeFolder") -eq "true") `
        {"Scripting Out $TypeFolder $ScriptThis"} `
    else {new-item -type directory -name "$TypeFolder"-path "$SavePath\$DateFolder"}
$ScriptFile = $ScriptThis -replace "\[|\]"
$ScriptDrop.Options.FileName = "" + $($SavePath) + "\" + $($DateFolder) + "\" + $($TypeFolder) + "\" + $($ScriptFile) + ".SQL"
$scriptr.Options.FileName = "$SavePath\$DateFolder\$TypeFolder\$ScriptFile.SQL"

#This is where each object actually gets scripted one at a time.
IF ($ScriptThis.GetType().Name -NE "Table") { $ScriptDrop.Script($ScriptThis) }
$scriptr.Script($ScriptThis)
} #This ends the loop
} #This completes the function