bourny Posted January 23, 2012 Share Posted January 23, 2012 I am looking to enumerate the connected USB devices with their corresponding logical drive letters into an array. I am using WMI to achieve this. At first I struggled to get both to show but then stumbled across the attached code. This code does an excellent job of what I need but with the slight difference in that I need to remove and readd the usb drive to detect it as an event. My issue is I would like to scan and pick up the connected USB drives logical drive letters without having to replug the usb device. I am guessing I need to use the "OAssociators OF" code inside WMI but struggling to work out how to do this without using the __InstanceCreationEvent used in the example below. Any ideas welcome. $wbemFlagReturnImmediately = 0x10 $wbemFlagForwardOnly = 0x20 $colItems = "" $strComputer = "localhost" $MyDrive = "SCSD TOOLS" $objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\CIMV2") $m_MediaConnectWatcher = $objWMIService.ExecNotificationQuery("SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_DiskDrive'") ;While 1 $mbo = $m_MediaConnectWatcher.NextEvent $obj = $mbo.TargetInstance If $obj.InterfaceType == "USB" Then $New = GetDriveLetterFromDisk($obj.Name) $Label = DriveGetLabel($New) MsgBox(0, "", $new) ;If $Label == $MyDrive Then ; MsgBox(4096, "Info", "My drive has been plugged in, backup my files!") ;EndIf EndIf ;WEnd Func GetDriveLetterFromDisk($name) $ans = "" $name = StringReplace($name,"\","\\") $oq_part = $objWMIService.ExecQuery("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & $name & """} WHERE AssocClass = Win32_DiskDriveToDiskPartition", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly) If IsObj($oq_part) Then For $obj_part In $oq_part $oq_disk = $objWMIService.ExecQuery("ASSOCIATORS OF {Win32_DiskPartition.DeviceID=""" & $obj_part.DeviceID & """} WHERE AssocClass = Win32_LogicalDiskToPartition", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly) If IsObj($oq_disk) Then For $obj_disk in $oq_disk $ans = $ans & $obj_disk.Name Next EndIf Next EndIf Return $ans EndFunc Link to comment Share on other sites More sharing options...
BrewManNH Posted January 23, 2012 Share Posted January 23, 2012 You could simplify it by using DriveGetDrive with type removable and get an array of all removable disks. If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag GudeHow to ask questions the smart way! I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from. Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays. - ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script. - Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label. - _FileGetProperty - Retrieve the properties of a file - SciTE Toolbar - A toolbar demo for use with the SciTE editor - GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI. - Latin Square password generator Link to comment Share on other sites More sharing options...
bourny Posted January 24, 2012 Author Share Posted January 24, 2012 BrewManNH :This does not work as My external USB hard drive is not classified as removable but as a disk drive. A solid state is but not a portable usb hard drive.Any more ideas welcome. The script I attached is exactly what I need apart from the fact I need to scan attached USB drives (Solid state / portable hard drive) without disconnecting them and reconnecting them. It is the bit at the top of the script I need to change but not sure to what. Link to comment Share on other sites More sharing options...
Moderators JLogan3o13 Posted January 24, 2012 Moderators Share Posted January 24, 2012 Hi, bourny. What about something like this, if you will be using the same drive(s) every time? The example uses a message box to determine the drive, but you could use a similar If statement to do what you want with that drive (it also gives you the drive letter, in case that changes each time): I used my thumb drive and the total space it contains (not used space). Local $aArray = DriveGetDrive("ALL") For $i = 1 To $aArray[0] If DriveSpaceTotal(StringUpper($aArray[$i])) = "3813.4453125" Then MsgBox(4096, "", "Drive " & StringUpper($aArray[$i]) & " is my thumb drive.") EndIf Next "Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball How to get your question answered on this forum! Link to comment Share on other sites More sharing options...
kylomas Posted January 24, 2012 Share Posted January 24, 2012 bourny, Does this give you what you expect? #include <Array.au3> $arrResults=_GetLogicalDriveToPartition() _ArrayDisplay($arrResults) Func _GetLogicalDriveToPartition() $objWMIService = ObjGet("winmgmts:{impersonationLevel=Impersonate}!.rootcimv2") If Not IsObj($objWMIService) Then Return -1 ;Failed to Connect to WMI on Local Machine Local $arr[1][2] $colDevice = $objWMIService.ExecQuery("SELECT * from Win32_LogicalDiskToPartition") For $objItem in $colDevice ReDim $arr[UBound($arr)+1][2] $arr[UBound($arr)-1][0]=StringTrimLeft($objItem.Antecedent,StringInStr($objItem.Antecedent,"=",0,-1)) $arr[UBound($arr)-1][1]=StringTrimLeft($objItem.Dependent,StringInstr($objItem.Dependent,"=",0,-1)) Next $colDevice=0 $objWMIService=0 $arr[0][0]="Disk #, Partition #" $arr[0][1]="Drive Letter" Return $arr EndFunc kylomas Forum Rules Procedure for posting code "I like pigs. Dogs look up to us. Cats look down on us. Pigs treat us as equals." - Sir Winston Churchill Link to comment Share on other sites More sharing options...
bourny Posted January 25, 2012 Author Share Posted January 25, 2012 JLogan3o13: Nice Try but unfortunatly I have various different types of USB drives which users could use. These range from solid state which are easy to detect as they are classified as removable drive by the OS. The portable hard drives are the issue as these are recognised as a disk drive same as the fixed system disk. The only difference is the connector is by USB instead of IDE / SATa etc. If I can see which drives are connected vie USB and then return each logical drive letter that would be spot on. My above example shows this but only if you reconnect the device to USB.kylomas: Nearly what I need. If you can add another column to the array with information if the logical drive is hanging off a usb / IDE / Sata connection then that is my question answered. This thread is nearly has an answer any further suggestions welcome to crack this difficult issue. It seems impossible to do this so far. Link to comment Share on other sites More sharing options...
rover Posted January 25, 2012 Share Posted January 25, 2012 Even though the WMI code to do this is probably in many posts on the forum, It was easy enough to look through the existing WMI scripts I have. added more object checking and the necessary COM error handler expandcollapse popup#include <Array.au3> Opt("MustDeclareVars", 1) Local $arrResults = _GetLogicalDriveToPartition() _ArrayDisplay($arrResults, "USB Drives") Exit Func _GetLogicalDriveToPartition() ; Error monitoring. This will trap all COM errors while alive. ; This particular object is declared as local, meaning after the function returns it will not exist. Local $oErrorHandler, $oWMIService, $arr[1][4], $iPos, $iPhysDrive, $iUB, $oColDevice, $oColItems $oErrorHandler = ObjEvent("AutoIt.Error", "_ErrFunc") If Not IsObj($oErrorHandler) Then ConsoleWrite("!No COM error handler" & @CRLF) $oWMIService = ObjGet("winmgmts:{impersonationLevel=Impersonate}!\\.\root\cimv2") If Not IsObj($oWMIService) Then Return -1 ;Failed to Connect to WMI on Local Machine $oColDevice = $oWMIService.ExecQuery("SELECT * from Win32_LogicalDiskToPartition", "WQL", 48) If Not IsObj($oColDevice) Then Return -1 For $objItem In $oColDevice $iPos = StringInStr($objItem.Antecedent, "Disk #") If Not @error And $iPos <> 0 Then $iPhysDrive = StringMid($objItem.Antecedent, $iPos +6, 1) $oColItems = $oWMIService.ExecQuery("SELECT InterfaceType,Model FROM Win32_DiskDrive WHERE DeviceID = '\\\\.\\PHYSICALDRIVE"&$iPhysDrive&"'", "WQL", 48) If Not IsObj($oColItems) Then Return -1 For $obj In $oColItems If $obj.InterfaceType == "USB" Then $iUB = UBound($arr) ReDim $arr[$iUB + 1][4] $arr[$iUB][0] = StringTrimLeft($objItem.Antecedent, StringInStr($objItem.Antecedent, "=", 0, -1)) $arr[$iUB][1] = StringReplace(StringTrimLeft($objItem.Dependent, StringInStr($objItem.Dependent, "=", 0, -1)), """", "") $arr[$iUB][2] = DriveGetLabel($arr[$iUB][1]) $arr[$iUB][3] = $obj.Model ;ConsoleWrite("+ Drive " & $arr[$iUB][1]& " is USB" & @CRLF) EndIf Next EndIf Next $arr[0][0] = "Disk #, Partition #" $arr[0][1] = "Drive Letter" $arr[0][2] = "Drive Label" $arr[0][3] = "Drive Model" Return $arr EndFunc ;==>_GetLogicalDriveToPartition ; User's COM error function. Will be called if COM error occurs Func _ErrFunc($oError) ; Do anything here. ConsoleWrite("err.number is: " & @TAB & $oError.number & @CRLF & _ "err.windescription:" & @TAB & $oError.windescription & @CRLF & _ "err.description is: " & @TAB & $oError.description & @CRLF & _ "err.source is: " & @TAB & $oError.source & @CRLF & _ "err.helpfile is: " & @TAB & $oError.helpfile & @CRLF & _ "err.helpcontext is: " & @TAB & $oError.helpcontext & @CRLF & _ "err.lastdllerror is: " & @TAB & $oError.lastdllerror & @CRLF & _ "err.scriptline is: " & @TAB & $oError.scriptline & @CRLF & _ "err.retcode is: " & @TAB & $oError.retcode & @CRLF & @CRLF) EndFunc ;==>_ErrFunc I see fascists... Link to comment Share on other sites More sharing options...
Chimaera Posted January 25, 2012 Share Posted January 25, 2012 (edited) How about Local $aArray = DriveGetDrive("ALL") For $i = 1 To $aArray[0] If DriveSpaceTotal(StringUpper($aArray[$i])) < "65000" And DriveSpaceTotal(StringUpper($aArray[$i])) > "0" Then MsgBox(4096, "", "Drive " & StringUpper($aArray[$i]) & " is my thumb drive.") EndIf Next Most Usb drives are less than 64gb and they are rare so just set the first figure to that or just aboveand i used the "0" value to exclude empty DVDs etc Edit Just realised this will pick up a DVD drive with a disc in it i think... Yep it does bugger.... Local $aArray = DriveGetDrive("FIXED") For $i = 1 To $aArray[0] If DriveSpaceTotal(StringUpper($aArray[$i])) < "65000" Then MsgBox(4096, "", "Drive " & StringUpper($aArray[$i]) & " is my thumb drive.") EndIf Next Local $aArray = DriveGetDrive("REMOVABLE") For $i = 1 To $aArray[0] If DriveSpaceTotal(StringUpper($aArray[$i])) < "65000" Then MsgBox(4096, "", "Drive " & StringUpper($aArray[$i]) & " is my thumb drive.") EndIf Next this works for me Edited January 25, 2012 by Chimaera If Ive just helped you ... miracles do happen. Chimaera CopyRobo() * Hidden Admin Account Enabler * Software Location From Registry * Find Display Resolution * _ChangeServices() Link to comment Share on other sites More sharing options...
airwilf Posted January 25, 2012 Share Posted January 25, 2012 Tested the following against fixed and removable drives, outputs the drive letter along with the model. All USB connected devices have "USB Device" at the end of the string.$strComputer = @ComputerName Dim $objWMIService = objget("winmgmts:\\" & $strComputer & "\root\cimv2") Dim $colDevices = $objWMIService.ExecQuery ("Select * From Win32_logicaldisktopartition") For $objDevice in $colDevices $strDeviceName = $objDevice.antecedent $strdrive = $objDevice.dependent $strQuote = Chr(34) $strDriveName = StringReplace($strDrive, $strQuote, "") $arrDriveNames = stringSplit($strDriveName, "=") $strDeviceName = StringReplace($strDeviceName, $strQuote, "") $arrDeviceNames = stringSplit($strDeviceName, "=") $split = stringsplit($arrDeviceNames[2],",") $replace = Stringtrimleft($split[1], 6) Dim $colUSBDevices = $objWMIService.ExecQuery("Select * From Win32_diskdrive Where index = '" & $replace & "'") For $objUSBDevice in $colUSBDevices msgbox(0,"",$arrDriveNames[2] & "drive " & " is" & @lf & $objUSBDevice.caption) Next Next Link to comment Share on other sites More sharing options...
guinness Posted January 25, 2012 Share Posted January 25, 2012 There's a script by Yashied floating around the forum somewhere, though I can't seem to find it right now, it doesn't use WMI but registering the Windows Message WM_DEVICECHANGE. UDF List: _AdapterConnections() • _AlwaysRun() • _AppMon() • _AppMonEx() • _ArrayFilter/_ArrayReduce • _BinaryBin() • _CheckMsgBox() • _CmdLineRaw() • _ContextMenu() • _ConvertLHWebColor()/_ConvertSHWebColor() • _DesktopDimensions() • _DisplayPassword() • _DotNet_Load()/_DotNet_Unload() • _Fibonacci() • _FileCompare() • _FileCompareContents() • _FileNameByHandle() • _FilePrefix/SRE() • _FindInFile() • _GetBackgroundColor()/_SetBackgroundColor() • _GetConrolID() • _GetCtrlClass() • _GetDirectoryFormat() • _GetDriveMediaType() • _GetFilename()/_GetFilenameExt() • _GetHardwareID() • _GetIP() • _GetIP_Country() • _GetOSLanguage() • _GetSavedSource() • _GetStringSize() • _GetSystemPaths() • _GetURLImage() • _GIFImage() • _GoogleWeather() • _GUICtrlCreateGroup() • _GUICtrlListBox_CreateArray() • _GUICtrlListView_CreateArray() • _GUICtrlListView_SaveCSV() • _GUICtrlListView_SaveHTML() • _GUICtrlListView_SaveTxt() • _GUICtrlListView_SaveXML() • _GUICtrlMenu_Recent() • _GUICtrlMenu_SetItemImage() • _GUICtrlTreeView_CreateArray() • _GUIDisable() • _GUIImageList_SetIconFromHandle() • _GUIRegisterMsg() • _GUISetIcon() • _Icon_Clear()/_Icon_Set() • _IdleTime() • _InetGet() • _InetGetGUI() • _InetGetProgress() • _IPDetails() • _IsFileOlder() • _IsGUID() • _IsHex() • _IsPalindrome() • _IsRegKey() • _IsStringRegExp() • _IsSystemDrive() • _IsUPX() • _IsValidType() • _IsWebColor() • _Language() • _Log() • _MicrosoftInternetConnectivity() • _MSDNDataType() • _PathFull/GetRelative/Split() • _PathSplitEx() • _PrintFromArray() • _ProgressSetMarquee() • _ReDim() • _RockPaperScissors()/_RockPaperScissorsLizardSpock() • _ScrollingCredits • _SelfDelete() • _SelfRename() • _SelfUpdate() • _SendTo() • _ShellAll() • _ShellFile() • _ShellFolder() • _SingletonHWID() • _SingletonPID() • _Startup() • _StringCompact() • _StringIsValid() • _StringRegExpMetaCharacters() • _StringReplaceWholeWord() • _StringStripChars() • _Temperature() • _TrialPeriod() • _UKToUSDate()/_USToUKDate() • _WinAPI_Create_CTL_CODE() • _WinAPI_CreateGUID() • _WMIDateStringToDate()/_DateToWMIDateString() • Au3 script parsing • AutoIt Search • AutoIt3 Portable • AutoIt3WrapperToPragma • AutoItWinGetTitle()/AutoItWinSetTitle() • Coding • DirToHTML5 • FileInstallr • FileReadLastChars() • GeoIP database • GUI - Only Close Button • GUI Examples • GUICtrlDeleteImage() • GUICtrlGetBkColor() • GUICtrlGetStyle() • GUIEvents • GUIGetBkColor() • Int_Parse() & Int_TryParse() • IsISBN() • LockFile() • Mapping CtrlIDs • OOP in AutoIt • ParseHeadersToSciTE() • PasswordValid • PasteBin • Posts Per Day • PreExpand • Protect Globals • Queue() • Resource Update • ResourcesEx • SciTE Jump • Settings INI • SHELLHOOK • Shunting-Yard • Signature Creator • Stack() • Stopwatch() • StringAddLF()/StringStripLF() • StringEOLToCRLF() • VSCROLL • WM_COPYDATA • More Examples... Updated: 22/04/2018 Link to comment Share on other sites More sharing options...
bourny Posted January 25, 2012 Author Share Posted January 25, 2012 Rover: Spot on. This gives me exactly what I am looking for. Chimaera: This does not tell me which device is USB. I plugged a portable drive in and it did not detect it. Appreciate your attempt and time spent.airwilf : Spot on and very impressed in the ammount of code used compared to Rovers. Summary. 2 very good responses to this issue and I now have the ability to detect all usb drives regardless if they are solid state or a classed as a fixed disk.. Note none of these examples have required the use of "associators Of" to derive the result which is what I was expecting to see in an answer. Makes it easier to understand for WMI newbies. Link to comment Share on other sites More sharing options...
bourny Posted January 25, 2012 Author Share Posted January 25, 2012 guinness: Will be interested to see this if you can find it. I have a solution now but always keen to see different ways and I am not familiar with WM instead of WMI so might extend my knowledge. Link to comment Share on other sites More sharing options...
Yashied Posted January 25, 2012 Share Posted January 25, 2012 expandcollapse popup#Include <APIConstants.au3> #Include <GUIConstantsEx.au3> #Include <WinAPIEx.au3> Opt('TrayAutoPause', 0) $hForm = GUICreate('') GUIRegisterMsg($WM_DEVICECHANGE, 'WM_DEVICECHANGE') While 1 Sleep(1000) WEnd Func _GetDrive($iMask) For $i = 0 To 25 If BitAND(BitShift($iMask, $i), 1) Then Return Chr(65 + $i) & ':' EndIf Next Return '' EndFunc ;==>_GetDrive Func _USBCheck($sVolume) Local $hDrive, $tData, $iBus, $iRes, $Fs $iBus = _WinAPI_GetDriveBusType($sVolume) Switch $iBus Case $DRIVE_BUS_TYPE_USB $hDrive = _WinAPI_CreateFileEx('.' & $sVolume, 3, 0, 0) If Not $hDrive Then Return EndIf $tData = DllStructCreate('dword DeviceType;ulong DeviceNumber;ulong PartitionNumber') $iRes = _WinAPI_DeviceIoControl($hDrive, $IOCTL_STORAGE_GET_DEVICE_NUMBER, 0, 0, DllStructGetPtr($tData), DllStructGetSize($tData)) _WinAPI_CloseHandle($hDrive) If (Not $iRes) Or (Not (DllStructGetData($tData, 'DeviceType') = 7)) Then Return EndIf ;~ $Fs = DriveGetFileSystem($sVolume) ;~ Switch $Fs ;~ Case 'FAT32', 'NTFS' ;~ ;~ Case Else ;~ Return ;~ EndSwitch Case Else Return EndSwitch ConsoleWrite('USB device found: ' & $sVolume & @CR) EndFunc ;==>_USBCheck Func WM_DEVICECHANGE($hWnd, $iMsg, $wParam, $lParam) Switch $hWnd Case $hForm Switch $wParam Case 0x8000 ; DBT_DEVICEARRIVAL Local $tDBV = DllStructCreate('dword Size;dword DeviceType;dword Reserved;dword Mask;ushort Flags', $lParam) Local $Type = DllStructGetData($tDBV, 'DeviceType') Local $Flag = DllStructGetData($tDBV, 'Flags') Local $Mask = DllStructGetData($tDBV, 'Mask') Switch $Type Case 2 ; DBT_DEVTYP_VOLUME Switch $Flag Case 0 _USBCheck(_GetDrive($Mask)) EndSwitch EndSwitch EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_DEVICECHANGE My UDFs: iKey | FTP Uploader | Battery Checker | Boot Manager | Font Viewer | UDF Keyword Manager | Run Dialog Replacement | USBProtect | 3D Axis | Calculator | Sleep | iSwitcher | TM | NetHelper | File Types Manager | Control Viewer | SynFolders | DLL Helper Animated Tray Icons UDF Library | Hotkeys UDF Library | Hotkeys Input Control UDF Library | Caret Shape UDF Library | Context Help UDF Library | Most Recently Used List UDF Library | Icons UDF Library | FTP UDF Library | Script Communications UDF Library | Color Chooser UDF Library | Color Picker Control UDF Library | IPHelper (Vista/7) UDF Library | WinAPI Extended UDF Library | WinAPIVhd UDF Library | Icon Chooser UDF Library | Copy UDF Library | Restart UDF Library | Event Log UDF Library | NotifyBox UDF Library | Pop-up Windows UDF Library | TVExplorer UDF Library | GuiHotKey UDF Library | GuiSysLink UDF Library | Package UDF Library | Skin UDF Library | AITray UDF Library | RDC UDF Library Appropriate path | Button text color | Gaussian random numbers | Header's styles (Vista/7) | ICON resource enumeration | Menu & INI | Tabbed string size | Tab's skin | Pop-up circular menu | Progress Bar without animation (Vista/7) | Registry export | Registry path jumping | Unique hardware ID | Windows alignment More... Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now