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

Modules

PowerShell Week at SQL University – Post 4

Recap

So far we’ve walked though how to turn on PowerShell and add modules, adding SQL Server 2008 snapins and using PowerShell variables, what cmdlets and functions are, what providers are and how to work with methods & properties.

Profiles

PowerShellProfilesToday we focus on load things in our profile so that they are always available in PowerShell.  First, some basics:

What is a Profile?  A profile is nothing more than a PowerShell script that gets run as soon as you open up a given PowerShell window.

Why would we want to do this?  I use PowerShell almost exclusively for automating work with my SQL Servers.  When I’m ready to do something I don’t want to start by reloading the same toolset every time I open it. I want to click the icon and be ready to go.  The profile saves me from this repetitive loading.  I update my profile as I find cool new scripts that I want to add.

You are not limited to using a single profile in PowerShell.  Personally, I use one of three profiles depending on the task at hand.  Here is how that works. I use the PowerShell ISE or other third party products as my primary way of writing PowerShell scripts (.ps1) and rarely use the “console.”   I only use the console if I need to troubleshoot something that might have to do with STA/MTA. 

When I open up the PowerShell ISE it’s uses it’s own profile CurrentUserCurrentHost that is stored in C:\Users\USERNAME\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1 (picture-right).  Inside of that file on my machine it currently looks like this:

import-module ISEPack
cd C:\Users\Aaron\Documents\PoSh\Load
. ./invoke-sqlcmd2.ps1
. ./Write-DataTable.ps1
. ./Out-DataTable.ps1
. ./Add-SqlTable.ps1
. ./Export-CSV-Append.ps1
. ./invoke-sqlcommand.ps1
. C:\Users\Aaron\Documents\PoSh\Tasks\Get-DisksSpace.ps1
cd c:\temp\

Whatever is in this file only gets loaded into my session when I open the ISE.  Nothing above gets run when I open up the console.  These are items I use in ISE, but not in the console PowerShell window.

There are items I use in both ISE and the console.  These items live in a “super profile” of sorts since I want these items no matter how I access PowerShell CurrentUserAllHosts (which is located in C:\Users\USERNAME\Documents\WindowsPowerShell\profile.ps1). Profile.ps1 (picture-center) gets run every time I open up any PowerShell “host” including 3rd party tools.  This also includes the SQLPS host which may cause errors messages to appear when you open it or run a SQL Agent Job.  These error messages don’t impact a PowerShell step in a SQL Agent Job from running.

Here’s what I have inside of my Profile.ps1 file.

Add-PSSnapin SqlServerCmdletSnapin100
Add-PSSnapin SqlServerProviderSnapin100
Import-Module SQLServer

Whenever I open the ISE both the Microsoft.PowerShellISE_profile.ps1 and the Profile.ps1 scripts get run.

PowerShell.exe (the little blue “host”) has it’s very own CurrentUserCurrentHost profile that it loads.  That’s the exact same name as the profile that we talked about the ISE loading so does that mean that it’s loading that same file?  No.  Each one is configured to load it’s own CurrentUserCurrentHost from a different location.  So if there are items I want in console world only I have a place to store them thanks to C:\Users\USERNAME\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1.  Since I rarely use the console my profile there sat empty until recently.  I only added items after I spotted a post by Oisin Grehan ( blog | twitter ) on Implementing a Matrix-Style Console Screen Saver and I HAD to try it.  This only works in the console and not in the ISE so it made my console profile the perfect place for implementing this.  Now my PowerShell_profile.ps1 file (picture-left) looks like this:

Import-Module screensaver
set-screensavertimeout (new-timespan -minutes 5)
enable-screensaver
Start-ScreenSaver

To edit one of the profiles that only load for the console or the ISE all you have to do is open them up and run notepad $profile.  It will figure out which file is the right one for that environment and open it for you.  To edit the profile that is run in every PowerShell environment just run notepad $profile.CurrentUserAllHosts.  If your WindowsPowerShell directory isn’t there it will not automatically create that for you and you will get an error message stating that it “can’t find the specified path“.  I’ve written a little script to check for that and create one for you if it’s not already there:

$myPowerShell = $HOME
$myPowerShell +="\Documents\WindowsPowerShell"
if ((Test-Path $myPowerShell) -eq "true") {"$myPowerShell is already there mate"}
else { "you need to make one"
mkdir $myPowerShell  }

Homework Assignment:

Setup one of your profiles to at least have one of the modules from the SQLPSX project and the SQL Server Snapins loaded up every time you start up the PowerShell ISE. Which profile to use is completely up to you.  Feel free to play around with your choices.  Optionally you can also include the Get-DisksSpace function like I do; but you don’t have to.

Let me know how this goes for you by dropping a note it the comments.  In tomorrow’s post we are going to work with multiple SQL Servers so you’ll need these things up and running for that.

