Jump to content

Batch copy files to usb


Recommended Posts


I have to update data on a huge quantity of usb keys.

The goal is > when a usb key is detected, the script must erase the data on this key, and copy *.* from a specified directory to the key, eject the key and wait for the next key.

I made a script, witch is a merge of ptrex's 'USB drive Monitor Example' and the arcker's 'AutoEjectIt'.

Here is the script:

; #FUNCTION# ====================================================================================================
; Description ...: Eject an USB Key or a CD-ROM safely
; Parameters ....: $$cDriveLetter - Drive to eject (ex : E: )

; Return values .: Success      - True
;                  Failure      - False
; Author ........: Yoan Roblet (Arcker)
; Remarks .......:
; Requirements...: AutoIt3Lib
; Related .......: http://support.microsoft.com/kb/165721
; ====================================================================================================

#include <A3LWinApi.au3>
#include <Misc.au3>

;BOOL EjectVolume(TCHAR cDriveLetter);
;HANDLE OpenVolume(TCHAR cDriveLetter);
;BOOL LockVolume(HANDLE hVolume);
;BOOL DismountVolume(HANDLE hVolume);
;BOOL PreventRemovalOfVolume(HANDLE hVolume, BOOL fPrevent);
;BOOL AutoEjectVolume(HANDLE hVolume);
;BOOL CloseVolume(HANDLE hVolume);

;StringFormat Output
$szVolumeFormat = "\\\\.\\%s"
$szRootFormat = "%s\\"
$szErrorFormat = "Error %d: %s\n"
;Arbitrary variables
;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 = 20


$strComputer = "."
 $objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\cimv2")

 $colEvents = $objWMIService.ExecNotificationQuery _
    ("Select * From __InstanceOperationEvent Within 5 Where " _
        & "TargetInstance isa 'Win32_LogicalDisk' and " _
           & "TargetInstance.DriveType = 2" )
HotKeySet("{ESC}", "Terminer")
;~ ==========================================================
;~                          ACTION
;~ ==========================================================
While 1
    $objEvent = $colEvents.NextEvent
    If $objEvent.TargetInstance.DriveType = 2 Then ;~ detecte les cles usb (2 = usb)
            Case $objEvent.Path_.Class()="__InstanceCreationEvent" ;~ detecte la creation d'un disque
                Consolewrite("Disque " & $objEvent.TargetInstance.DeviceId & "ajouté." & @CR)
                FileDelete($objEvent.TargetInstance.DeviceId &"\*.*") ;~ efface le contenu de la clé
                FileCopy($chemin &"*.*", $objEvent.TargetInstance.DeviceId &"\") ;~ copie les nouveaux fichiers
                $OpenVolume = $objEvent.TargetInstance.DeviceId
                ConsoleWrite("Trying to Eject the drive " & EjectVolume($OpenVolume) & @crlf) ; <=== use of the autoejectit
            Case $objEvent.Path_.Class()="__InstanceDeletionEvent"
                Consolewrite("Disque " & $objEvent.TargetInstance.DeviceId & "supprimé."& @CR)
;~ ==========================================================

Func Terminer()
    Exit 0

Func ReportError($szMsg)
    ConsoleWrite(StringFormat($szErrorFormat, _API_GetLastErrorMessage (), $szMsg) & @CRLF)
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
    $szVolumeName = StringFormat($szVolumeFormat, $cDriveLetter)
    ;$szVolumeName = $szVolumeFormat & $cDriveLetter
    ConsoleWrite($szVolumeName & @crlf )
    $hVolume = _API_CreateFile ($szVolumeName, 2,$dwAccessFlags, 6)
        hVolume = CreateFile(   szVolumeName,
        NULL );
    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
    Return False;
EndFunc   ;==>LockVolume
Func DismountVolume($hVolume)
    ConsoleWrite("Dismount " & $hVolume & @crlf)
    Local $dwBytesReturned, $iRead
    local $aResult = _Device_Control($hVolume, $FSCTL_DISMOUNT_VOLUME, $iRead)
    Return $aResult
    ;Return $dwBytesReturned
EndFunc   ;==>DismountVolume
Func PreventRemovalOfVolume($hVolume, $fPreventRemoval)
    Local $dwBytesReturned
    Local $aResult
    Local $lpInbuffer,$nInBufferSize,$lpOutBuffer,$nOutBufferSize,$lpOverlapped
    $PMRBUFFER = DllStructCreate("bool PreventMediaRemoval")
    $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), _
    if $aResult = 0 then msgbox(0,"",_API_GetLastErrorMessage())
    Return $aResult <> 0
     ;& PMRBuffer, sizeof (PREVENT_MEDIA_REMOVAL),
    ;NULL, 0,
    ; & dwBytesReturned,
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;
        ConsoleWrite("Volume can't be locked or dismounted, please close possible opened files" & @crlf)
    ; Close the volume so other processes can use the drive.
    If CloseVolume($hVolume) = False Then
        Return False;
    If $fAutoEject Then
        ConsoleWrite(StringFormat("Media in Drive %s has been ejected safely.\n", $cDriveLetter))
        If $fRemoveSafely Then
            ConsoleWrite(StringFormat("Media in Drive %s can be safely removed.\n", $cDriveLetter))
    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, _
    $iRead   = DllStructGetData($tRead, "Data")
    ConsoleWrite("Device Control " & $iRead & @CRLF)
    Return $aResult<>0
EndFunc   ;==>_Device_Control

- The problem is i don't know where to put the HotKey to quit the program when i launch the program, it works, but when i press 'ESC' it only quit when a usb change has been detected. I would like to quit exactly when i want. i don't specialy need a hotkey, even a gui with a button is better but i don't know gui creation for the moment.

- Does a script already exist for copying data on usb keys with shorter code?

Thank you for your help and suggests,


Link to comment
Share on other sites

Any ideas for the place of the hotkey?

Add this to the top of the script: Opt("TrayIconDebug", 1)

And when you hit ESC and nothing happens, check what line of the script it's hung up on.


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

What happens if you insert a sleep(1000) statement into the while loop? Don't think that the while loop is some kind of blocking function but it's worth the try...

A While/WEnd loop is not blocking, but can slam your CPU usage. A shorter sleep, i.e. Sleep(20) or Sleep(100), is usually better to free up the CPU while still making the script responsive to events. A full second is slow enough to be perceptible lag to the user.


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...