Thursday, December 18, 2008

Finding Partition Offsets Made Easier (with Powershell)

A while back, I read Linchi Shea's blog posting on finding partition offsets. I recently found some time to rework his C# file plus perl script solution into a single Powershell script.

The upsides to my solution are:
  • It's Powershell-only, so there is nothing to compile and you don't need to install perl.
  • Using Powershell provides some added bling, for no real cost. It's easy to construct a pipeline that will interrogate many servers or will provide sorting or filtering.

The major downside to my solution is:
  • You must install Powershell. This shouldn't be a problem on Windows Vista or Windows Server 2008.
Please be careful of the formatting. While embedding the code here is more convenient than a zip file, I'm still learning blogger and things may not wrap the way that I would like them too. I've also looked for a way to post syntax-highlighted Powershell code. There are solutions for other languages, but nothing for Powershell is jumping out at me so I will rely on a simple <pre> tag for this post.

# Example of use:
# $serverlist | foreach { Get-PartitionInfo $_ } | ft -a
#

param (
[string] $computer = $(throw "ERROR: The 'computer' parameter is required.")
)

$scope = new System.Management.ManagementScope
$scope.Path = "\\$($computer)\root\cimv2"
$scope.Connect()

$query = new System.Management.ObjectQuery
$query.QueryString = "SELECT * FROM Win32_DiskPartition"

$searcher = new System.Management.ManagementObjectSearcher($scope, $query)
$queryCollection = $searcher.Get()

# this is a quick-and-dirty way to build an object with members that I can reference
$report = "" | select-object "Computer","PhysicalDiskIndex",
"PartitionIndex","PartitionOffset","PartitionOffsetKB",
"LogicalDiskName","LogicalDiskVolumeName","LogicalDiskSize","LogicalDiskSizeGB"

# start setting values for the members of my reporting object.
# I'm casting everything to make sure I get data types that I want
$report.Computer = [string] $computer
$queryCollection | foreach {
$report.PhysicalDiskIndex = [int] $_.DiskIndex
$report.PartitionIndex = [int] $_.Index
$report.PartitionOffset = [int64] $_.StartingOffset
$report.PartitionOffsetKB = [int64] $_.StartingOffset /1kb
$_.GetRelated("Win32_LogicalDisk") | foreach {
$report.LogicalDiskName = [string] $_.Name
$report.LogicalDiskVolumeName = [string] $_.VolumeName
$report.LogicalDiskSize = [int64] $_.Size
$report.LogicalDiskSizeGB = [int] [math]::round($_.Size / 1gb, 0)
# emit the report for this iteration.
# This gets passed to the next item in the pipeline, if there is one.
$report
}
}