If you’re confused by where your files are you can just run this script that I lifted off of the HeyScriptingGuys site to have it tell you where all of the profiles for your session have been loaded from.  Keep in mind that we’re not touching the ones in the Windows directory.

$profile |

Get-Member -MemberType note* |

Format-Table -Wrap -AutoSize -Property name,

@{ Label=“Path”; Expression={$_.definition -replace “System.String”,“”} }

PowerShellProfiles

In Case you would like more to play with…

There is a lot more that can be done with PowerShell Profiles but these are the basics you need to get up and running. If you want to dive deeper check out these posts over on the Hey Scripting Guy Blog.  Go here to download the SQLServer or ISEPack modules; they are both part of larger projects.  If you’d like some of the scripts that I reference in my profile you can grab the Get-DisksSpace one here and I’ll be blogging about the rest later this week.

Be Advised:

Everything that you put into you profile eats up RAM.  Thankfully most scripts are only a few kilobytes.  Keep in mind that the more items you add into your profile the longer that it is going to take to load.

imageIn case you’re wondering if that “Matrix Style Console Screen Saver” is worth having around, here is what it looks like after a few minutes:

That’s all that I’ve got for you today, see you back tomorrow!

PowerShell Week at SQL University – Post 1

Getting Started With PowerShell Variables

Yesterday we laid the ground work for PowerShell Week.  Today we will learn about Variables in PowerShell. You will notice that PowerShell variables work very differently from SQL Server variables.

The evolution of variables in SQL Server is pretty straight forward. In SQL Server 2000 you had to DECLARE a variable as a specific type in one statement and then SET the value of the variable in another statement, like this: DECLARE @SQLvariable VARCHAR(12) SET @SQLvariable = ‘OldFeature’. By the time SQL 2008 hit the streets we could DECLARE and SET a variable in one statement like this: DECLARE @SQLvariable VARCHAR(12) = ‘NewFeature’ . PowerShell evolves variables to the next logical step.  You no longer need to declare or type your variable. Instead PowerShell uses the value of the variable to infer it’s type. If a variable does not alreayd exist PowerShell simply creates it for you.  In PowerShell our statement looks like this: $SQLvariable = ‘NewFeature’. (Beginer tip: $ identifies variables in PowerShell just like @ identifies them in SQL Server.)

Since it doesn’t work in SQL let’s try it in PowerShell: $SQLvariable = ‘NewFeature’.  OK so we loaded data into a variable, ‘big deal’ right?  How do we know that we actually loaded it and more importantly what datatype is it?  Well in PowerShell you can simply call the variable to get its value. (Another beginer tip: you don’t need to use a keyword like SELECT for this, just the variable name: $SQLvariable.)  What if you just want to determine the datatype?  All you have to do is tack on the .GetType() Method: $SQLvariable.GetType().

$SQLvariable = 'NewFeature'
$SQLvariable
$SQLvariable.GetType()

When you run this here’s what your result will be:

image

As I alluded to earlier, another feature of PowerShell is that it remembers your variables for you, even between executions.  Basically as long as you don’t end your session the variable, it’s datatype, and its value will persist.  You will see later than you can also set a variable in one script and consume it in another.

Let’s try this again with a new variable and set it to a different value:

$PoShvariable = 123
$PoShvariable
$PoShvariable.GetType()

image

What happens if once the datatype is set we try to set it to a different, incompatible datatype?  It’s going to explode right?  Nope, you’ll have to throw something more difficult than that at it.  Give this a try:

$PoShvariable.GetType()
$PoShvariable = 'NewFeature'
$PoShvariable
$PoShvariable.GetType()

 

 image 

Since PowerShell relies on .NET a variable could be any datatype in .NET so if you’re sitting inside the AdventureWorks database you can see for yourself, just run this:

$MyTable = get-item TABLESProduction.TransactionHistory
$MyTable.GetType()            

$MyStoredProc = get-item StoredProceduresHumanResources.uspUpdateEmployeePersonalInfo
$MyStoredProc.GetType()
image

Now earlier I mentioned that PowerShell keeps track of and remembers the variables that you previously declared.  So how do you see what variables are already there?  Just run this command and you can see every variable you have running in the session, even the internal ones.

Variable

In the list of items that get returned you’ll see one called Error that holds the last error message that occurred in your session.  This handy feature can help you when you have to debug your own work.

Is that all there is to know about variables in PowerShell?  Not hardly, but I think that’s a good stopping point for this post.  More on variables later.

PowerShell Week at SQL University – Post 0

Welcome to PowerShell Week at SQL University. For regulars at SQLvariant, SQL University is something Jorge Segarra organized to get industry experts together to create learning courses around SQL Server. These learning courses are in one week segments that focus on a specific area.

