Open Source SQLPS

I first saw PowerShell in 2007 or 2008 at TechEd. I was both fascinated and excited, finding the idea of using command line tools both nostalgic as well as handy. Certainly there have been a number of file based operations I’ve wanted to do in SQL Server in the past that weren’t easy to accomplish in DOS-style programming and even less easy in T-SQL. VBScript worked, but it was a very cumbersome, error prone method of developing scripts.

PowerShell (PoSh) seemed elegant, and I was excited to have it come to SQL Server and integrate with SMO. SQLPS was released as a first step, but it was again cumbersome and poorly integrated into SQL Server. I found it to be more of a pain than a help, and abandoned using it. Since then I’ve tended to build my own scripts using techniques from our Powershell Tool Time series to help.

However plenty of PoSh experts I know like the SQLPS module, but they want it improved. Apart from asking for a few changes in SQL Server 2016, there is a Connect item to open source the module. It’s an interesting idea, and certainly it does appear the Microsoft is unwilling to put many resources into SQLPS. If that’s the case, why not open source the tools? Is there any revenue impact?

I’d argue that this is one of those areas that starts to exceed the scope of what MS can accomplish when it’s not a priority. Just like the opening of Windows Live Writer, allowing the community, including MS employees, to donate their own time to fixing and expanding the tool could allow this to flourish and grow, perhaps even helping SQL Server adoption.

I’m certainly not a PoSh expert, but I’m curious. If you use PoSh, would you want a SQLPS module maintained as an Open Source product? Whether you do or not, what do you think about opening up ideas like this for public viewing and pull requests to integrate changes back into the product?

Steve Jones

The Voice of the DBA Podcast

Listen to the MP3 Audio ( 2.8MB) podcast or subscribe to the feed at iTunes and LibSyn.

PowerShell–Don’t Use Write-Host

I’ve written a few scripts and programs lately, mostly just for fun. In those scripts, I’ve used Write-Host to return output. To me, it’s been like “Print” in various languages where I can get output of a program. Often I’ll use a method/function to get info and then use print to output that to the caller.

However a few people noted that in my last script, Write-host wasn’t necessary. When I asked why, both Mike Fal and Drew Furgiule responded. I got these two items:

I learned something new today. I had assumed that I’d need a way to get the output to the screen and manage output with my own logic. I’ve had this before

$debug = 1

if $debug  = 1 { write-host $somevariable}

However a quick check shows this isn’t really what I want. Instead, I’d use Write-Debug or Write-Verbose. A quick test shows I can do this:

2016-03-02 12_10_16-Windows PowerShell ISE

That’s much better than passing in a debug parameter or changing a value as I run scripts.

Looks like I have some refactoring to do.

Quick Folder Size with PowerShell

This is a fairly simple idea, and one I’m sure many people have done in the past. Personally, I have tended to just hover a mouse over a folder when I want a size. That seems to work fairly well, but not only is it slow, it’s not programmatic.

2016-02-25 10_24_01-Settings

I saw Jose Barreto write a quick OneDrive size script in PowerShell (PoSh), and thought it was interesting. It didn’t work for me as I’ve moved the OneDrive folder to my D: drive, so I had to alter this to get information. However in doing so, I decided to play with a function.

Here’s the code I used, altering Jose’s slightly.

UPDATE: Thanks to Mike Fal, one of my go-to PoSh experts, I’ve removed the aliases for Dir and %.

