Managing an HA Hyper-V Infrastructure: Part 3 – Scripting DiskPart with PowerShell

In my last installment of the “Managing an HA Hyper-V Infrastructure” series, I discussed getting volumes provisioned on the SAN.  Now that we have the volume presented to Windows, the next is to setup the disk.  In Windows 2008, this means bringing the disk online, initializing the disk, partitioning the disk, formatting the volume, and giving the volume a label.

For the longest time, I struggled with figuring out how to do this via script.  In Disk Management, this process is very easy, but with scripting, not so much.  From what I can gather, not many people out there are scripting with DiskPart, or if they are, they aren’t writing about it online.  After weeks of searching, and
finding little to no information, I decided to set out on writing my own PowerShell version of DiskPart.  Due to the complexity of this topic, I plan on dividing this one out over a few posts.  Without further ado, let’s dive in.

The first issue with DiskPart is that it has two ways it can be run, both of which aren’t very useful to us out of the box:
interactive mode and scripted mode.
Interactive mode, of course, isn’t useful for scripting.  Scripted mode requires the use of a pre-existing text file from which to call and execute a set of commands.  Since our text file is going to be different every time we need to run it based on volume name, disk number, etc., this makes DiskPart very limited in what it can do from an automation perspective.  So how can be work around this limitation?
OK, if you’ve been reading any of the previous posts, by now you already know
the answer.  Right again, it’sPowerShell.

Much like the way I created the CompCU wrapper in the previous post, we can create a PowerShell wrapper for DiskPart to allow you to run it in scripted mode, but work it interactively at the same time by passing variables, running through loops, etc., increasing flexibility exponentially.  The basic syntax for scripted DiskPart is:

DiskPart /s filename.txt

Since we have to have a file from which to call DiskPart, we need to dump all of the commands we’d like to run into a temp file, execute it, and then discard the temp file.  Here’s how we can do that:

function Run-DiskPart {
param([array]$commands)
$tempfile = [System.IO.Path]::GetTempFileName()
foreach ($com in $commands)
{ac $tempfile $com}
$output=DiskPart /s $tempfile
ri $tempfile
$output
}

Here’s an example of how we might call this function.  Let’s say that from a series of steps in my script, I know that I need to get detailed disk information on disk 3:

                $Num = 3
Run-DiskPart “select disk $Num”,”detaiL disk”

Now, let’s step through this one line at a time.  First:

                param([array]$commands)

We are allowing as input any number of commands which will find their way into our script.  In the example above, we have two commands: “select disk 3”, and “detail disk”.

Second:

                $tempfile = [System.IO.Path]::GetTempFileName()

This line is actually setting up a temp file to be used by DiskPart.  Usually, this file will live in a path something like:

                C:\Users\<username>\AppData\Local\Temp\tmp7FD2.tmp

Third:

                foreach ($com in $commands)

Here, we’re simply looping through each object in our array.  Again, from the earlier example, we have to objects: “select disk 3”, and “detail disk”.  The first time through the loop will deal with “”select disk 3”, and the second loop through will deal with “detail disk”.

Fourth:

                {ac $tempfile $com}

Here, we are adding the first command, “select disk 3” to line one of our temp file, tmp7FD2.tmp.  Since we’re inside a loop, the code will then come back through and add our second line, “detail disk”, to line two of our temp file.

Fifth:

                $output=DiskPart /s $tempfile

Here, we are actually executing DiskPart, using the script we just created, and capturing all output into the $output variable.

Sixth:

                ri $tempfile

Now that we’ve finished using our temp file, this line deletes the file.  In PowerShell, ri is an alias for remove-item, which is the equivalent of del in standard command prompt syntax.

Finally:

                $output

This line just passes back all of the output we captured when originally running DiskPart.  This output is still all just a bunch of strings, and as such, it will need a lot of parsing to become useful data.  We’ll look more at how we do that in the next installment.  For now, just know that DiskPart CAN be scripted on the fly, with full variable support, loops, etc., and can therefore become an invaluable piece in our overall scripting solution.  If you made it this far, hopefully you’ve
found how you can put this function to use in your environment. Until next
time…

