thanks for the au3 version of the USB list ptrex.
Right, here's my script so far. As mentioned previously this amalgamates a couple scripts and functions together (with the odd tweak here and there to suit). Apologies for any incorrect command useage you may find, I'm still learning.
; ====================================================================================================
======================================
; Created by UglyBob - 03/08/2007
; Thanks to:
; Yoan Roblet (Arcker) (AutoIT member) - For the code (functions) which disconnect the detected USB device from the workstation
; ptrex (AutoIT member) - For the initial USB detection code)
; Johny Clelland (AutoIT member) - For the initial AD code to query group membership
; Reference Material -
; <a href='http://support.microsoft.com/kb/165721' class='bbc_url' title='External link' rel='nofollow external'>http://support.microsoft.com/kb/165721</a>
; Microsoft Script Guy USB Monitor - <a href='http://www.microsoft.com/technet/scriptcen...06/hey0213.mspx' class='bbc_url' title='External link' rel='nofollow external'>http://www.microsoft.com/technet/scriptcen...06/hey0213.mspx</a>
; WMI queries - <a href='http://msdn2.microsoft.com/en-us/library/aa394173.aspx' class='bbc_url' title='External link' rel='nofollow external'>http://msdn2.microsoft.com/en-us/library/aa394173.aspx</a>
; Microsoft Script Guy ID USB Devices - <a href='http://www.microsoft.com/technet/scriptcen...05/hey0315.mspx' class='bbc_url' title='External link' rel='nofollow external'>http://www.microsoft.com/technet/scriptcen...05/hey0315.mspx</a>
; Version Control
; ---------------
; Updated - 06/08/2007 - Added filters to the initial SELECT query for USB devices that also create floppy & CD-ROM drives
; Updated - 07/08/2007 - Added filters to the win32_logicaldisk query to ignore already disconnected USB devices
; ====================================================================================================
======================================
#include <A3LWinApi.au3>
#include <Constants.au3>
; ------------------------------------------------------------------------------------------------------------
; Variables
$AllowUser = False
$objWMIService = ObjGet("winmgmts:\\.\root\cimv2")
$Offline = False
$OpenVolume = ""
$szVolumeFormat = "\\\\.\\%s"
$szRootFormat = "%s\\"
$szErrorFormat = "Error %d: %s\n"
$USB_Allow_Group = "USB storage Users"
$colEvents = $objWMIService.ExecNotificationQuery _
("Select * From __InstanceOperationEvent Within 5 Where " _
& "TargetInstance isa 'Win32_PnPEntity' and " _
& "(TargetInstance.Description = 'USB FloppyDisk Drive' or " _
& "TargetInstance.Description = 'CD-ROM Drive' or " _
& "TargetInstance.Description = 'Disk Drive')" )
; Additional filter = TargetInstance.Description = 'Generic Volume'
;------------------------------------------
;Arbitrary variables
Global Const $INVALID_HANDLE_VALUE = 0
;------------------------------------------
;DeviceIoControl Contants
Global Const $FSCTL_LOCK_VOLUME = int(0x090018)
Global Const $FSCTL_DISMOUNT_VOLUME = int(0x00090020)
Global Const $IOCTL_STORAGE_EJECT_MEDIA = int(0x002D4808)
Global Const $IOCTL_STORAGE_MEDIA_REMOVAL = int(0x002D4804)
;------------------------------------------
;Retry Constants
Global Const $LOCK_TIMEOUT = 10000 ; 10 Seconds
Global Const $LOCK_RETRIES = 3
;------------------------------------------
; AD LDAP variables
Dim $objConnection, $oUsr, $objRootDSE
$objConnection = ObjCreate("ADODB.Connection") ; Create COM object to AD
$objConnection.Provider = "ADsDSOObject"
$objConnection.Open ("Active Directory Provider") ; Open connection to AD
$objRootDSE = ObjGet("LDAP://RootDSE")
; If there is no response from LDAP then the script will treat the computer running the script as 'offline'.
; Ideal when a laptop is not connected to the network.
If @Error then
$Offline = True
Else
ConsoleWrite ( "Domain = " & $objRootDSE.Get ("defaultNamingContext") & @CRLF )
ConsoleWrite ( "Offline = " & $Offline & @CRLF )
$strDNSDomain = $objRootDSE.Get ("defaultNamingContext") ;Retrieve the current AD domain name (DN)
EndIf
; ------------------------------------------------------------------------------------------------------------
While 1
$objEvent = $colEvents.NextEvent
Select
Case $objEvent.Path_.Class()="__InstanceCreationEvent"
ConsoleWrite ( "Detected Device = " & $objEvent.TargetInstance.DeviceID & " - " & $objEvent.TargetInstance.Description & @CRLF )
$Event = $objWMIService.ExecQuery("Select * From Win32_LogicalDisk Where (DriveType = 2 and MediaType != 5 and (FileSystem = 'FAT' or FileSystem = 'FAT32'))" )
For $objItem in $Event
$OpenVolume = $objItem.DeviceID
ConsoleWrite ( $objItem.DeviceID & " - " & $objItem.VolumeName & " - " & $objItem.FileSystem & @CRLF )
If $Offline = False Then
If memberof($AllowUser) = False Then
EjectVolume($OpenVolume)
MsgBox (16, "USB Drive Detected", "Drive " & $OpenVolume & " has been added to your PC." & @CRLF & @CRLF & "You are not authorised to use such portable media." & @CRLF & @CRLF & "Please contact the ICT dept. for further assistance.")
EndIf
Else
MsgBox (64, "USB Drive Notification", "Drive " & $OpenVolume & " has been added to your PC.")
EndIf
Next
$OpenVolume = ""
; The 'case' statement below is no longer required for this particular script but is useful for reporting successful USB disconnections
;Case $objEvent.Path_.Class()="__InstanceDeletionEvent"
; MsgBox (64, "USB Drive", "Drive " & $OpenVolume & " has been Removed.")
EndSelect
WEnd
; ---------------------------------
;
; FUNCTIONS
;
; ---------------------------------
Func ReportError($szMsg)
ConsoleWrite(StringFormat($szErrorFormat, _API_GetLastErrorMessage (), $szMsg) & @CRLF)
Exit
EndFunc ;==>ReportError
Func OpenVolume($cDriveLetter)
;HANDLE hVolume
;UINT uDriveType
;TCHAR szVolumeName[8]
;TCHAR szRootName[5]
;DWORD dwAccessFlags
$szRootName = StringFormat($szRootFormat, $cDriveLetter)
$uDriveType = DriveGetType($szRootName);
ConsoleWrite($szRootName & @tab & $uDriveType & @crlf)
Switch $uDriveType
Case "Removable"
$dwAccessFlags = 6
Case "CDROM"
$dwAccessFlags = 2
Case Else
ConsoleWrite("Cannot eject. Drive type is incorrect." & @CRLF)
Return $INVALID_HANDLE_VALUE
EndSwitch
$szVolumeName = StringFormat($szVolumeFormat, $cDriveLetter)
;$szVolumeName = $szVolumeFormat & $cDriveLetter
ConsoleWrite($szVolumeName & @crlf )
$hVolume = _API_CreateFile ($szVolumeName, 2,$dwAccessFlags, 6)
#cs
hVolume = CreateFile( szVolumeName,
dwAccessFlags,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL );
#ce
If ($hVolume == $INVALID_HANDLE_VALUE) Then ReportError("CreateFile");
Return $hVolume;
EndFunc ;==>OpenVolume
Func CloseVolume($hVolume)
Return _API_CloseHandle ($hVolume);
EndFunc ;==>CloseVolume
Func LockVolume($hVolume)
Local $dwBytesReturned
Local $dwSleepAmount
Local $nTryCount
local $iRead
$dwSleepAmount = $LOCK_TIMEOUT / $LOCK_RETRIES;
; Do this in a loop until a timeout period has expired
For $nTryCount = 0 To $nTryCount < $LOCK_RETRIES
If _Device_Control($hVolume, $FSCTL_LOCK_VOLUME, $iRead) Then
Return True
Else
Sleep($dwSleepAmount);
EndIf
Next
Return False;
EndFunc ;==>LockVolume
Func DismountVolume($hVolume)
ConsoleWrite("Dismount " & $hVolume & @crlf)
Local $dwBytesReturned, $iRead
local $aResult = _Device_Control($hVolume, $FSCTL_DISMOUNT_VOLUME, $iRead)
;msgbox(0,"",$aResult)
Return $aResult
;Return $dwBytesReturned
EndFunc ;==>DismountVolume
Func PreventRemovalOfVolume($hVolume, $fPreventRemoval)
Local $dwBytesReturned
Local $aResult
Local $lpInbuffer,$nInBufferSize,$lpOutBuffer,$nOutBufferSize,$lpOverlapped
$PMRBUFFER = DllStructCreate("bool PreventMediaRemoval")
DllStructSetData($PMRBUFFER,"PreventMediaRemoval",$fPreventRemoval)
$lpBytesReturned = DllStructCreate("int Read")
$pRead = DllStructGetPtr($lpBytesReturned, "Read")
$aResult = Dllcall("kernel32.dll","int","DeviceIoControl","hwnd",$hVolume,"uint",$IOCTL_STORAGE_MEDIA_REMOVAL,"ptr",DllStructGetPtr($PMRBUFFER),"uint",DllStructGetSize($PMRBUFFER), _
"ptr",$lpOutBuffer,"uint",$nOutBufferSize,"ptr",$pRead,"ptr",$lpOverlapped)
if $aResult = 0 then msgbox(0,"",_API_GetLastErrorMessage())
Return $aResult <> 0
;& PMRBuffer, sizeof (PREVENT_MEDIA_REMOVAL),
;NULL, 0,
; & dwBytesReturned,
;NULL);
EndFunc ;==>PreventRemovalOfVolume
Func AutoEjectVolume($hVolume)
Local $aResult, $iRead;
$aResult = _Device_Control($hVolume, $IOCTL_STORAGE_EJECT_MEDIA, $iRead)
Return $aResult
EndFunc ;==>AutoEjectVolume
Func EjectVolume($cDriveLetter)
Local $hVolume;
Local $fRemoveSafely = False;
Local $fAutoEject = False;
; Open the volume.
$hVolume = OpenVolume($cDriveLetter);
If $hVolume == $INVALID_HANDLE_VALUE Then Return False
; Lock and dismount the volume.
If LockVolume($hVolume) And DismountVolume($hVolume) Then
$fRemoveSafely = True;
ConsoleWrite("Volume Locked and Dismounted, trying to eject " & @crlf)
; Set prevent removal to false and eject the volume.
If PreventRemovalOfVolume($hVolume, False) And AutoEjectVolume($hVolume) Then
$fAutoEject = True;
EndIf
Else
ConsoleWrite("Volume can't be locked or dismounted, please close possible opened files" & @crlf)
EndIf
; Close the volume so other processes can use the drive.
If CloseVolume($hVolume) = False Then
Return False;
EndIf
If $fAutoEject Then
ConsoleWrite(StringFormat("Media in Drive %s has been ejected safely.\n", $cDriveLetter))
Else
If $fRemoveSafely Then
ConsoleWrite(StringFormat("Media in Drive %s can be safely removed.\n", $cDriveLetter))
EndIf
EndIf
Return True;
EndFunc ;==>EjectVolume
Func _Device_Control($hDevice, $dwIoControlCode, ByRef $iRead)
Local $aResult
Local $lpInbuffer,$nInBufferSize,$lpOutBuffer,$nOutBufferSize,$lpOverlapped
$tRead = DllStructCreate("int Data")
$aResult = Dllcall("kernel32.dll","int","DeviceIoControl","hwnd",$hDevice,"uint",$dwIoControlCode,"ptr",$lpInBuffer,"uint",0, _
"ptr",$lpOutBuffer,"uint",0,"ptr",DllStructGetPtr($tRead),"ptr",$lpOverlapped)
$iRead = DllStructGetData($tRead, "Data")
ConsoleWrite("Device Control " & $iRead & @CRLF)
Return $aResult<>0
EndFunc ;==>_Device_Control
Func Memberof($AllowUser)
Dim $usergroups[1], $i = 1
Local $groups
$strQuery = "<LDAP://" & $strDNSDomain & ">;( samAccountName=" & @UserName & ");ADsPath;subtree"
$objRecordSet = $objConnection.Execute ($strQuery) ; Retrieve the FQDN for the logged on user
If $objRecordSet.RecordCount = 1 Then
$ldap_entry = $objRecordSet.fields (0).value
$oUsr = ObjGet($ldap_entry) ; Retrieve the COM Object for the logged on user
$groups = $oUsr.groups ; Get the list of group objects from the user
For $groupname In $groups
ReDim $usergroups[UBound($usergroups) + 1]
$usergroups[0] += 1 ; Increment the count of groups
$usergroups[$i] = StringTrimLeft($groupname.name, 3)
If $usergroups[$i] = $USB_Allow_Group Then
$AllowUser = True
Return $AllowUser
ConsoleWrite ( "Allow = " & $AllowUser & @CRLF )
ExitLoop
EndIf
$i += 1
Next
EndIf
ConsoleWrite ( "Allow = " & $AllowUser & @CRLF )
EndFunc ;==>memberof
(DriveType = 2 and MediaType != 5 and (FileSystem = 'FAT' or FileSystem = 'FAT32')) when checking the drives is to filter the floppy disk drive and to ignore a USB device that has already been disconnected by the script but the drive is still physically attached to the PC. There may be a slightly better WMI field to query, but so far this works, you may want to add 'NTFS' should you wish to disconnect any such devices too.
I did spot a simpler script somewhere on this forum regarding the listing of a user's groups, but the AD function works so hey why change it.