The PoSH DBA – SQLPSX: SQL Server PowerShell Extensions

Every DBA needs to know about SQLPSX, the PowerShell module library that is built by DBAs for DBAs, and designed to provide intuitive functions around the SMO objects. It makes the automation of database administration easier across all versions of SQL Server since SQL Server 2000. Laerte Junior, who is one of the developers on the open-source project, describes how to use it.

“Productivity is being able to do things that you were never able to do before”

– Franz Kafka

What is SQLPSX?

Imagine that you are obliged to script out the T-SQL source code of all the stored procedures for all the databases on a particular SQL server instance in order, maybe, to audit any changes. You can do this by using the SSMS script dialogs of course. But, let’s make the situation a bit more complex. This process must be done weekly and without user input, that is, without the DBA sitting in front of the SSMS tool. There are drawbacks of attempting to use SSMS for this task.

The tool does not have the option to choose all databases. You have to do the process for each database in turn.

SSMS provides no way to automate the generation of the scripts. Each week you will have to do the whole process again, click by error-prone, tedious, click.

Now let’s provide some additional requirements to make it more like real life. You have fifty databases on the server that we’ll call QuiGonJinn. If the time for each database to generate scripts its five minutes, the total time to do this process will be two hundred and fifty minutes or, in other words, four hours. And remember that this process needs to happen every week. As a DBA skilled in PowerShell, you can accommodate these requirements by using a series of SQLPSX functions, in a command line of PowerShell, like this:

This script produces a .sql file for each database in the QuiGonJinn instance that contains the source TSQL of all the stored procedures, and stores it in the path c:\temp\scripts. To automate this process, you can simply set up a SQL Server Agent job to run the script on the required schedule or run it on Windows Scheduler on a server.

We used SQLPSX to do this. It saved a lot of effort,

SQLPSX can increase your day-to-day productivity. With it, you no longer need to lose at least four hours each week in mind-numbing tedium to perform this process. Because the process is automated, you’ve eliminated the possibility of user-error in running the SSMS tool, and you’ve increased the chances of getting home in the evening before your children go to bed.

The SQLPSX modules are compatible with all versions of SQL Server, starting with SQL Server 2000. According with its documentation, “SQLPSX consists of 13 modules with 163 advanced functions, 2 cmdlets and 7 scripts for working with ADO.NET, SMO, Agent, RMO, SSIS, SQL script files, PBM, Oracle and MySQL and using PowerShell ISE as a SQL and Oracle query tool. In addition optional backend databases and SQL Server Reporting Services 2008 reports are provided with SQL Server and PBM modules”. In other words, SQLPSX is the best and most complete library in PowerShell for SQL Server.

The libraries work directly with SMO objects (SQL Server Management Objects), so that each SQLPSX function returns an SMO object. For example, the Get-SQLServer returns an SMO object type Microsoft.SqlServer.­Management.Smo.Server. This means that you can use SQLPSX when you choose to , or interact directly with SMO if you need to, or want to. The distinction of SQLPSX is that frequently-used scripts are pre-packaged into PowerShell functions, allowing you to concentrate on the task on hand, rather than writing great gobs of mostly redundant SMO code for each new task, and then having to test it all.

Note: For a full explanation about SMO see SQL Server Management Objects Reference at Microsoft Developer Network (MSDN) http://bit.ly/U0leMX

SQLPSX allows you to reduce the amount of code you write in order to perform regular tasks such as scripting databases or setting up a complex, multi-machine task to, for example, configure replication. The original SQLPSX modules were created by a friend and mentor Chad Miller. It is now an active community project, and I am proud to be a developer participating in this ambitious project.

The SQLPSX cmdlets library today has over 15,000 downloads, and more than 160 people following the project. The forum is constantly monitored, questions are answered and bugs are fixed. The library is continuously updated, generating releases for bugs and improvements. You can download it from Codeplex-SQLPSX -> http://sqlpsx.codeplex.com/

Installing SQLPSX

In the article on setting up your environment, we provided instructions on how to install and configure SQLPSX in the profile, but now we’ll go a little deeper into this process.

From the http://sqlpsx.codeplex.com/ page, go to the download tab. There you will find two types of downloads; one that uses an MSI Installer and another with zipped modules as illustrated in Figure 1:

 

1911-clip_image001-340x446.jpg