Good luck, and happy virtualizing!

Managing an HA Hyper-V Infrastructure: Part 2 – Provisioning SAN Storage (on a Compellent SAN)

We’ve had a Compellent SAN for about six months, and I love 95% of the things about it.  Part of the 5% that I dislike though is no native PowerShell support (yet – stay tuned for that).  Compellent does offer a Java based scripting tool though called CompCU.jar.

Much like diskpart, ipconfig, dir, and other great and useful tools, CompCu.jar is a command line based utility which can’t easily be scripted with variables and for-each loops, and which doesn’t give output that easily lends itself to parsing.  Enter (drum roll)… PowerShell of course.

One of the (thousands of) great things about PowerShell is that with a bit of ingenuity and elbow grease you can convert just about anything to run with a PowerShell wrapper.

Here’s an example of the basic syntax for running a CompCu command on the SAN:

java -jar compcu.jar -host sancontroller -user admin  –password mypass -c “server show”

Of course the only part that ever changes is the part between the quotes at the end.  Therefore, the first order of business is to wrap everything else in a function.

Here’s how I setup the PowerShell wrapper for CompCu.jar

function san
{
param ($mystring)
cmd /c java -jar "compcu.jar" -host "dns.or.ip.of.san" -user sanusername -password 'sanpassword' -c ""$mystring""
}

Now, when I want to execute a command on the SAN, I just type something like:

san "server show"

That’s a lot less typing!  But wait, there’s more!  Now that we have the wrapper, and we’re at a PowerShell prompt, we have the full power of PowerShell at our fingertips.  So let’s say that one of the most common things we do is create a volume on the SAN and map that to all five of our cluster servers.  With a couple lines, we can extend our first function to a new super-function:

function clusterlun
{
param ($lunname)
san "volume create -name $lunname -readcache true -writecache true -size 500g -folder CLUSTER -server CLUSTERSERVER1"
san "volume map -name $lunname -server CLUSTERSERVER2 -force"
san "volume map -name $lunname -server CLUSTERSERVER3 -force"
san "volume map -name $lunname -server CLUSTERSERVER4 -force"
san "volume map -name $lunname -server CLUSTERSERVER5 -force"
}

Now, each time we want to setup a new Cluster LUN on the SAN, we can just type:

clusterlun MYLUNNAME

As opposed to:

java –jar compcu.jar -host server1 –user admin  –password mypass –c "create -name MYLUNNAME -readcache true -writecache true -size 500g -folder CLUSTER -server CLUSTERSERVER1"

java –jar compcu.jar -host server1 –user admin  –password mypass –c "volume map -name MYLUNNAME -server CLUSTERSERVER2 -force"

java –jar compcu.jar -host server1 –user admin  –password mypass –c "volume map -name MYLUNNAME -server CLUSTERSERVER3 -force"

java –jar compcu.jar -host server1 –user admin  –password mypass –c "volume map -name MYLUNNAME -server CLUSTERSERVER4 -force"

java –jar compcu.jar -host server1 –user admin  –password mypass –c "volume map -name MYLUNNAME -server CLUSTERSERVER5 -force"

That’s the difference between 684 characters (with spaces) and 20 characters for each LUN map (disclaimer – yes, I know there are ways the java version could be shortened with a bit more effort, but I’m trying to prove a point – no matter WHAT you do, PowerShell will ALWAYS be shorter, AND more flexible ).  But wait, that’s not all!

Let’s say you already have a cluster up and running with 30 mapped volumes, and you want to add another cluster node.  Normally, this involves an enormous amount of work to map all 30 LUNs to another server.  From the web-based GUI, it would probably take 15-20 minutes.  But with PowerShell, you can do that in 30 seconds or less with TWO lines of code.  That’s right.  TWO LINES OF CODE!!!! Simply put the names of your existing volumes into a text file, and run the following:

$myvolumes = get-content myvolumes.txt
foreach ($vol in $myvolumes) {san "volume map -name $vol-server CLUSTERSERVER6 -force"}

Voila!   Your server is now all mapped up and ready to be added to the cluster.