function Get-FolderInfo($folder) {
$OneDrives = $folder
Get-ChildItem $OneDrives | ForEach-Object {
$OneDrive = $_
Get-ChildItem $OneDrive -Recurse -File -Force | ForEach-Object {
$Bytes += $_.Length
$Folders = (Get-ChildItem $OneDrive -Recurse -Directory -Force).Count
$GB = [System.Math]::Round($Bytes/1GB,2)
Write-Host “Folder ‘$OneDrive’ has $Folders folders, $Files files, $Bytes bytes ($GB GB)”

Note that I’ve passed in the folder name and then kept Jose’s code. This worked fine for me, as you can see below.

2016-02-25 10_24_11-Windows PowerShell ISE

The next step for me was to make this programmatic and useful. All that text isn’t helpful. What I really want is just a size. I guess I need a folder name as well, so I built a function to return that information. I merely changed the last line to:

  Write-Host “$GB”

I also moved this to the end of the function, rather than for each subfolder. With this change, I can now call this for a folder and get the size in GB returned.

2016-02-25 10_31_22-Windows PowerShell ISE

And this checks out from Windows

2016-02-25 10_31_16-Settings

I know there are better ways to write this function, but this was more of a programming exercise. This was really a 10 minute chance to practice and experiment a bit with PoSh and work on skills.

BTW, I used dot sourcing to load this as a function I could callIn love

2016-02-25 10_33_42-Jump List for VMware Workstation Pro

Hash Tables in PowerShell–Advent of Code Day 3

I continue to work on solving the Advent of Code puzzles in both PowerShell and T-SQL after completing them in Python.

When I hit day 3 in PowerShell, it was a few new tricks to learn, one of which was reading a large string from a file. However the interseting thing for me was learning to work with hash tables.

The Day 3 puzzle looks at moving Santa around on a grid. We don’t know the size or shape of the grid, just that we get directions in 1 of 4 ways (^<>V) and then must move to a new house. The first puzzle asks how many houses get one present.

This is interesting, and naturally to me the first thing that occurs is a dictionary. I used one in Python, adding new elements as I received new coordinates. I wasn’t sure how to do this in PowerShell, and ended up searching a bit about two dimensional arrays, thinking I could perform a count there, adding indexes as needed. However I ran into hash tables while searching, and this was a better solution for me.

The short part of working with hash tables is that you declare them with a simple command. In my case, since I had a delivery at coordinates (0,0), I wrote this:

$houses = @{“0,0” = 1}

This uses the @{} syntax to set up a key value pair. Essentially a dictionary. From here, I computed new “keys” from the directions, and could add new values like this:

$houses.Add(“1,1”, 1)

Of course, I had to check for existing values, and if there were existing values, I had to increment them.

$houses.Set_Item(“1,1”, $houses[“1,1”] + 1)

With that code, I could easily solve the puzzle. However I was struck by the various ways I work with the hash tables. I use braces, {}, to declare the table. I use brackets, [], to access elements and then parenthesis, (), when calling methods. All of that makes programming sense, but it’s something to keep in mind, especially as those three marks mean different things in Python.

I also learned how to search with ContainsKey and ContainsValue, as well as how to Set_Item and Get_Item, which didn’t appear to work with the ISE Intellisense.

All in all, it was interesting working with a hash table and good to learn PowerShell supports them. They are very handy constructs when building up a set of data that you’ll need to work with, and you need more than the simple buckets an array provides.

Advent of Code Day 1, Puzzle B

As I continue through the Advent of Code, albeit slowly, I’m solving each puzzle 3 days. I worked through 6 of them in Python before moving on to other languages, and this is my chance to catch up with both PowerShell and T-SQL. I likely won’t post all solutions, but I was having fun rewriting code, so here are the ways I looked at things.


Note: You should try this on your own. I logged into the AventofCode with GitHub and things worked great for me.


Go on, give it a try.


I’ll wait.


Solutions coming.




I started here, using iterations, which are very powerful in Python. In this case, I took advantage of the multiple variable assignment in Python to enumerate the array and get each value and index. I think use a comparison to determine if I add or subtract one. Finally, an IF returns the current index if I hit –1. I should probably have a break in there for efficiency as well.

def calculate_negative(directions):
start = 0
for i, c in enumerate(directions):
if c == '(':
start += 1
start -= 1
if start == -1:


This was a bit trickier for me. I wasn’t sure how to work with a string and pull out values. I did some searching and ran across the .ToCharArray function. That doesn’t feel like the best way to do this, but I decided to use it.

The rest of the function is similar and gave me the correct answer, so there you go.

$count = 0
$floor = 0
foreach ($c in $input.ToCharArray())
if ($c -eq '(') {$floor += 1}
elseif ($c -eq ')') {$floor -= 1 }
$count += 1
if ($floor -eq -1)


A more complex situation here, given that we need to work through a string, calculating a running total. I broke the input up using a tally table and a splitter with substring. This was fairly easy, and not complex as I was just getting individual charaters.

Then it was a simple running total of the CTE to get me the totals at each point in time. This worked well, but I needed the first –1 total.

Finally, I used the outer query to get the min value out of the code and use that, which gave me the lowest value where the –1 occurred.

WITH tally (n)
FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) a(n) -- 10
CROSS JOIN (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) b(n) -- x 10 = 100
CROSS JOIN (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) c(n) -- x 10 = 1000
CROSS JOIN (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) d(n) -- x 10 = 10000
, direction (n, d)
SELECT tally.n
, d = CASE WHEN SUBSTRING(@input, n, 1) = '(' THEN 1 ELSE -1 end
FROM tally
), currfloor
, 'currentfloor' = SUM(d.d) OVER (ORDER BY d.n ROWS UNBOUNDED PRECEDING)
FROM direction d
SELECT MIN(currfloor.n)
FROM currfloor
WHERE currentfloor = -1

Advent of Code Day 1, Puzzle A

I have been working my way through the Advent of Code series across the last few weeks. This is a side project, allowing me to use some Python skills to solve the various puzzles. I also started to use PowerShell to solve the puzzles, mostly becauase this means I practice new skills.

Note: I urge you to try to work on this yourself, withough reading my solutions. It’s fun and worth some practice. Once you’ve done that, feel free to read on.

Go ahead

Write your own.

Here’s the input:

DECLARE @input VARCHAR(MAX) = ‘()(((()))(()()()((((()(((())(()(()((((((()(()(((())))((()(((()))((())(()((()()()()(((())(((((((())))()()(()(()(())(((((()()()((())(((((()()))))()(())(((())(())((((((())())))(()())))()))))()())()())((()()((()()()()(()((((((((()()())((()()(((((()(((())((())(()))()((((()((((((((())()((()())(())((()))())((((()())(((((((((((()()(((((()(()))())(((()(()))())((()(()())())())(()(((())(())())()()(()(()((()))((()))))((((()(((()))))((((()(()(()())())()(((()((((())((((()(((()()(())()()()())((()((((((()((()()))()((()))()(()()((())))(((()(((()))((()((()(()))(((()()(()(()()()))))()()(((()(((())())))))((()(((())()(()(())((()())))((((())))(()(()(()())()((()())))(((()((()(())()()((()((())(()()((())(())()))()))((()(())()))())(((((((()(()()(()(())())))))))(()((((((())((((())((())())(()()))))()(())(()())()())((())(()))))(()))(()((()))()(()((((((()()()()((((((((()(()(())((()()(()()))(())()())()((())))()))()())(((()))(())()(())()))()((()((()(()()())(())()()()((())())))((()()(()()((()(())()()())(((()(()()))))(())))(()(()())()))()()))))))()))))((((((())))())))(()(())())(()())))))(()))()))))))()((()))))()))))(()(()((()())())(()()))))(((())()))())())())(((()(()()))(())()(())(())((((((()()))))((()(()))))))(()))())(((()()(()))()())()()()())))))))))))))(())(()))(()))((()(())(()())(())())(()())(())()()(()())))()()()))(())())()))())())(())((())))))))(())))(())))))()))))((())(()(((()))))(()))()((()(())))(()())(((((()))()())()()))))()))))()))())(()(()()()))()))))))((()))))))))))()((()))((()(())((())()()(()()))()(()))))()()(()))()))(((())))(())()((())(())(()())()())())))))))())))()((())))()))(()))()()))(((((((()))())(()()))(()()(()))()(()((()())()))))))(((()()()())))(())()))()())(()()))()()))))))))(())))()))()()))))))()))()())))()(())(())))))()(())()()(()()))))())((()))))()))))(()(((((()))))))))())))())()(())()()))))(())))())()()())()()())()(()))))()))()))))))))())))((()))()))()))())))()())()()())))())))(()((())()((()))())))))())()(())((())))))))))))())()())(())())())(()))(()))()))())(()(())())()())()()(()))))(()(())))))))(())))())(())))))))())()()(())())())))(())))))()))()(()())()(()))())())))))()()(()))()))))())))))))))()))))()))))))())()())()()))))()())))())))))))))))()()))))()()(((()))()()(())()))))((()))))(()))(())())))(())()))))))(()))()))))(())())))))()))(()())))))))))))))())))))))))()((()())(()())))))))((()))))(())(())))()(()())())))())())(()()()())))()))))))())))))())()()())))))))))))()()(()))))()())()))((()())(()))))()(()))))))))))()())())(((())(()))))())()))()))()))))))()))))))(()))))()))))()(())))(())))(()))())()()(()()))()))(()()))))))))()))(()))())(()()(()(()())()()))()))))))))(())))))((()()(()))())())))))()))())(()())()()))())))()(()()()()))((())())))())()(()()))()))))))))(()))(())))()))))(()(()())(()))))()())())()))()()))())))))))))))())()))))))()))))))))())))))()))))())(()())))(())()))())())))))()()(()()())(()())))()()))(((()))(()()()))))()))))()))))((())))()((((((()()))))))())))))))))))(((()))))))))))))(())())))))())(()))))))(()))((()))())))()(()((()))()))()))))))))))())()))()(()()))))())))())(())()(()))()))())(()))()))))(()()))()()(())))))()))(())(()(()()))(()()())))))(((()))))))()))))))))))))(())(()))))()())())()()((()()))())))))(()))))())))))))()()()))))))))())))()(((()()))(())))))(((())())))))((()))()(()))(()))))(()())))(()))())))))()))))(())(())))()((()))(())())))()()))()))))))))()))(()()()(()()()(()))())(())()())(((()))(())))))))))(((()())))()()))))))))()(())(()))()((((())(())(()())))()))(((())()()()))((()))(()))())())))())))(()))())()())())(()(())())()()()(())))())(())))(())))(())()))()))(()((()))))))))())(()))))))())(()()))()()))()(()(()())))()()(()((()((((((()))(())))()()()))())()))((()()(()))())((()(()(()))(()()))))()())))()))()())))))))()()((()())(())))()))(()))(())(()))())(()(())))()()))))))(((()(((()()))()(()(())())((()()))()))()))()))()(()()()(()))((()())()(())))()()))(((())()()())(())()((()()()()(()(())(()()))()(((((()())))((())))))(()()()))))(((()(())))()))((()((()(())()(()((())))((()())()(()))(((()())()()(()))(())(((()((()())()((())()())(((()()))((()((())(()))(()())(()()()))((()))(())(()((()()())((()))(())))(())(())(())))(()())))(((((()(()(((((()())((((()(()())(())(()()(((())((()(((()()(((()()((((((())))())(()((((((()(()))()))()()((()((()))))()(()()(()((()()))))))(((((()(((((())()()()(())())))))))()))((()()(())))(())(()()()())))))(()((((())))))))()()(((()(()(()(()(()())()()()(((((((((()()())()(()))((()()()()()(((((((()())()((())()))((((((()(()(()(()())(((()(((((((()(((())(((((((((())(())())()))((()(()))(((()()())(())(()(()()(((()(())()))())))(())((((((())(()()())()()(((()(((())(()(((())(((((((()(((((((((()))(())(()(()(()))))((()))()(())())())((()(()((()()))((()()((()(())(())(()((())(((())(((()()()((((((()()(())((((())()))))(())((()(()((())))(((((()(()()())())((())())))((())((()((()()((((((())(((()()(()())())(()(()))(()(()))())())()(((((((()(((()(())()()((())((()(()()((()(()()(((((((((((())((())((((((())((()((((()(()((((()(((((((())()((()))))())()((()((((()(()(((()((()())))(())())(((()(((())((((((()(((((((((()()(())))(()(((((()((((()())))((()((()((()(()()(((())((((((((((((()(((())(()(((((()))(()()(()()()()()()((())(((((((())(((((())))))())()(()()(()(()(((()()(((((())(()((()((()(((()()((()((((())()))()((((())(())))()())(((())(())(()()((()(((()()((((((((((()()(()())())(((((((((())((((()))()()((((())(()((((()(((())())(((((((((((()((((())))(())(()(((()(((()((())(((((()((()()(()(()()((((((()((((()((()(()((()(()((((((()))))()()(((((()((()(()(())()))(())(((((((()((((()())(()((()((()(()))())))(())((()))))(((((((()()()())(()))(()()((()())()((()((()()()(()(()()))(()())(())(((((()(((((((((((()((()(((()(((((((()()((((((()(((((()(()((()(((((())((((((()))((((())((()()((())(((())()(((((()()(((((()((()(()(((((((()(((((()((()((()((())(())((())(()))()()))(()()(()(()()(((((((()(((()(((())()(((((()((((((()())((((())()((()((()(()()())(()))((((()()((((((()((()(()(()((((()((()((())((((((()(()(())((((((()((((((((((()((())()))()(()(()(((((()()()))((())))()(()((((((((((((((()(((()((((()((())((()((()(((()()(()(((()((())(()()())))()(()(()(((((()()(()(()((((()(((((())()(()(()))(((((()()(((()()(())((((((((((((((())((())(((((((((((())()()()(())()(()(()(((((((((())(((()))(()()())(()((((()(())(((((()())(())((((((((())()((((()((((((())(()((()(())(((()((((()))(((((((((()()))((((()(())()()()(())(()((())((()()))()(((())(((((())((((((()()))(((((((((()((((((())))(((((((()((()(()(())))())(()(()))()(((((()())(()))()(()(())(((()))))())()())))(((((()))())()((()(()))))((()()()((((((()))()()((((((((())((()(()(((()(()((())((()())(()((((())(()(((()()()(()(()()))())())((((((((((())())((()))()((())(())(())))())()(()()(())))())(()))(((()(()()(((()(((())))()(((()(())()((((((())()))()))()((((((()(()(((((()())))()))))())()()(((()(((((())((()()(()((()((()(()(()(())))(()()()()((()(())(((()((()))((((()))())(())))())(()))()()()())()))(((()()())()((())))(())(()()()()(()())((()(()()((((())))((()((()(())((()(()((())()(()()(((()())()()())((()))((())(((()()(())))()()))(((()((())()(((((()())(())((())()())())((((((()(()(((((()))(()(‘;

Now solve it.

Your turn.

Here come my solutions, so don’t scroll down until you’re ready.




I’ve been trying to learn Python, so this was a good chance to practice. Day 1 is fairy simple in Python, since I can do a .count of a string. In my case, I made a function that takes the input and does a count of a particular string.

def calculate_floor(directions):
print(str(directions.count('(') - directions.count(')')))

This function takes the input and counts the number of open parenthesis, an up, and then subtracts the count of the close parenthesis, the down. I print that, and with the input given on the site, this gives me the correct answer.


I have been trying to improve my PowerShell skills, and this doesn’t really help with lots of the types of things I do in PoSh, but it does help me learn a bit more about the language and practice some code.

In this case, I take a similar approach, which may not be the best. I start by converting the input to an array and then using Where-Object to look for the open parenthesis. I do the same for the close, and then subtract. I don’t know if I could do this in one statement, and didn’t research much. What I found wasn’t helpful, but I was able to solve the puzzle. Perhaps someone will tell me if I can assign two variables at once with different counts.

I did try RegEx, but coulnd’t get it to work, so I moved on. Perhaps I’ll go back to that. Input abbreviated.

$input = ‘()(((()))(()()()((((()(((())(()(()((((((()(()(((()’

$up = ($input.ToCharArray() | Where-Object {$_ -eq ‘(‘} ).Count
$down = ($input.ToCharArray() | Where-Object {$_ -eq ‘)’} ).Count

Write-Host(“Up:” + $up)
Write-Host(“Down:” + $up)
Write-Host(“Final:” + ($up-$down))


This was interesting to me since some of the puzzles I did in Python (I was 6 ahead when I tried new languages), required some parsing. In this case, I decided that I’d do some replacement. I thought that I wanted to count all open parens. How could I do this?

The easy way is to pull out the opens, or remove the closes. REPLACE() does this, so my up was a CTE

WITH UpFloors (UpCount)
( SELECT LEN(REPLACE(@input, ‘)’, ”)) ‘UpFloors’)

Then I did the same for the closes.

WITH UpFloors (DownCount)
( SELECT LEN(REPLACE(@input, ‘(‘, ”)) ‘DownFloors’)

Now I can put them together.

WITH UpFloors (UpCount)
( SELECT LEN(REPLACE(@input, ‘)’, ”)) ‘UpFloors’)
DownFloors (DownCount)
( SELECT LEN(REPLACE(@input, ‘(‘, ”)) ‘DownFloors’)
SELECT UpFloors.UpCount – DownFloors.DownCount
FROM UpFloors,  DownFloors

Running Powershell with Task Scheduler

Another post for me that is simple and hopefully serves as an example for people trying to get blogging as#SQLNewBloggers.

One of the things I needed to do with my SQL Saturday download process was run this automatically. I don’t want to remember to do this, so I decided to set this up on a schedule.

I ran a quick search and it seemed to be a simple process. Essentially I run the Task Scheduler application and then call my script as a parameter to the PowerShell exe. The first step is to run Task Scheduler.

2015-11-05 11_43_36-Task Scheduler

This has a list of jobs, which I found some to be interesting. I disabled Adobe and a few others. Those are really annoying. I clicked "Create a basic task".

2015-11-05 11_43_47-Task Scheduler

The basic task is a wizard to walkthrough. First enter a name and description. Use something that will help you in 5 months when this breaks.

2015-11-05 11_44_07-Create Basic Task Wizard

I decided to run this daily. It’s not a big deal to me, so I’ll let it just go.

2015-11-05 11_44_16-Create Basic Task Wizard

The time doesn’t matter, and I let it run in the middle of the day. This way I might notice it running sometimes and that will motivate me to keep working on this process.

2015-11-05 11_44_22-Create Basic Task Wizard

I want to run a program, so I choose that in the next step.

2015-11-05 11_44_29-Create Basic Task Wizard

The dialog wants to know which program. In my case, I’ll have to browse to my PoSh code.

2015-11-05 11_44_36-Create Basic Task Wizard

I pick my code and it puts the path in here. However that won’t run as is. If you’ve used PoSh, you know this doesn’t work.

2015-11-05 11_44_44-Create Basic Task Wizard

What I need to do is call powershell.exe. I found this in the reference item below and what I do is add "powershell" to the front of my file, and then use the "-file" parameter. I also enclose my PoSh script in quotes.

2015-11-05 11_44_58-Create Basic Task Wizard

When I click next, I get the warning, which I accept.

2015-11-05 11_45_05-Task Scheduler

There’s a summary after this, but I say OK to that, and then run the script from the Task Scheduler. It works perfectly, so I stop there.

Now we’ll see how it works over time. And if I get the next step working.


This was a quick process for me. A google search, a 2 minute read, and then 2 minutes to build the task.

It took maybe 10 minutes to write this post, most of which was taking the screen shots and resizing them.

You can do this.


I just used one link, which was from the Scripting Guy blog.

Ending My Loop in PowerShell Early

Another post for me that is simple and hopefully serves as an example for people trying to get blogging as#SQLNewBloggers.

I was modifying my PowerShell (PoSh) script to download SQL Saturday files recently to not re-download files. However when I did this, I also realized that I didn’t necessarily want the script to run too long.

One of the challenges of downloading the data is that I don’t know how many events exist. We don’t keep that number handy, and it changes regularly. One of the things I decided to do was run my process in a loop.

While ($i -lt 9999) {

That’s fine, but it’s not a great loop. It runs 9999 times, which isn’t what I want. It works, but it’s an unnecessary use of resources. However I don’t want to break the loop when the file file isn’t found. There have been issues generating a file, like #350, when #351 exists and is there.

I decided to use a shortcut technique I had learned as a kid. I set a variable and then incremented it when I missed a file. When the increment reaches some value, I break the loop.

I decided to use 12 as my number of missed. No good reason, but that’s what I picked. I started by putting a variable outside of the loop.

$missedXML = 0
While ($i -lt 9999) {

Then I increment this variable in the CATCH section of my error handler.

  # if we can't load the file, assume we're done for now. 
  Write-Host "error with  #" $i 

Finally, I set up an IF loop at the bottom of the loop. If I’ve missed 12 times, I break the loop by setting the counter to the last value.

$i = $i + 1
if ($missedXML -ge 12) { 
 $i = 9999 

I tested this with some debugging information and what I found was that when I got to 494, I started missing files. As soon as I hit 12, the loop ended.

Enhancement complete.


This post came about when I started working on the script. I made the modifications from the previous post and decided to also fix the extra loops with this technique.

This post took about 10 minutes to write.


No resources needed here. I’ve got enough PoSh knowledge to handle this task myself.

Test if a File Exists with Powershell

Another post for me that is simple and hopefully serves as an example for people trying to get blogging as#SQLNewBloggers.

Awhile back I wrote a PowerShell script (PoSh) to download the SQL Saturday XML files used for the Guidebook application. These contain a bunch of the information that I wanted to collect, transform, and keep around.

However the script wasn’t great. It basically looped a set number of times and re-downloaded the files. Not the more efficient solution, especially if I want this to run regularly.

One of the enhancements I wanted to make was check if the file exists, and if not, then download it. However, if it does exist, then I’ll skip the file. I know this means I don’t get updated files if schedules change, which is possible, but in that case, I can just delete the file from my desktop and go from there.

I made a quick search, and found a few links to the Test-Path cmdlet. Essentially you give this a file path and it returns true or false. Almost exactly what I need. This is what I added to my code:

if (Test-Path $DestinationFile) {

#do something


However I want to take action if the file doesn’t exist. In most languages, I’d add a ! in front to signify "not". However that doesn’t work in PoSh, just like > doesn’t mean greater than.

Another search showed me the -NOT operator. That’s what I need, but I can’t do this:

if (-NOT Test-Path $DestinationFile) {

#do something


Instead, I need to have a single expression for -NOT, which means more parenthesis. Not a big deal. I used this code:

if (-NOT (Test-Path $DestinationFile)) {

#do something


That worked great and now I only download the files I need. If I want to re-download (for newer events), I just delete those files and re-run the script.


This post came about when I started working on the script. It actually took longer to write this than find the solution, add it to code, and test it. That process was about 5 minutes.

This post took about 10 minutes to write. I also had a second post based on similar modifications to the script, so I’m did that in another 5 minutes.


A few of the links I used:

Boring or Scripting

Do you want to continue to perform boring, repetitive, mundane tasks as a part of your job? Many of you might not be challenged at work, or you might be burdened with a series of requests that repeat themselves over and over. They’re easy tasks, many of them probably take minutes. I’m sure there’s also a level of mindlessness that you find comforting at times with just working through a familiar task.

However many of you also get busy. You have no shortage of new tasks that get assigned to you on a regular basis. You probably also get stressed from your heavy workload at times. What do you do when you’re too busy to work through the mundane tasks, but they still need to be done? It can be a challenge to manage that burst in a workload if you haven’t prepared for it.

There is a way to remove some of the mundane administrative work from your job. It’s not simple, and it’s not going to solve all your issues right away, but over time, you can certainly reduce the burden of working on dull tasks over and over again, across multiple machines.

Learning PowerShell (PoSh) or some other scripting language. VBScript works fine, as does Perl, and there are others, but if you’re a Microsoft person, especially a SQL Server person, learn PoSh. It’s used in all the products, it’s becoming a standard for all Microsoft products, it works in the cloud, and it works with SQL Server. It takes some getting used to, and it certainly can help with repetitive tasks. It can also run all your SQL scripts for you, just in a more automated fashion.

You can grow your career, add a new skill, reduce your workload, and become more efficient at your job.

Or continue to be boring.

Steve Jones

The Voice of the DBA Podcast

Listen to the MP3 Audio ( 2.3MB) podcast or subscribe to the feed at iTunes and LibSyn.