Figure 1 – The SQLPSX Site with the download options

For this example, we will download the.zip files and perform a manual setup. Another very important file in this process is the readme.txt, so be sure to also read it.

Click on the zip version in “other available downloads“, download the zip file and save it in a folder on your machine. By default the zip file is locked. In windows Explorer, Right click the file, pick ‘properties‘ in the context menu, and down right, click on unblock. I’m not referring to a specific file name because by the time you read this article a newer version may have been released.

Unzipping this file it will create a folder called “modules” and within this folder, 13 other folders with the name of each module within each folder is the individual module code as shown in Figure 2:

 1911-clip_image002-420x409.jpg

Figure 2 – Listing all SQLPSX modules

As we saw in my previous article, we need to put the modules’ code in one of the paths that the environment variable $ENV:PSModulePath points to. In the case we copy all these folders to the path of the user, or %WindowsUserProfile%\Documents\WindowsPowerShell\Modules. In my case all the folders were copied to C:\Users\Laerte.Junior\Documents\WindowsPowerShell\Modules

Note: In several examples in this book, we’ll use SQL Server Agent jobs to run a script. In this case you will have to do the same process to make the modules available for the account that will run SQL Agent Job, whether or not it is a proxy account. Another option is to use a machine-global PowerShell profile that applies to all sessions. My previous article covered this.

The SQLPSX libraries directly use the SQL Server Management Objects, or SMO, which is a collection of objects in a .NET library that provides you with the means to manage SQL Server programmatically: Therefore you need to have SMO installed on the machine that uses SQLPSX. If you’ve installed SQL Server Management Studio, SMO is already included: If not, then you can install it separately from the SQL Server Feature Pack http://bit.ly/SIFalD.. If you are installing SMO manually, we strongly recommend using the latest version of SMO because some features may not be accessible in very old versions of SMO.

Note This entire procedure is documented in the Documentation tab on the SQLPSX website

Working with SQLPSX

The SQLPSX modules are fairly straightforward to understand even if you haven’t read the excellent documentation available from typing get-help followed by the name of the SQLPSX function. The function names, noun and verb, follow PowerShell naming conventions, and are therefore intuitive and consistent with each functions’ purpose. If you want to find the functions that refer to tables, for example, look for the Get-SQLTable cmdlet or for stored procedures select Get-SQLStoredProcedure. Because each function is abstracted into a PowerShell cmdlet/function, you don’t have to worry about which SQL Server system view to use, or find your T-SQL script that performs this operation. Also, you don’t need to worry about what runs on each version of SQL Server: SMO looks after this for you. Simply use the Get-SQLDatabase and this function will return all the necessary information. The next sections cover some often-used operations in SQL Server that can be easily done using SQLPSX.

General SQL Server – Server Settings

Some basic information that we may need to use frequently in our jobs administering SQL Server is stored in the server level settings of an SQL Server instance. The function Get-SQL Server returns all members you need for this process. For example, to list information such as name, collation, etc. of the ObiWan SQL Server instance, you can issue the following PowerShell statement:

Note: We are only bringing the server information from ObiWan instance. But you can also use this function to get information about a series of instances stored in the c:\ servers\SQLInstances.txt file, that looks like this:

We’ll also add the date that you gathered the information. Notice that we pass the date as custom property to the Select-Object because it is not a property of Get-SQLServer function:

We can also check for a specific set of SQL Server instances by SQL Server version. Regardless of the exact version number, you can use the starting number in the version number to identify each major version, as you can see in Table X:

SQL Server Version

Starts with

2000

8.

2005

9.

2008

10.

2008 R2

10.

2012

11.

Therefore, if we want to identify whether we have any instances of SQL Server 2005 amongst our servers, we can filter for “9.” in the property version:

Or to list all instances ordering by name and version properties:

Another very important set of instance level properties is returned by the T-SQL system procedure sp_configure. To have access to these using SQLPSX, we need to extract it from the configuration property returned by the function Get-SQLServer. The object returned by this function is a complex one in that it is an object that contains other objects. Thus Select-Object will return the specification of an internal object:

To access this object we have to then expand the two properties ‘Configuration’ and ‘Properties’ that are properties of the object returned by Get-SQLServer :

Another way is by directly accessing the property within the Configuration using custom properties. In the example we are using the Max Degree of Parallelism:

