Sign in to follow this  
Followers 0
symadis

Batch copy files to usb

7 posts in this topic

Hello,

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>


;Prototypes
;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
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 = 20

   
           

$chemin="c:\usbee\"
$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)
        Select
            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)
        EndSelect
    EndIf
    
WEnd
;~ ==========================================================

Func Terminer()
    Exit 0
EndFunc




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

- 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,

Loris

Share this post


Link to post
Share on other sites



Any ideas for the place of the hotkey?

Share this post


Link to post
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

Share this post


Link to post
Share on other sites

Thank you, i'll try this!

Share this post


Link to post
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...

Share this post


Link to post
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

Share this post


Link to post
Share on other sites

I know that 1 sec is to much to go productive with a program. It was only for testing purpose. In our domain we use some AutoItscripts with GUI's. I think the users would allready killed me if i used a sleep(1000) <_<

Share this post


Link to post
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
Sign in to follow this  
Followers 0