When I began blogging about PowerShell there were some complications based on your operating system. There were so many people blogging about these issues that I didn’t address it initially. Since this is an introductory course I decided to go ahead and spin up a brand new Windows 7 VM so that I can walk you through these small but vital details. If you don’t have Windows 7 this would be a great time to upgrade. If you can’t upgrade then download PowerShell for you operating system from this link. Now, onto getting started:

Disclaimer:
PowerShell opens in a protected state as a security measure. To enjoy the full power of PowerShell (and run scripts you downloaded off of the internet) you need to run without these safeguards. In today’s lesson we are simply launching PowerShell and priming it for the scripts and work we will interact with in the next several lessons.

To get started with PowerShell just click the Start button and type in ISE to locate the Integrated Script Editor in your program listing. Right click and launch PowerShell in Run as Adminsitrator mode:

image

Enter Get-ExecutionPolicy as a command. If you haven’t used PowerShell yet you will most likely see that the Execution Policy is set to “Restricted”. You’ll need to run the command Set-ExecutionPolicy RemoteSigned to be able to run the scripts and follow along with the lesson. You’ll also get a popup that you’ll have to say yes to.

image

Your output should look very non-informative like this:

image

Now that we have that set let’s go to SQLPSX.CodePlex.com and and download the SQLPSX project. It’s currently in version 2.2.1 and consists of 9 modules containing 133 advanced functions, only 2 cmdlets and 7 scripts. It’s for working with ADO.NET, SMO, SQL Agent, RMO, SSIS, SQL script files and using the PowerShell ISE as a SQL query tool:

NOTE: Update at bottom with workaround:

image

During the installation we will run it without modifying the profile (just yet).

image

Once you’ve installed it successfully you should now have a WindowsPowerShell directory under your My Documents if you didn’t have one already (which is really important):

image

After it’s installed we should be able to open up the ISE again and run this command :

Get-Module -ListAvailable

image

And finally we’re going to get to the step where we load something up. Run import-module SQLServer to load up the main SQL Server module. After you run that command it won’t give you any output telling you that it successfully loaded so you can run this command write-host -foregroundcolor DarkGreen “Modules Loaded: $(get-module)” to have it tell you what Modules it currently has loaded.

image

Alright that pretty much wraps it up for today. I know we didn’t do a lot with PowerShell and SQL Server yet but this gets some important ground work out of the way so that hopefully everyone is able to script along for the rest of the week. (If you’re dying to read ahead have a look at this post: Basic Querying From PowerShell)

If you run into any issues please leave a comment and I’ll be glad to lend any help that I can. See all you back here tomorrow for the next post in this series Post 1.

UPDATE:

There seems to be an issue with loading the SQLServer Module as I had described. I have found this to be a work-around: Go to \\~\My Documents\WindowsPowerShell\Modules\SQLIse\Modules\ and copy everything except for the SQLISE folder, then go to the \\~\My Documents\WindowsPowerShell\Modules\ folder and paste all of those items. At this point you should now be able to run the command and get it to load up properly.

I will post more when I found out other alternatives.

Get More Done with SQLPSX

In my LiveMeeting session for the AppDev Virtual Chapter of PASS yesterday I talked about building on top of tools that others had already built for you to use.  A great one for any DBA to use is the SQL PowerShell Extensions known as SQLPSX.  Even if you’ve never used PowerShell before you should take a look at this.  Heck even Sys Admins in shops that don’t have a DBA should have a look at this.  I have found the commands I have worked with very easy to use; even easier than T-SQL in some cases.

SQLPSX

After you download the files and RTFM you can then you can follow along on this next part.  Oh wait, first a little warning straight from Buck Woody:

Script Disclaimer, for people who need to be told this sort of thing:  

Never trust any script, including those that you find here, until you understand exactly what it does and how it will act on your systems. Always check the script on a test system or Virtual Machine, not a production system. All scripts on this site are performed by a professional stunt driver on a closed course. Your mileage may vary. Void where prohibited. Offer good for a limited time only. Keep out of reach of small children. Do not operate heavy machinery while using this script. If you experience blurry vision, indigestion or diarrhea during the operation of this script, see a physician immediately.

get-module -listAvailable

import-module SQLServer