Note: In the above examples, we display only certain information such as Name, Collation, Edition, Language, Product, Product Level, Version and Service Account. But there is much more to be displayed. Just type the command below to get the full list of members returned by the function:

Get-SQLServer <SQLServerInstance> | Get-Member

Database Settings and Objects

Now that we have the means to get the general information about the SQL Server instances, we will see how to access an instance’s databases. The function Get-SQLDatabase has this functionality. It returns generic information about one database or the collection of databases on a given instance. To return all the user databases in the QuiGonJinn SQL Server instance just type:

The function has two parameters. The -dbname parameter selects only the specified database. The parameter -force also includes the System Databases. So, to list the information in the database AdventureWorks2012 in the QuiGonJinn instance type:

…or to return all databases including the System ones:

We already have seen that we can pipe the output of a cmdlet to the Get-Member cmdlet to discover all the properties of any object in PowerShell. This is fine for many purposes, but when you do this, all members are listed including methods…etc. To list only the properties, we need to use the -membertype parameter:

The -membertype parameter will still return all the “property” properties, including those containing objects like the collection of tables. There is a “configuration” property at a database level, analogous to the instance-level configuration property returned by the Get-SQLServer function.

An interesting fact is that each SMO object also contains a specific property named “properties.” It contains all the other properties using simple data types, such as string or int. Listing all the properties returned by Get-SQLDatabase, which is a type SMO Microsoft.SqlServer.Management.Smo.Database, just expand the “properties” property and select Name and Value, as shown in the code below:

As you can see, with Get-SQLDatabase we have all of the database information, such as date of creation, autoshrink configuration option and last backup date.

Every database contains objects such as stored procedures, tables, views…etc. To access these objects, we use the specific functions to each one. As I said before, SQLPSX function names are quite intuitive, so to access the stored procedures collection and properties of each stored procedure of the ObiWan SQL Server instance and AdventureWorks2012 database we use the Get-SQLStoredProcedure:

The function has the parameter -name, and that means to access the properties of a particular stored procedure, say uspGetBillOfMaterials, and just pass its name as a parameter:

We can select the properties Name, DateLastModified, CreateDate, and whether a stored procedure is set for replication by just piping Get-SQLStoredProcedure output to the Select-Object cmdlet:

There are a number of database objects you can get this way. In this example, we’ll get information about tables using the function Get-SQLTable:

Note: The function Get-SQLTable has some parameters to filter the table name and schema. For a complete explanation of the function type Get-Help Get-SQLTable -full

In the case of the tables we can go deeper and view all the properties of its indexes using the Get-SQLIndex function:

Figure 3 shows all the properties that the function Get-SQLIndex returns:

1911-Figure4.3-ab24f0b4-7df1-44ae-8057-1

Figure 3 -All properties from Get-SQLIndex

Once we have the index objects, we can return fragmentation information using the Get-SQLIndexFragmentation function. To check how fragmented the indexes of the Person table are, just type:

We can see that the object returned from this function has several properties and that one of them is the AverageFragmentation. This means that we can filter by fragmentation, choosing only those indexes above 50% fragmentation, by using the code:

This way, we can use the formula to check whether fragmentation is greater than 10% and less than 30% and the page count> 1000, and if it is, we reorganize the index, otherwise we rebuild it using the functions Invoke-SQLIndexDefrag and Invoke-SQLIndexRebuild. The following listing shows the code to perform this operation for all tables and indexes in the database Adventureworks2012 and ObiWan SQL Server instance:

Listing – Performing Reorganize or Rebuild Indexes

As you can imagine from this listing, we can perform a complex operation with a few command lines that can be applied to all tables and indexes. There are many functions that SQLPSX have for Database and Server information, more than we can list here. For the full list type:

Scripting SQL Server Objects

As we saw at the beginning of the article, scripting SQL Server objects using SSMS can be a painful operation for a busy DBA with responsibility for many servers and databases, especially if you need to automate this process.

The function Get-SQLScripter fills this gap precisely. With it you have the flexibility needed because you can get the T-SQL script to CREATE or DELETE any SQL Server object. Let’s say you need to script the stored procedure uspGetWhereUsedProductID in the AdventureWorks2012 Database and QuiGonJinn SQL Server instance, the code is :

In this case the output is returned to the screen, but we can direct to a .sql file by just piping it to the Out-File cmdlet:

Similarly you can perform this operation with any other SQL Server object, such as tables, views or triggers.

Another very important group of options in the scripting process using SQLPSX are the ones that control the many ways that the scripting can be performed, such as adding "If Not Exists" at the beginning of the script to create the object only if it doesn’t already exist, or opting whether to specify the Collation clause when scripting Tables. In this case you have to set a variable with the New-SQLScriptingOptions function and select the options that you are interested in. The example below demonstrates how to add "IF Not Exists" in the script of the stored procedure uspGetWhereUsedProductID:

To add the “If Not exists”, but remove the “Collate” clause in the script in the Vendor table:

The Figure 4 illustrates the output:

1911-Figure4.4-9b2a8f77-5c55-4b12-8d7f-c

Figure 4 -Vendor table with scripting options

As you can see, SQLPSX simplifies a very important task in the DBA’s day-to-day job. To return all scripting options used in New-SQLScriptingOptions function, type:

Deploy your first solution using SQLPSX

Anyone with many SQL Server instances to manage will need to automate the process of gathering information about the server-level configuration (sp_configure) of each one. For better organization, this process should be run monthly, and it is likely that you’ll need to store this information as a CSV file in a given path, with separate folders for each instance.

The work window you have for this process is not very large, so the process has to run as fast as possible, so synchronous mode is out of the question. One way to do this is to create a T-SQL script in each instance and run it with a SQL Agent job in each one. We can also think of creating an SSIS package to run this script on all servers, but both solutions have their limitations compared with using PowerShell.

If you were to use SSIS to create a flexible solution, you must create a separate step to gather instance information and configure the SSIS package for run each instance in turn asynchronously. You must have an advanced knowledge of the SSIS tool, and the means to maintain the package, so this may be difficult if you don’t have the SSIS prowess in-house.

if we’re serious about flexibility and minimizing the impact of maintenance, you definitely will not want to create or run a T-SQL script and SQL Agent job in each instance.

With PowerShell and SQLPSX, you have fewer lines of code, and you can run it on any SQL Server instances you can access. That’s because they are listed in a .txt file. If you want to add a new instance in the gathering or remove one, simply change the .txt file.

In addition, we have the PowerShell function Split-Job, which is part of the Functions.PSM1 module in the Toolkit file, which in turn to run the collection for each instance on a separate runspace and controlling it queue, or in other words, using asynchronous mode.

Before looking at the code, let’s look at and document the process flow. This is shown in Figure 5

Note: When using the term “Runspaces” I’m referring to the method of creating an instance of PowerShell from the command line, which you can interact with, by creating and modifying its elements, as providers, commands or functions. It is something like you open a new PowerShell session, but using command line. For a further reader, look at MSDN Link http://bit.ly/SrtrFV.

1911-poshdbaimage.PNG

Figure 5 -Flowchart for the process of gathering information from SQL Server instances

Now that we understand the process, let’s see the code. It is displayed in this Listing:

Listing – Gathering SQL Server instances information – Server level

The process (C), Split-Job, has some interesting parameters to check :

The -InitializeScript is the modules that I want to import and the -Variable parameter sends the variables chosen to the runspace. This is required because as the process inside Split-Job will run in another runspace, all the variables and functions from SQLPSX will be not visible.

The next step is create a path called C:\DocSQL and save this script as ListSQLInfo.ps1.Now it is just to navigate to the C:\DocSQL and run the script, typing:

The output will be the information from all SQL Server instances listed in the .txt file, in separated folders with the specific CSV for every instance inside them as shown by Figure 6

 1911-clip_image006-300x175.jpg

Figure 6 -Specific folders to each SQL Server instance

If we navigate to the folder ObiWan_Inst1 we will find the Obiwan_INST1_20121019_0913.CSV file, as shown in Figure 7:

 1911-clip_image007-380x151.jpg

Figure 7 – CSV File to the ObiWan\Inst1 SQL Server instance with the information gathered

And, by opening the ObIWan_Inst1_21021019_0913.csv file in Excel, we will have all the information gathered for the ObiWan\Inst1 SQL Server instance. The file has 133 lines of configurations options and Figure 8 illustrates some of them:

1911-Figure4.9-4c0d3053-f870-4f9e-b6cf-0

Figure 8 -First properties of the ObiWan\Inst1 CSV File

