Saturday, May 08, 2010

Adapting to the ever changing drive letters...

...by using unique volume labels.

Okay, this isn't a complete thought yet, just some ideas I've mulled over and found a solution for for myself, but feel free to adapt and play with it. The reason I came up with this is because I picked up a new toy, a pogoplug (v2) and it provides me with network attached storage of multiple USB Drives (External Hard Disks or USB Keys). That's great, and it also provides for the automated backup of files/folders on my PC to the device, so why would I want to control it any further?

Because I can. The drive letters can change from time to time, depending on the timing of this or that being able to adapt to the changing drive letter seemed like a good idea. So, I fired up Notepad++ and wrote myself a VBScript tool that can do a bunch of things, but in this instance it can locate the drive letter for the volume name and I can parse that using CScript (command-line VBScript, vs. WScript, which would run graphical). Now I first ran cscript //H:CScript to ensure that it runs like a "DOS App" but you could easily change the batch file portion of this to simply run this in cscript. The follwing is the VBScript:

Option Explicit
' Find My Drive (ListDrives.vbs)

DIM strVolume, strFound, objDictionary, objWMIService, colDisks, objDisk, strComputer
DIM flagHideList, strDrive, wshShell, wshSystemEnv, wshCurrentEnv, strSetVar
DIM i

flagHideList=false
strFound=""
strVolume=""
strComputer = "."

Set wshShell = CreateObject( "WScript.Shell" )
Set wshCurrentEnv = wshShell.Environment( "VOLATILE" ) ' PROCESS, SYSTEM, USER and VOLATILE
Set objDictionary = CreateObject("Scripting.Dictionary")
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

If Wscript.Arguments.Count = 0 Then
    ' Do Proceed as Normal
Else
    For i = 0 to Wscript.Arguments.Count - 1
  If lcase(Wscript.Arguments(i)) = "/volume" Then
            if i+1 <= Wscript.Arguments.Count then
    strVolume=Wscript.Arguments(i+1)
   end if
  end if
  If lcase(Wscript.Arguments(i)) = "/setvar" Then
            if i+1 <= Wscript.Arguments.Count then
    strSetVar=Wscript.Arguments(i+1)
   end if
  end if
  If lcase(Wscript.Arguments(i)) = "/hidelist" Then
   flagHideList=true
  end if
 next
End If

Set colDisks = objWMIService.ExecQuery("Select * from Win32_LogicalDisk")

For Each objDisk in colDisks
    objDictionary.Add objDisk.DeviceID, objDisk.VolumeName
 if NOT flagHideList then WScript.Echo objDisk.DeviceID & " " & objDisk.VolumeName
Next

For i = 67 to 90
    strDrive = Chr(i) & ":"
    If objDictionary.Exists(strDrive) Then
  if strVolume=ObjDictionary.Item(strDrive) then strFound=Chr(i) & ":"
    End If
Next
if strFound<>"" then
 WScript.Echo strVolume & "=" & strFound
 if strSetVar<>"" then
  ' Display the current value
  WScript.Echo strSetVar & "=" & wshCurrentEnv( strSetVar )
  ' Set the environment variable
  wshCurrentEnv( strSetVar ) = strFound
  WScript.Echo strSetVar & "=" & wshCurrentEnv( strSetVar )
 end if
end if
WScript.Quit 0
...and yes, this could be enhanced and/or streamlined.

So. To find a Volume name "Tom's Drive" you would type:
ListDrives.vbs /volume "Tom's Drive"

Now that's cute, but useless beyond yourself... what you can do is automate it... throw this into a batch file:

FOR /F "usebackq tokens=1,2 skip=3 delims==" %%i IN (`ListDrives.vbs /volume "Tom's Drive" /hidelist`) DO SET DL=%%j 

or

FOR /F "usebackq tokens=1,2 skip=3 delims==" %%i IN (`cscript ListDrives.vbs /volume "Tom's Drive" /hidelist`) DO SET DL=%%j 

You can now use the environment variable %DL% as the drive letter. You can use this dealing with All sorts of USB Keys, or even a memory card. There are other tricks too, but this was just an idea.

There is no individual ownership when you are part of a team, it's the sum of the parts that makes you the RESILIENT team you need to be.