In summary, you can see that knocking out the scripting portion on the SAN is the first and integral part in getting your "scripted Hyper-V cluster solution" ready for prime time. And PowerShell comes through with flying colors in making that piece easy!  I don't have experience with other SANs, so I don't know what their scripting options are, so your mileage may vary, but believe me, it's worth the time in getting this figured out early on.  Every minute you spend doing this manually is a minute wasted, and eventually, you'll get so sick of doing things manually that you'll finally break down and script it.  So why not script it from the beginning?

<

p class=”MsoNormal” style=”margin: 0in 0in 10pt;”>Good luck, and happy virtualizing!

Managing an HA Hyper-V Infrastructure: Part 1 – Overview

So it has officially been over a year since my last post, but I have a good excuse.  I’ve spent much of the last year building out a pretty large Highly Available (HA) Virtual Infrastructure, with over 100 Hyper-V Virtual Machines across three clusters, all running on Virtualized Storage (on a Compellent SAN).  It’s not easy to scale out to 100+ machines quickly, especially when many of the tools are in their early stages of development.  Luckily, my old friend PowerShell saved the day on many occasions, becoming the thread that tied our whole solution together.  So what are the pieces involved in setting up a Virtual Infrastructure?  Well, in my environment, those tools were:

·         Windows Server 2008 Datacenter Edition
·         Windows Failover Clustering
·         Hyper-V
·         System Center Virtual Machine Manager 2008 (beta at the time)
·         Compellent Storage Center 4
·         Windows PowerShell

So what does it take to deploy an HA VM in Hyper-V?  Well, once you have a Hyper-V cluster up and running (there are many posts/articles/whitepapers already floating about on that topic, so I’ll skip it here), there a series of steps one must go through, which can be fairly painful when first learning, but which become lightning fast once you get through the learning curve (and once you decide to do EVERYTHING using PowerShell).  Here’s the general workflow:

First, everything at the storage level:

1)      Create a volume for your virtual machine on a SAN
2)      Map  that volume to all of the nodes of your cluster
3)      Bring the disk online on one node of your cluster
4)      Format and name the volume on one node of your cluster
5)      Rescan the disks on each node of your cluster
6)      Add the disk to your shared cluster storage

Next, the actual virtual machine setup (using SCVMM in our environment):

1)      Refresh the Host Cluster in Virtual Machine Manager in order to make it aware of your new SAN storage
2)      Choose from a pre-existing sysprepped virtual machine template (I’ve already set these up, and I can choose from Windows 2003, Windows 2008, etc., as well as my number of procs, amount of RAM, etc. )
3)      Allow Virtual Machine Manager to decide the best host for deployment using Intelligent Placement.
4)      Choose the disk created from the previous storage steps
5)      Kick off the Deployment
6)      Start up the machine
7)      Complete the Sysprep wizard from inside the VM

Sure, that may seem like a lot steps (and it did to me too when we first started), but you can script almost EVERY step using PowerShell, so in the end, this whole process can be completed in under 10 minutes, with about 3-4 total minutes of user interaction.  Just think about that.  Someone calls you up and says they have a new database server that needs to be up by next week (put a rush on it!), and you don’t have to rush to spec servers, get quotes , find out about availability, check shipping times, etc., and HOPE you can get it racked in time.  You just spend four minutes on spinning up the VM, (optionally wait three days so they don’t think you can actually set machines up this fast, to prevent them from taking it for granted), call them back, and tell them it’s ready.

The magic of the whole solution lies in the scripting in order to  tie it all together.  Working through all of the steps manually would take well over an hour per machine (still better than taking weeks to buy a physical server, but much longer than I want to spend), especially when you start factoring in manually mapping volumes to 5+ nodes of a cluster.  However, not a lot of people are using these technologies yet, so there wasn’t much guidance in scripting that area.

My main hope over the next several posts is to provide what I’ve learned along the way, along with the scripts I’ve written, to help more people hop on board the virtualization train.  I’m certain that it’s picking up steam, and over the next year, you can either join in or be left behind.  Good luck, and happy virtualizing!