0
votes

I'm trying to do a script that will run constantly in background. Its goal is to detect USB flash drives, external hard drives, or any writable device that you'd connect to your computer. Once it detected one, it'd copy a file at the root of this device. Here's my code (the echo lines are for clearer debugging):

@echo off
:loop
for /F "tokens=1*" %%a in ('fsutil fsinfo drives') do (
    for %%c in (%%b) do (
        for /F "tokens=4" %%d in ('fsutil fsinfo drivetype %%c') do (
            if %%d equ amovible (
                echo Found out that %%c is removable. Trying to echo the content...
                dir %%c >NUL
                echo Error: %errorlevel%
                if %errorlevel%==0 (
                    echo Errorlevel is 0! Copying...
                    if not exist %%c\test.txt (
                        copy .\test.txt %%c\test.txt
                        echo.
                    )
                ) else (
                    echo Errorlevel isn't 0. Looks like the drive isn't here, or is unavailable. Aborting copying...
                  echo.
                )
            )
        )
    )
)
TIMEOUT 2
goto :loop

And here's the problem. The condition "if %errorlevel%==0" is supposed to check if the "dir %%c >NUL" command succeeded, so if errorlevel is 0, that means there's a filesystem on the device, and it's not like an empty card reader or an empty floppy drive. The thing is when I execute my code, errorlevel is always 0, and I can't figure out why ("echo Error: %errorlevel%" tells it). So the file test.txt does copy on my USB flash drive, so this basically work, the thing is when it comes to copy the file to my floppy drive, an error box shows up, saying that I should insert a device in the reader, that's why I want to do this errorlevel check.

So if someone has a solution, please help, I'm really stuck. Thanks in advance.

1
You need to use delayed expansion (!ErrorLevel!), because otherwise, you get the ErrorLevel present when the entire parenthesised block (loop) is parsed...aschipfl
Whoaaw, thanks man! Worked like a charm!Nim
You could of course use the classic if not errorlevel 1 ... which doesn't need delayed expansion.user6811411
You're welcome! What is the loop for %%c in (%%b) do ( ... ) intended for?aschipfl
+aschipfl Well the fsutil fsinfo drives commande lists the differents drive letters, so the for loop is used to check them one by oneNim

1 Answers

2
votes

You need to use delayed expansion (!ErrorLevel!), because otherwise, you get the ErrorLevel value that is present when the entire parenthesised block (that is the nested for loop structure here) is parsed. Since exclamation marks are consumed by the delayed expansion feature, I would enable it only where it is actually needed, like this:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
:loop
for /F "tokens=1*" %%a in ('fsutil fsinfo drives') do (
    for %%c in (%%b) do (
        for /F "tokens=4" %%d in ('fsutil fsinfo drivetype %%c') do (
            if "%%d"=="amovible" (
                echo Found out that %%c is removable. Trying to echo the content...
                dir "%%~c" > nul
                setlocal EnableDelayedExpansion
                echo Error: !ErrorLevel!
                if !ErrorLevel! equ 0 (
                    endlocal
                    echo ErrorLevel is 0! Copying...
                    if not exist "%%~c\test.txt" (
                        copy ".\test.txt" "%%~c\test.txt"
                        echo/
                    )
                ) else (
                    endlocal
                    echo ErrorLevel isn't 0. Looks like the drive isn't here, or is unavailable. Aborting copying...
                    echo/
                )
            )
        )
    )
)
timeout 2
goto :loop
endlocal

Alternatively, since dir does never set ErrorLevel to a negative value, you could also use the if not errorlevel 1 syntax, meaning "if not ErrorLevel is greater than or equal to 1", and therefore "if ErrorLevel is less than 1" (apparently you cannot echo the actual ErrorLevel value then):

                ...
                dir "%%~c" > nul
                if not ErrorLevel 1 (
                    echo ErrorLevel is 0! Copying...
                    if not exist "%%~c\test.txt" (
                        copy ".\test.txt" "%%~c\test.txt"
                        echo/
                    )
                ) else (
                    echo ErrorLevel isn't 0. Looks like the drive isn't here, or is unavailable. Aborting copying...
                    echo/
                )
                ...

Another method is to use the conditional execution operators && and/or ||, which lets the following command or block execute only in case the preceding command returns an exit code of zero (most of the time, and also for the dir command here, the exit code is the same value as ErrorLevel):

                ...
                dir "%%~c" > nul && (
                    echo ErrorLevel is 0! Copying...
                    if not exist "%%~c\test.txt" (
                        copy ".\test.txt" "%%~c\test.txt"
                        echo/
                    )
                ) || (
                    echo ErrorLevel isn't 0. Looks like the drive isn't here, or is unavailable. Aborting copying...
                    echo/
                )
                ...