Invoke-SqlBackup -sqlserver "WINX64ULT7\Kilimanjaro" -dbname "AdventureWorks" `

-filepath "C:\Temp\AdventureWorks_db_$(((Get-Date).ToString("yyyyMMddHHmm"))).bak"

Now this little script here (above) will backup a db for you and even include the current YearMonthDayHourMinute in the file string.  This one below will backup all of the non-system databases on your instance.  If you’re like me you’re thinking this doesn’t do anything that you can’t already do today with a maintenance plan.  That’s true and maybe I should have titled this post “Get Something Done with SQLPSX” but I will build on how you can leverage this more tomorrow.  For now, why don’t you add an AND clause only backup all the databases that start with ‘A’ ;-)

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

-database master -serverinstance WIN7\Kilimanjaro )

{

$k="C:\Temp\" + $($dbn.name) + "_db_$(((Get-Date).ToString("yyyyMMddHHmm"))).bak"WIN7\Kilimanjaro" -dbname $($dbn.name)  -filepath $k

$dbn; Invoke-SQLBackup -sqlserver "

}

I’ve gone ahead and included the SQLPSX help items here.  Please see if there’s one that catches your eye and see if it might work for you.

* Get-AgentAlert

* Get-AgentAlertCategory

* Get-AgentJob

* Get-AgentJobHistory

* Get-AgentJobSchedule

* Get-AgentJobServer

* Get-AgentJobStep

* Get-AgentOperator

* Get-AgentOperatorCategory

* Get-AgentProxyAccount

* Get-AgentSchedule

* Get-AgentTargetServer

* Get-AgentTargetServerGroup

* Set-AgentJobHistoryFilter

* Get-ReplArticle

* Get-ReplEnumLogReaderAgent

* Get-ReplEnumPublications

* Get-ReplEnumPublications2

* Get-ReplEnumSnapshotAgent

* Get-ReplEnumSubscriptions

* Get-ReplEnumSubscriptions2

* Get-ReplLightPublication

* Get-ReplMonitor

* Get-ReplPublication

* Get-ReplPublicationMonitor

* Get-ReplPublisherMonitor

* Get-ReplScript

* Get-ReplServer

* Get-ReplSubscriberSubscription

* Get-ReplSubscription

* Get-ReplTransPendingCommandInfo

* New-ReplMergePublication

* New-ReplScriptOptions

* New-ReplTransPublication

* Get-GroupUser

* Get-ShowMbrs

* New-ShowMbrs

* Set-ShowMbrs

* Out-SqlScript

* Test-SqlScript

* Add-SqlDatabase

* Add-SqlDatabaseRole

* Add-SqlDatabaseRoleMember

* Add-SqlDataFile

* Add-SqlFileGroup

* Add-SqlLogFile

* Add-SqlLogin

* Add-SqlServerRoleMember

* Add-SqlUser

* Get-Sql

* Get-SqlCheck

* Get-SqlColumn

* Get-SqlConnection

* Get-SqlData

* Get-SqlDatabase

* Get-SqlDatabasePermission

* Get-SqlDatabaseRole

* Get-SqlDataFile

* Get-SqlDefaultDir

* Get-SqlEdition

* Get-SqlErrorLog

* Get-SqlForeignKey

* Get-SqlIndex

* Get-SqlIndexFragmentation

* Get-SqlInformation_Schema.Columns

* Get-SqlInformation_Schema.Routines

* Get-SqlInformation_Schema.Tables

* Get-SqlInformation_Schema.Views

* Get-SqlLinkedServerLogin

* Get-SqlLogFile

* Get-SqlLogin

* Get-SqlObjectPermission

* Get-SqlPort

* Get-SqlProcess

* Get-SqlSchema

* Get-SqlScripter

* Get-SqlServer

* Get-SqlServerPermission

* Get-SqlServerRole

* Get-SqlShowMbrs

* Get-SqlStatistic

* Get-SqlStoredProcedure

* Get-SqlSynonym

* Get-SqlSysDatabases

* Get-SqlTable

* Get-SqlTransaction

* Get-SqlTrigger

* Get-SqlUser

* Get-SqlUserDefinedDataType

* Get-SqlUserDefinedFunction

* Get-SqlVersion

* Get-SqlView

* Invoke-SqlBackup

* Invoke-SqlDatabaseCheck

* Invoke-SqlIndexDefrag

* Invoke-SqlIndexRebuild

* Invoke-SqlRestore

* New-SqlScriptingOptions

* Remove-SqlDatabase

* Remove-SqlDatabaseRole

* Remove-SqlDatabaseRoleMember

* Remove-SqlLogin

* Remove-SqlServerRoleMember

* Remove-SqlUser

* Set-SqlData

* Set-SqlDatabasePermission

* Set-SqlObjectPermission

* Set-SqlServerPermission

* Update-SqlStatistic

* Copy-ISItemFileToSQL

* Copy-ISItemSQLToFile

* Copy-ISItemSQLToSQL

* Get-ISData

* Get-ISItem

* Get-ISPackage

* Get-ISRunningPackage

* Get-ISSqlConfigurationItem

* New-ISApplication

* New-ISItem

* Remove-ISItem

* Rename-ISItem

* Set-ISConnectionString

* Set-ISPackage

* Test-ISPath