One little known fact is that you can use the PowerShell pipeline to actually feed information into a native command. Why would that be breath taking?
Automating Native Commands
Because there are tools like DiskPart. They are important but they only support an interactive mode or batch files. With the PowerShell pipeline, you can feed your commands into the native command as if you had typed them in interactively. Now, isn't that awesome?
Before you try for yourself, be aware that DiskPart requires admin privileges. So on a box with UAC, make sure you launch PowerShell with full admin rights in the first place. If you don't, DiskPart will elevate itself automatically and break the pipeline.
Let's try and get the list of drives:
"list disk" | diskpart
It works. The result is plain text, and of course you probably get a lot more information than you wanted. Fortunately, DiskPart indents the important information so you could add a little filter, letting through only lines that start with two blank spaces:
"list disk" | diskpart | ? { $_.StartsWith(' ') }
Not bad. So the first learning point here is: whenever a command (any command, not just DiskPart) requires interactive information, simply place it onto the pipeline and pass it on to the command. It is a bit like writing to StdIn in earlier days, just a lot easier.
Creating New Virtual Hard Drives (VHDs)
The really exciting part starts when you combine batches of commands to do more complex things. For example, I played a bit with Windows 7 virtual hard drives (VHD). The following code will generate a new VHD for you:
$path = Read-Host "Enter Path to VHD"
$label = Read-Host "Enter Drive Label"
$maximum = Read-Host "Enter maximum Size in MB"
$type = "fixed"
$command= @"
create vdisk file="$path" maximum=$maximum type=$type
select vdisk file="$path"
attach vdisk
create partition primary
assign letter=$letter
format quick label="$label"
"@
$command|
DiskPart |
Where-Object { $_.Length -gt 0 } |
Foreach-Object { Write-Progress -Activity "Creating New VHD" -Status $_ -Id 1}
Adding "UI" to Native Commands
What you see here is a batch of six commands. DiskPart accepts them step by step and executes the appropriate action.
Normally, DiskPart would output progress information directly to the console. Here, Write-Progress takes the results from DiskPart in real time as they occur and displays them in a neat progress bar, preventing garbage information to appear in your console.
The second learning point is: pipe the results from any native command to Write-Progress, and you will immediately get a nice output. Low hanging fruits to convert a nasty old command line tool into something more sophisticated.
New-VHD - a home-made new PowerShell function for Windows 7
Taking all of this and combining it, here is a quick and dirty new PowerShell function called New-VHD. It takes care of the most common errors (target file already exists, drive letter already exists) and uses DiskPart (on Windows 7) to create new virtual hard disks.
function New-VHD {
param($path, $maximum=200, $letter='r', $label='New Disk', $type='fixed')
if (test-path $path) {
Throw "Target path '$path' exists and cannot be overwritten."
}
if (test-path "$($letter):\") {
Throw "Drive letter '$letter' is taken. Choose another one."
}
$command= @"
create vdisk file="$path" maximum=$maximum type=$type
select vdisk file="$path"
attach vdisk
create partition primary
assign letter=$letter
format quick label="$label"
"@
$command|
DiskPart |
Where-Object { $_.Length -gt 0 } |
Foreach-Object { Write-Progress -Activity "Creating New VHD" -Status $_ -Id 1}
}
One important thing to note: Whenever you batch-process more than one command, you run into the risk that something unexpected happens. For example, when you try and create a new VHD and this fails, all subsequent commands will still run and maybe cause undesired effects. So there is some risk attached to this. This is why you should take this into account and wrap appropriate error handling around it.
Have fun and don't forget to enjoy the sun!
-Tobias
Posted
May 25 2009, 12:13 AM
by
Tobias