views:

405

answers:

2

I have an Exchange server with lots of mountpoints. Given the path to the database files is there a way to find out what volume they are on? The problem is that they are typically not at the volume mount point, but further down the tree. I'm using Powershell, so I need a solution preferably using WMI but could also use any .NET or COM objects.

+2  A: 

PSCX includes a Get-ReparsePoint cmdlet:

C:\temp> Get-ReparsePoint d | ft -auto

Target                                           Path      ReparsePointTag
------                                           ----      ---------------
\??\Volume{a5908e7a-eca5-11dd-be98-005056c00008} C:\temp\d      MountPoint

You can map volume GUIDs to familiar drive names using the registry:

Get-ItemProperty HKLM:\SYSTEM\MountedDevices

[...]
\DosDevices\D:                                   : {22, 35, 171, 65...}
[...]
\??\Volume{a5908e7a-eca5-11dd-be98-005056c00008} : {22, 35, 171, 65...}

Putting things together, we can get the serial # of the physical drive that's mounted at c:\temp\d:

$guid = (Get-ReparsePoint d).target
$serial = (get-itemproperty HKLM:\SYSTEM\MountedDevices).$guid

You can compare that serial against the serial numbers of the other logical volumes such as the ones with DOS letters.

> function ArrayEqual([psobject[]]$arr1, [psobject[]]$arr2) 
      { @(Compare-Object $arr1 $arr2 -sync 0).Length -eq 0 }

> (gi HKLM:\SYSTEM\MountedDevices).property | ?{ $_ -like "\dos*" } | 
      ?{ ArrayEqual$serial (gp HKLM:\SYSTEM\MountedDevices).$_ }

\DosDevices\D:

See Keith Hill's blog for an explanation of the array comparison function.

For completeness, note this does NOT seem to be the same serial reported by COM...

> $comSerial = (new-object -com scripting.filesystemobject).getdrive("d")
> [bitconverter]::GetBytes($comSerial)
18
208
242
202
Richard Berg
up-- answer was pretty close to this, but most places I don't have PSCX, so...
slipsec
You can always read the PSCX source code, it's OSS...
Richard Berg
worked something out. WMI love! http://slipsec.com/blog/?p=126
slipsec
+1  A: 

I'd just discovered the ReparsePoint attribute.

After grabbing the directory I'm in, I can walk up the tree untill I get to Root and check for ReparsePoints along the way.

$dbDir = (get-item (Get-MailboxDatabase $db).edbfilepath).directory
$dbDir
if($dbdir.parent){
  #todo make this recursive
}

#test if it's a reparse point.    
if ($dbdir.attributes -band [System.IO.FileAttributes]::ReparsePoint ){
  #it's a mountpoint.
}

From here there's the "mountvol /L" tool, or better the WMI Association class Win32_MountPoint and Win32_Volume.

A bit involved- but I don't see a simple way to just ask "what volume am I on?" Once I get it all put together, I'll post a full explanation.

edit - more details here: http://slipsec.com/blog/?p=126

slipsec