Now we need to automate this process. Let’s use the SQL Agent job for this. On the machine that will run the script, create a SQL Server Agent Job called GatheringInstanceInfo and add a step type CmdExec. Call it Step_1 and type in the command line:

Figure 9 illustrates the process:

1911-Figure4.10-38a2f850-da9d-467a-b8e6-

Figure 9-Creating a SQL Server Agent Job to run the script

Okay, now we only need to schedule the job to run monthly and we have the process completely automated. After all, it is all about solutions. Just remember that the account that is running the SQL Agent job needs to have rights to create the files.

Summary

One of the tools that is designed to buy time for the busy DBA is SQLPSX. It works with PowerShell and SMO to make it all easier and quicker to use. We covered how to install SQLPSX and why to use it. The next step was driving into some day-to-day examples, as listing SQL Server instances information and Databases.

In order to show that its power went way beyond mere information-gathering, we also showed to perform a very important operation, to check a table’s fragmentation and how to fix it. To finish the article, we deployed our first solution using SQLPSX and learned how to schedule it in the SQL Server agent jobs.

Downloads

Tags: , , , , , , ,

  • 17258 views

  • Rate
    [Total: 18    Average: 4.8/5]
  • Jorge Serres

    Defrag part:Get-SqlDatabase
    Hi Laerte,
    good article but it’s got some errors! pls review it b4 posting otherwise makes us doubt quality….I do like your articles and trust the code. However, I usually catch some errors…the index defrag does not work smoothly…It’ll miss out on some tables

  • Laerte

    Get-sqldatabse
    Sure Jorge, but can you be more specific my friend ? I dont get any bugs doing here. Error message it wiould be good. Also, you can ping me at laertesqldba@outlook.com

  • demisco

    Running .ListSQLInfo.ps1
    Hello,

    Very nice article. I have a strange issue though. Trying to run the ListSQLInfo.ps1 and it gives me the error below:

    PS C:DBAPOSHScripts> .ListSQLInfo.ps1
    Missing closing ‘}’ in statement block.
    At C:DBAPOSHScriptsListSQLInfo.ps1:40 char:59
    + Remove-variable Timestamp -ErrorAction SilentlyContinue #Z <<<<
    + CategoryInfo : ParserError: (CloseBraceToken:TokenId) [], ParseException
    + FullyQualifiedErrorId : MissingEndCurlyBrace

    I run out of ides 😛

    Thanks a lot
    demisco

  • Running .ListSQLInfo.ps1

    Laerte
    Demisco, I am running without problems. Do you have the functions.psm1 and sqlpsx in some of the $psmodulepath variable, or in case of the posh2.0 in your profile ? what is posh and sql version ? I am running 3.0 and SQL 2012. Are you sure that you copy the full code in the page ? Tkx man

  • demisco

    Running .ListSQLInfo.ps1
    I have functions.psm1 and sqlpsx in C:WindowsSystem32WindowsPowerShellv1.0Modules
    The $ENV:PSModulePath points to C:UsersmyusernameDocumentsWindowsPowerShellModules;C:Windowssystem32WindowsPowerShellv1.0Modules
    The version of powershell is 2.0
    SQL Version is 2008 R1
    I do not have any profiles……..i was using the command import-module to load the required modules (Functions and SQLPSX) into my powershell command line.
    I copy/pasted the code and verified may times that it was correct 🙂

    Thanks a lot for your time and reply.

  • Laerte

    Running .ListSQLInfo.ps1
    My friend, can you ping me at laertesqldba@outlook.com ? lets see what is happeing . Thanks 🙂

  • Laerte

    Error Message
    Guys, already sent the ListSQLInfo.ps1 to the Editor Team to download, please do not copy and paste the code 🙂

  • Laerte

    Error Message
    Or if you do it, check for wild chars in the end of these linesand remove it 🙂

    Out-File (join-path $PWD -ChildPath "DocError.txt") –Append #V
    }
    } else {
    $ErrorMessage = "$(Get-date) – SQL Server Instance $($_) unreachable" #X
    Write-Warning $ErrorMessage #Y
    $ErrorMessage |
    Out-File (join-path $PWD -ChildPath "DocError.txt") –Append #V

  • Andrew Clarke

    re: Running .ListSQLInfo.ps1
    The file is now in the head of the article, in the grey box next to the title