Powershell and .NET Objects

Now that we’ve covered SQLCMD.exe with the command prompt I’d like to dive into the present and future of Windows command line, Powershell. One of the great things about Powershell is that for every task there are always multiple ways to tackle it. In this blog series I will be covering three different methods of establishing a SQL Server connection and executing a query. Of those three ways there are different situations where you might be forced to pick one over the other but we’ll get into that as I cover each.

Why this method?

I think all DBAs will agree that, given the option between command prompt and Powershell, you should always use Powershell. Powershell has all of the capabilities as command prompt plus so much more. So, now that you’ve chosen Powershell and verified that you have it installed; why would we use .NET?

Powershell exposes the entire .NET framework to the script writer so, naturally, you can use the exact same .NET objects to build your SQL connection, execute queries, and retrieve the results. There are, however, other methods of using Powershell to interact with SQL Server, as mentioned above.

Recently I needed to have a T-SQL script file executed on an entire active-active topology of SQL Server. The scripts were related to peer-to-peer replication, I could not predict how the code would change by the developers in the future, it had to be run outside of the individual node’s SSDT dacpac deployments, and it had to snap into their continuous integration seamlessly. They already had a requirement to run their deployment agents on Server 2008 R2 or above so I could assume I had access to Powershell 2.0 but couldn’t count on the deployment agent having any of the SQL modules installed. So, in an effort to write re-usable code that was flexible and didn’t impose any new requirements on the change management team, I chose to use .NET. This method does not require anything that is not native to Windows Server 2008 R2 or higher.

 How to use it

First off, I highly recommend using the Windows Powershell ISE which comes prepackaged with Windows 7 and 8. If you are running Windows Server or just don’t want to use the ISE then the normal Powershell console will work just fine as well.

We are going to start off by establishing our variables. The timeout settings seen below are optional but I like to include them in case the defaults need adjustment at a future date.

$ConnectionTimeOutInSeconds = 30;
$CommandTimeOutInSeconds = 30;
$server = 'localhost\SQL2008R2';
$database = 'master';

Next we will; instantiate the SQLConnection object, set the connection string, and open the connection.

# establish connection
$Conn=New-Object System.Data.SQLClient.SQLConnection "Server=$server;Database=$database;Trusted_Connection=Yes;Connection Timeout=$ConnectionTimeOutInSeconds;";
$Conn.Open();

We will then instantiate the SqlCommand object and set the command timeout.

# instantiate command object
$DataCmd = New-Object System.Data.SqlClient.SqlCommand;
$DataCmd.CommandTimeout = $CommandTimeOutInSeconds;

This next snippet will extract the T-SQL text from a file and load it into the $MyQuery variable

# extract T-SQL
$sqlFile = 'C:\Fake_Test_File.sql';
$MyQuery = (get-content ($sqlFile));

Alternatively, you may also hard code the query like so.

$MyQuery = "SELECT `'Don`'t forget to subscribe to the SQLHammer.com RSS feed.`'";

Next we will set the command object’s connection property and execute. This first example is for a non-query such as DML commands.

# associate command to connection
$DataCmd.Connection = $Conn;
# execute script
$DataCmd.ExecuteNonQuery();

This second example is to execute a query and print the results to the console.

$reader = $Conn.ExecuteReader("SELECT Name, CostRate FROM Production.Location")
while ($reader.Read())
{
   $name = $reader.GetValue(0);
   $cRate = $reader.GetValue(1);
   Write-Host $name,"(",$cRate,")"
}

Finally, we collect the garbage.

# clean up
$Conn.Close();
$Conn.Dispose();

Full script – non-query

##############################################
# Set Variables
##############################################

$ConnectionTimeOutInSeconds = 30;
$CommandTimeOutInSeconds = 30;
$server = 'localhost\SQL2008R2';
$database = 'master';

##############################################
# Execute scripts
##############################################

# establish connection
$Conn=New-Object System.Data.SQLClient.SQLConnection "Server=$server;Database=$database;Trusted_Connection=Yes;Connection Timeout=$ConnectionTimeOutInSeconds;";
$Conn.Open();

# instantiate command object
$DataCmd = New-Object System.Data.SqlClient.SqlCommand;
$DataCmd.CommandTimeout = $CommandTimeOutInSeconds;

# extract T-SQL
$sqlFile = 'C:\Fake_Test_File.sql';
$MyQuery = (get-content ($sqlFile));

# associate command to command text
$DataCmd.CommandText = $MyQuery;

# associate command to connection
$DataCmd.Connection = $Conn;

# execute script
$DataCmd.ExecuteNonQuery();

# clean up
$Conn.Close();
$Conn.Dispose();

Full script – query read

##############################################
# Set Variables
##############################################

$ConnectionTimeOutInSeconds = 30;
$CommandTimeOutInSeconds = 30;
$server = 'localhost\SQL2008R2';
$database = 'master';

##############################################
# Execute scripts
##############################################

# establish connection
$Conn=New-Object System.Data.SQLClient.SQLConnection "Server=$server;Database=$database;Trusted_Connection=Yes;Connection Timeout=$ConnectionTimeOutInSeconds;";
$Conn.Open();

# instantiate command object
$DataCmd = New-Object System.Data.SqlClient.SqlCommand;
$DataCmd.CommandTimeout = $CommandTimeOutInSeconds;

# extract T-SQL
$sqlFile = 'C:\Fake_Test_File.sql';
$MyQuery = (get-content ($sqlFile));

# associate command to command text
$MyQuery = "SELECT `'Don`'t forget to subscribe to the SQLHammer.com RSS feed.`'";

# associate command to connection
$reader = $Conn.ExecuteReader($DataCmd.CommandText);
while ($reader.Read())
{
   $name = $reader.GetValue(0);
   $cRate = $reader.GetValue(1);
   Write-Host $name,"(",$cRate,")"
}

# clean up
$Conn.Close();
$Conn.Dispose();

What’s next?

In the next part of this blog series we will look into how to use the SQLPSX community built Powershell module.

Navigation

  1. Part 1 – Introduction
  2. Part 2 – SQLCMD.exe using command prompt
  3. Part 3 – .NET objects using Powershell
  4. Part 4 – SQLPSX using Powershell (SQL Server 2000 and above)
  5. Part 5 – SQLPS using Powershell (SQL Server 2012 / 2014)