Auto mount/unmount new PSDrives for removable drives and network shares in PowerShell v2

The new eventing infrastructure in PowerShell 2.0 is pretty delicious. You couldn’t do the following in 1.0 without a 3rd party snap-in (like my PSEventing snapin), but now it’s all there at the touch of your fingers. Well, it demands a bit of a sniff around WMI too, but hey, it works well.  With this module, anytime you add or remove a removable device like an external harddrive or USB key, or map a new network drive in explorer, PowerShell will now automatically add or remove a corresponding PSDrive for you.

  1. # AutoMount.psm1 v1.0  
  2. # Oisin "x0n" Grehan (MVP)  
  3.  
  4. $query = new-object System.Management.WqlEventQuery  
  5. $query.EventClassName = "__InstanceOperationEvent" 
  6.  
  7. # default to every 2 seconds  
  8. $query.WithinInterval = new-object System.TimeSpan 0,0,2  
  9.  
  10. # this WMI is only available with Windows 2003 and Vista (not XP it appears).  
  11. # this could be rewritten to use different WMI queries to support 2000/NT/XP also.  
  12. $query.QueryString = "Select * from Win32_VolumeChangeEvent" 
  13.  
  14. # attach a watcher  
  15. $watcher = new-object System.Management.ManagementEventWatcher $query 
  16.  
  17. # here we use -SupportEvent instead of -SourceIdentifier  
  18. # this prevents this event from being generally visible  
  19. # also note the use of the call operator to invoke a   
  20. # function in the scope of the module since this action  
  21. # occurs outside of module scope.  
  22. Register-ObjectEvent $watcher -EventName "EventArrived" `  
  23.     -SupportEvent "WMI.VolumeChange" -Action {  
  24.         & (get-module automount) VolumeChangeCallback @args 
  25.     }  
  26.  
  27. # New PSEvents:  
  28. #  
  29. #     PowerShell.DeviceConfigurationChanged  
  30. #     PowerShell.DeviceArrived  
  31. #     PowerShell.DeviceRemoved  
  32. #     PowerShell.DeviceDocking  
  33.  
  34. # win32_volumechangeevent event types  
  35. $eventTypes = @{  
  36.     1 = "ConfigurationChanged";  
  37.     2 = "Arrived";  
  38.     3 = "Removed";  
  39.     4 = "Docking";  
  40. }  
  41.  
  42. # private module level callback function  
  43. function VolumeChangeCallback ($sender, $eventargs) {  
  44.     trap { write-warning $_ }  
  45.  
  46.     $driveName = $eventArgs.NewEvent.DriveName.TrimEnd(":")  
  47.     $eventType = [int]$eventArgs.NewEvent.EventType # was uint16  
  48.  
  49.     $forwardedEvent = "Device$($eventTypes[$eventType])" 
  50.       
  51.     # forward a new simpler event specific to device event type  
  52.     [void]( New-PSEvent "PowerShell.$forwardedEvent" -Sender $driveName `  
  53.         -EventArguments $eventargs )  
  54. }  
  55.  
  56. # hook up our psdrive mount / unmount events  
  57. # and start the WMI watcher  
  58. function Enable-AutoMount {  
  59.  
  60.     Register-PSEvent -SourceIdentifier "PowerShell.DeviceArrived" `  
  61.         -Action {              
  62.             new-psdrive -name $args[0] -psprovider `  
  63.                 filesystem -root "$args[0]:";  
  64.          }  
  65.  
  66.     Register-PSEvent -SourceIdentifier "PowerShell.DeviceRemoved" `  
  67.         -Action {  
  68.             remove-psdrive -name $args[0] -ea 0; # may not exist  
  69.         }  
  70.       
  71.     $watcher.Start()  
  72. }  
  73.  
  74. # tear down our psdrive mount / unmount events  
  75. # and stop the WMI watcher  
  76. function Disable-AutoMount {  
  77.  
  78.     Unregister-PSEvent -SourceIdentifier "PowerShell.DeviceArrived" 
  79.     Unregister-PSEvent -SourceIdentifier "PowerShell.DeviceRemoved" 
  80.       
  81.     $watcher.Stop()  
  82. }  
  83.  
  84. # export functions to control automount  
  85. Export-ModuleMember Enable-AutoMount, Disable-AutoMount  
  86.  
  87. # start watching and (un)mounting  
  88. Enable-AutoMount 

This only works PowerShell v2.0 CTP2, and you’ll need to save it as AutoMount.psm1 in a directory under your documents folder like so (vista example):

%userprofile%\documents\windowspowershell\packages\automount\automount.psm1

You can then load it with the command:

ps> add-module automount

I have this in my profile.  You can temporarily disable automount with the function Disable-AutoMount and reenable it at anytime with Enable-AutoMount. The module also exposes four new events for you to consume yourself. You could, for example, hook your own script to run anytime a device is added and/or removed. This is what I do myself in the module. I hook a WMI event once then forward 1 of 4 possible new events depending on the type of WMI event that was raised.

NOTE: this particular flavour of WMI query only works in Vista and Windows 2003 it appears. I’m looking into getting it working with 2000/XP also.

Have fun!

blog comments powered by Disqus

About the author

Irish, PowerShell MVP, .NET/ASP.NET/SharePoint Developer, Budding Architect. Developer. Montrealer. Opinionated. Montreal, Quebec.

Month List

Page List