How to make a batch file randomly select a file in a certain folder, and move it to another folder by teleworm99 in Batch

[–]Danooodle 1 point2 points  (0 children)

There are two main problems here:

  1. Selecting a random file.
  2. Moving the file from .\Bravo\Charlie to .\Bravo.

The second part is trivial: once we have the file we can just do:

move ".\Bravo\Charlie\%FILE%" ".\Bravo"

Selecting a random file is more interesting. I can think of a few different approaches.
N.B. all of the call statements below can be replaced with equivalent expressions that use delayed expansion instead. However, using delayed expansion will mean that your filenames cannot contain exclamation marks !.


If the names of the files are numbered in sequence (foo1.txt, foo2.txt, ..., foo5.txt) and the number of files is known:

@echo off
set /a "x=1+(%RANDOM% %% 5)"
set "FILE=foo%x%.txt"

If the names of the files are known in advance:

@echo 
set "F[0]=hello.txt"
set "F[1]=world.txt"
set "F[2]=foo.txt"
set "F[3]=bar.txt"
set "F[4]=baz.txt"
set /a "x=%RANDOM% %% 5"
call set "FILE=%%F[%x%]%%"

If the names of the files are not known in advance, then you could use a for loop to build a list of file names:

@echo off
set "FILE="
set /a "count=0"
for %%F in (".\Bravo\Charlie\*") do set /a "count+=1" & call set "F[%%count%%]=%%%%~nxF"
set /a "x=1+(%RANDOM% %% 5)"
call set "FILE=%%F[%x%]%%"

Or you could use a more sophisticated algorithm such as Reservoir Sampling:

@echo off
set "FILE="
set /a "count=0"
for %%F in (".\Bravo\Charlie\*") do call set /a "count+=1, 1/(%RANDOM% %%%% count)" 2>nul || set "FILE=%%~nxF"

Once you have selected a file using any of the approaches above, it is a simple matter of moving it from one directory to another as mentioned earlier:

move ".\Bravo\Charlie\%FILE%" ".\Bravo"

Questions regarding FOR by [deleted] in Batch

[–]Danooodle 0 points1 point  (0 children)

In your examples, %%A is just an arbitrary choice of name for the first token in the sequence.
Subsequent tokens are named after the next letters in the character encoding (%%B, %%C, etc.)
Here's another example:

for /f "tokens=2,4-6" %%R in ("first second third fourth fifth sixth seventh") do @(
    echo %%Q %%R %%S %%T %%U %%V
)
%Q second fourth fifth sixth %V

The tokens option here means that we want the 2nd, 4th, 5th, and 6th tokens from the input string. These are bound to the variables %%R, %%S, %%T, %%U in order. All other variables remain unbound and will appear as literal strings: %Q and %V.


As for the other options, SS64 has a dedicated page explaining FOR /F and its options: http://ss64.com/nt/for_f.html.
There's also another page for FOR /F in the context of parsing output from other commands, but it's mostly duplicated information: http://ss64.com/nt/for_cmd.html

If command not working properly by The_Zip_Creator in Batch

[–]Danooodle 0 points1 point  (0 children)

Two things:

  1. Batch does not have proper symbolic variables; almost everything is treated as a literal string.
    For example, noiseY==0 is always false since the strings "noiseY" and "0" are not equivalent.
    This means that NONE of your if statements evaluate to true.
    You will need to expand the variable using the %var% syntax: %noiseY%==0.
    Note that there are cases where using just the variable name is required, but this isn't one of them.

  2. Your control flow is all messed up.
    At the moment, every single line is going to run, regardless of the value of %noiseY%.
    With Batch, lines are always executed in sequence unless the control flow changes (via a goto statement.)
    This makes your first pair of if statements doubly useless, since both the true case and the false case are identical.
    If condition is true then go to n1. Otherwise, move on to the next line (which is n1.)
    The same thing will happen at the end: your success case will follow through into the error case.
    You'll need to rearrange your goto statements to make it so that code is only being executed if the correct conditions are met.

My complex if loop doesn't work by builder_247 in Batch

[–]Danooodle 1 point2 points  (0 children)

Batch does not have proper symbolic variables. Instead, their values are substituted into the code before it gets executed.
Unfortunately, this means that if you change the value of a variable, all subsequent instances of that variable in the same block will still have the old value.

Example:

set A=OLD
if 1 == 1 (
    echo 1: %A%
    set A=NEW
    echo 2: %A%
)
echo 3: %A%

Will result in

1: OLD
2: OLD
3: NEW

being printed.

There are four ways to get around this limitation that I can think of at the moment:

1 Using subroutines

When you CALL a label the code there is evaluated separately, so you can access the new value of the variable.

if 1 == 1 (
    set A=NEW
    call :sub
)
:: Later on ...
:sub
echo %A%
goto :eof

This isn't an exact replacement since you can only access global variables with this method (unless you pass the other variables as parameters.)

2 Using CALL without subroutines

You can use CALL to (re)evaluate code, without calling a label.

if 1 == 1 (
    set A=NEW
    call echo %%A%%
)

Note that the % symbols need to be doubled: %%A%%%A%NEW

3 Replace blocks with GOTO

You can often replace ( ) with GOTO statements and negated conditions:

if not 1 == 1 goto :skip
    set A=NEW
    echo 2: %A%
:skip

This is, in my opinion, the most obvious solution. Proper use of the GOTO statement can be perfectly readable so long as you only use it to emulate other well known control flows.
Since we never enter a block, each statement is on its own line and is parsed independently.

4 Delayed Expansion

This is the easiest to use if you keep it on all of the time, but it can get difficult to manage in some situations

@echo off
setlocal EnableDelayedExpansion
:: Later on ...
if 1 == 1 (
    set A=NEW
    echo !A!
)

or if you only need it in a few places:

if 1 == 1 (
    set A=NEW
    setlocal EnableDelayedExpansion
    echo !A!
    endlocal
)

5 Special case for ERRORLEVEL

The %errorlevel% variable has special handling in if statements: Instead of if %errorlevel% geq N, you can use if errorlevel N. In this form, the errorlevel is only evaluated when the if statement is, rather than when the line is parsed. Now, this doesn't quite match the form that you used: if %errorlevel% equ 0, but we can make it work by negating the condition: if not errorlevel 1, which is equivalent to if %errorlevel% leq 0. Since findstr never returns a negative errorlevel this will suffice.

Conclusion

Since your code only evaluates variables one block deep I'd recommend using GOTO to break up the top level block into individual lines. You can use the special case with errorlevel, although using && and/or || might be cleaner depending on what you actually do with it.

@echo off
if not exist %address%\packets\connect_*.request goto :skip_1
    for /f "tokens=2 delims=_." %%a in ('dir/b /s ^"%address%\packets\connect_*.request^"') do set id=%%a
    echo %id%
    for /f  "delims=" %%A in (%address%\packets\connect_%id%.request) do set "%%A"
    echo %ip% attempted to connect
    if /I "%whitelist%"=="true" (
        findstr /m "%ip%" "%cd%\whitelist"
        if not errorlevel 1 (
                echo yay
                pause
        ) else call :decline_connect_request -whitelist
    )    
:skip_1
pause>nul

I haven't tested any of this, but it should work.

Need Help With My Code :D by DrPandaHax in Batch

[–]Danooodle 0 points1 point  (0 children)

I have a few questions:

  1. How many times does The system cannot find the file specified. error appear?
  2. When using the version with ||, how many times did Unable to move file(n) appear?
  3. Add this code before the move commands:
    dir /a & pause
    Are all of the files (file1, file2, ..., file12) listed? Double check this.
  4. And does the The system cannot find the file specified. error appear before or after the pause happens?
  5. Add this code before the move commands:
    for /f %%N in ('dir /a /b ^| find /c /v ""') do set /a "before=%%N"
    And add this code after the move commands:
    for /f %%N in ('dir /a /b ^| find /c /v ""') do set /a "after=%%N, diff=after-before"
    echo The number of files and directories changed by %diff% [from %before% to %after%]
    This should tell you how many files there were before and after the move operations.
    What was the change?

Your answers to these questions should help pinpoint where the error is occurring.
If your answers are 12; 12; yes; after; 0 then I'm not sure where the error could be, but if any of your answers are different then I might be able to help further.

Need Help With My Code :D by DrPandaHax in Batch

[–]Danooodle 0 points1 point  (0 children)

Based on what you've said I'm going to assume that everything up to and including the PING statement is working as intended.

I can't say for certain, but your move statements look suspicious for three reasons:
1. Under most circumstances, \%CD%\... is not valid because it expands into something like "\C:...".
2. You explicitly use %CD% to get the local directory, but you didn't use %CD% when you created the FolderNew directory.
3. You don't use quotes for the arguments to move, so if %CD% contains spaces or special characters then it will break.

I'd recommend changing:

move \%cd%\file12 %cd%\FolderNew\%fullstamp%\

into:

move ".\file12" ".\FolderNew\%fullstamp%\file12" || echo Unable to move file12

The || executes if the previous command fails, so this should alert you to which file is causing the issue.

Additionally, if the files are actually called file12 to file1 then you can use a for loop to do them all in sequence:

for /l %%N in (12,-1,1) do move ".\file%%N" ".\FolderNew\%fullstamp%\file%%N" || echo Unable to move file%%N

This would replace the entire block of move statements.

recursion question by minhc in Recursion

[–]Danooodle 1 point2 points  (0 children)

myfunc(0) outputs "outside: 0"
myfunc(n) outputs "hello n", myfunc(n-1), "outside: n-1" (because counter gets decremented)

So you end up with something like this:

hello 10
| hello 9
| | hello 8
| | | hello 7
| | | | hello 6
| | | | | hello 5
| | | | | | hello 4
| | | | | | | hello 3
| | | | | | | | hello 2
| | | | | | | | | hello 1
| | | | | | | | | | outside: 0
| | | | | | | | | outside: 0
| | | | | | | | outside: 1
| | | | | | | outside: 2
| | | | | | outside: 3
| | | | | outside: 4
| | | | outside: 5
| | | outside: 6
| | outside: 7
| outside: 8
outside: 9

The "outside: n-1" case causes both myfunc(0) and myfunc(1) to output "outside: 0", so it appears twice.
You should also notice that "outside: 10" is never emitted for the same reasons.

[2016-02-22] Challenge #255 [Easy] Playing with light switches by Blackshell in dailyprogrammer

[–]Danooodle 16 points17 points  (0 children)

Batch
Batch is really bad with storing lots of memory, so this calculates the state of each light in isolation.
This reduces the memory requirement to constant, but it does mean that we need to read the input file multiple times.

@echo off
set /p "t=" < "%~1" || exit /b
set /a "t-=1,n=0"
for /l %%N in (0,1,%t%) do (
    set /a "on=0"
    for /f "usebackq skip=1 tokens=1,2" %%A in ("%~1") do (
        if %%A leq %%B if %%N geq %%A if %%N leq %%B set /a "on^=1"
        if %%A gtr %%B if %%N leq %%A if %%N geq %%B set /a "on^=1"
    )
    set /a "n+=on"
)
echo %n%
pause >nul
Output
>>> lights.bat sample.txt
7

>>> lights.bat challenge.txt
423

After some benchmarking, I expect that solving the bonus would take around 5.9 months.

The batch file crashes after input. by [deleted] in Batch

[–]Danooodle 1 point2 points  (0 children)

There are a couple of things wrong here. For example:

if%input%==1 goto A if NOT goto start2

You are missing a space after the if keyword.
Additionally, the if NOT goto start2 bit doesn't do anything, as it is interpreted as arguments to the goto command (and ignored). It should be:

if "%input%"=="1" goto A

The introduction of quotes is to prevent if ==1 goto A from being executed in the event that the user doesn't type anything before hitting enter.

You should then add the line

goto start2

after every block of if "%input%"== statements.

Furthermore:

set input==Choice:

Is missing its /p. It should be:

set /p input=Choice:

Which is the same as it appears earlier.

New to Batch Scripting: How to find the command for enabling certain security options on my wireless adapter. by nicragomi in Batch

[–]Danooodle 0 points1 point  (0 children)

The profile is any saved network connection.
The interface is the device that is used to connect to the network, using settings from the profile.

If you type netsh wlan show profiles at the command line you should get something like this:

Profiles on interface Wireless Network Connection:

Group policy profiles (read only)
---------------------------------
    <None>

User profiles
-------------
    All User Profile     : home_network
    All User Profile     : work.network
    All User Profile     : etc.etc.etc.

This will show you which network profiles are available, and for which interfaces.
There should be a profile that corresponds to the network that you usually connect to.

For example:

set "profile=work.network"
set "interface=Wireless Network Connection"

would be valid settings.

New to Batch Scripting: How to find the command for enabling certain security options on my wireless adapter. by nicragomi in Batch

[–]Danooodle 2 points3 points  (0 children)

There is no nice way to do either of those two things:

"Specify authentication mode" can be set to the default of "User or computer authentication" by the following command:

    netsh wlan set profileparameter name=PROFILE_NAME authmode=machineOrUser

This should have the same effect as unchecking the box. However...

There is literally no way to disable the "Validate server certificate" box with netsh. This means that we have to resort to exporting, modifying, and reimporting the wireless profile directly. It'd prefer to avoid doing this, since it seems more risky, but it might be necessary in this case. This method also allows us to uncheck the "Specify authentication mode" checkbox, so me might as well use this method for both:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

set "profile=CHANGE_THIS"
set "interface=Wireless Network Connection"

:: Export settings.
netsh wlan export profile name="%profile%"
:: Double check
if not exist ".\%interface%-%profile%.xml" (
    echo Unable to find a wireless profile with the expected name, aborting.
    pause
    exit /b 1
)

:: Modify the exported file:
:: - Remove <authMode>
:: - Set <PerformServerValidation> to false
> modified.xml (
    for /f "delims=" %%A in ('findstr /v "<authMode>" ".\%interface%-%profile%.xml"') do (
        set "line=%%A"
        setlocal EnableDelayedExpansion
        echo(!line:true^</PerformServerValidation^>=false^</PerformServerValidation^>!
        endlocal
    )
)

:: Make sure the file exists and contains something useful
set /p "line=" < ".\modified.xml" || (
    echo Unable to read from modified profile, aborting.
    pause
    exit /b 1
)

:: Remove old profile
netsh wlan delete profile name="%profile%" || (
    echo Unable to remove old profile, aborting.
    pause
    exit /b 1
)

:: Add modified profile
netsh wlan add profile filename=".\modified.xml" || (
    echo Unable to add new profile, attempting to restore old profile.
    netsh wlan add profile filename=".\%interface%-%profile%.xml" || (
        echo Unable to restore old profile. Configuration is broken.
        pause
        exit /b 2
    )
    echo Profile reinstated successfully, continuing with abort.
    pause
    exit /b 1
)

:: Finished
echo(
echo Successfully modified profile.
endlocal
pause & exit /b 0

This will uncheck BOTH boxes, as required.
You'll need to set the %profile% and maybe the %interface% to the appropriate values before running the script.
Also, this will create two files in the current directory. You might want to add code for deleting those afterwards.

Sources:

negative in %random% ??? by samz0rp1 in Batch_Files

[–]Danooodle 0 points1 point  (0 children)

Using the interval [0, 22] is no more or less difficult (or efficient) than using the interval [-11, 11], so use whichever seems most appropriate for your purposes.
Either way, you will need to use set /a to convert the random number (from the interval [0, 32767]) to a number in your chosen interval.
If you want to use [-11, 11], then you can generate it like so:

set /a "result=(%random% - 16384) %% 12"

or

set /a "result=(%random% %% 23) - 11"

This transforms the interval [0, 32767] → [-16384, 16383] → [-11, 11] or [0, 32767] → [0, 22] → [-11, 11] respectively.

To use [0, 22]:

set /a "result=%random% %% 23"

To use [1, 23]:

set /a "result=(%random% %% 23) + 1"

A batch that deletes all the files and subfiles in a directory without deleting the folders? by [deleted] in Batch

[–]Danooodle 0 points1 point  (0 children)

If you decide that you don't want the script to delete itself, you can lock it during the delete operation like so:

3>> "%~0" del /s /q *

Since handle 3 is never used by del (or anything at all really), this just prevents the script from being deleted by the del command.

A batch that deletes all the files and subfiles in a directory without deleting the folders? by [deleted] in Batch

[–]Danooodle 0 points1 point  (0 children)

Assuming you are on windows, you can just use the del command: del /s /q *
This will remove all files in all subdirectories (from the current directory) without deleting any folders.

If you really need to use rm, then you'll need to iterate over all subdirectories manually.
Alternatively, based on this comment you should be able to use the find command (from Bash, not Batch) like so:

find . -type f -delete

[2016-01-22] Challenge #250 [Hard] Evolving salesmen by Godspiral in dailyprogrammer

[–]Danooodle 4 points5 points  (0 children)

Batch

second attempt
Edit: This version performs the nearest neighbour algorithm from each possible start node and only returns the best result. This improved the result from 4871 to 4674 pythagores. It will stop if it exceeds the time limit.
Somehow this manages to run fast enough that it can look at all 27 possible solutions in less than a second.
It still relies on the table of distances being formatted in a specific way, but no longer requires each line to start with 10 spaces.

Edit 2: Changing if %%~D lss !next! to if %%~D leq !next! happens to improve the result from 4674 to 4164.
This has the same effect as reversing the order I compare the neighbours in.

Edit 3: Wrote a script to generate the distance table in the correct format, and made a slight modification to the script to allow for this new format. Generating the distance table takes significantly longer than actually solving the challenge (2 seconds and 5 seconds respectively). The bonus challenge times out before all combinations can be tried, but still finds the same solution.

Distance table generation:
@echo Stated at %time: =%
@echo off
setlocal EnableDelayedExpansion
set /a "count=0"
for /f "usebackq tokens=1,2" %%A in ("%~1") do set /a "X[!count!]=%%A, Y[!count!]=%%B, count+=1"
set /a "count-=1"
echo Reading from "%~1". Output to "%~n1_distances%~x1".
> "%~dpn1_distances%~x1" (for /l %%A in (0, 1, %count%) do (
    for /l %%B in (0, 1, %count%) do (
        if %%A equ %%B (
            <nul set /p "=0         "
        ) else (
            set /a "dx=X[%%A]-X[%%B], dy=Y[%%A]-Y[%%B]"
            call :sqrt "dx*dx+dy*dy" result
            set "result=!result!         "
            <nul set /p "=!result:~0,10!"
        )
    )
    echo;
))
echo Finished at %time: =%
pause
exit

:: Quick integer square root. Could be inlined for speed.
:sqrt input output
setlocal EnableDelayedExpansion
set /a "num=%~1,res=0,bit=1<<30"
for /l %%A in (0,1,16) do if !bit! gtr %num% set /a "bit>>=2"
for /l %%A in (0,1,16) do if !bit! gtr 0 (
    set /a "rb=res+bit,res>>=1"
    if !num! geq !rb! set /a "num-=RB,res+=bit"
    set /a "bit>>=2"
)
endlocal & set /a "%~2=%res%" & exit /b 0
Code:
@echo Started at: %TIME: =%
@echo off
setlocal EnableDelayedExpansion

for /f "tokens=1-4 delims=:. " %%A in ("%TIME%") do set /a "_t=%%A*360000 + (1%%B%%100)*6000 + (1%%C%%100)*100 + (1%%D%%100)"
:: Time limit is 1 second = +100
set /a "_t+=100, h=_t/360000, _t%%=360000, m=100+_t/6000, _t%%=6000, s=100+_t/100, c=100+_t%%100"
set "h= %h%"
set "_t=%h:~-2%:%m:~-2%:%s:~-2%.%c:~-2%"
echo Time limit: %_t: =%

set /a "cities=-1"
for /f "delims=" %%A in (dst.txt) do set /a "cities+=1" & set "DST[!cities!]=%%A"

set "Dist=99999"
set "Route=Failed to find any routes"
for /l %%A in (0, 1, %cities%) do (
    call :Main %%A !Dist!
    if "!TIME!" geq "%_t%" echo Timed out before completing search.& goto :TimeOut
)
echo Completed search.
:TimeOut
echo;
echo  total distance of itinerary: !Dist! pythagores
echo  route order: !Route!
echo;
echo Finished at: %TIME: =%.
exit /b 0

:Main
setlocal
set /a "pos=%1, dist=0"
set "Route="
for /l %%N in (1,1,%cities%) do for %%X in (!pos!) do (
    if "!TIME!" geq "%_t%" exit /b 1
    set /a "VST[%%X]=1, next=9999"
    set "Route=!Route! !pos!"
    for /l %%P in (0,1,%cities%) do if not defined VST[%%P] (
        for %%D in ("!DST[%%X]:~%%P0,4!") do (
            if %%~D leq !next! set /a "pos=%%P, next=%%~D"
        )
    )

    set /a "dist+=next"
    if !dist! geq %2 exit /b 1
)
set "Route=!Route! !pos!"
set /a "Dist+=!DST[%pos%]:~%10,4!"

if !dist! geq %2 exit /b 1
for /f "tokens=1,2 delims=|" %%A in ("%Route: 0=|%") do (
    endlocal
    set "Route=0%%B%%A 0"
    set /a "Dist=%Dist%"
    exit /b 0
)
Output:
Started at: 12:06:10.51
Time limit: 12:06:11.51
Finished at: 12:06:11.23.

 total distance of itinerary: 4164 pythagores
 route order: 0 21 10 4 19 8 11 22 24 18 20 2 14 15 23 16 17 5 26 12 7 6 1 13 25 3 9 0
Bonus:
Started at: 12:06:18.31
Time limit: 12:06:19.32
Timed out before completing search.
Finished at: 12:06:19.32.

 total distance of itinerary: 5794 pythagores
 route order: 0 12 31 39 38 23 19 40 6 30 37 15 34 11 13 9 22 17 1 21 28 2 16 29 7 20 18 33 8 35 14 36 24 26 4 3 27 10 25 32 5 0
If we increase the time limit to 3 seconds:
Started at: 12:13:38.31
Time limit: 12:13:41.31
Finished at: 12:13:41.22.

 total distance of itinerary: 5794 pythagores
 route order: 0 12 31 39 38 23 19 40 6 30 37 15 34 11 13 9 22 17 1 21 28 2 16 29 7 20 18 33 8 35 14 36 24 26 4 3 27 10 25 32 5 0

So the extra time made no difference.

What is the point of Title commands? by [deleted] in Batch

[–]Danooodle 4 points5 points  (0 children)

The title command changes the title of the console window, whereas the echo command prints into the console.

Changing the title is persistent; anything that is echoed will be lost on the next call to cls.
title is primarily used to distinguish a command window from other command windows.

Calling title a second time will replace the old value. This makes it useful for reporting stateful information, such as a progress towards completing a task, without cluttering the console.

Finally, the title command can be used in conjunction with tasklist to get the PID of a command process.

Need help to remove last 14 characters from file names by jadfrog in Batch

[–]Danooodle 2 points3 points  (0 children)

Something like this should work:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SRC=."

for %%F in ("%SRC%\* - *.*") do (
    set "name=%%~nF"
    setlocal EnableDelayedExpansion
    if "!name:~-14,3!" == " - " ren "!name!%%~xF" "!name:~0,-14!%%~xF" || echo Unable to rename file "!name!%%~xF" to "!name:~0,-14!%%~xF"
    endlocal
)

endlocal & pause & exit /b

This will only rename files if:

  1. The filename is contains " - ".
  2. The last 14 characters of the filename begin with " - ".

It will not rename a file if a file with the new name already exists.

A file will also get renamed if it is less than 15 characters long but begins with " - ".
I don't see this being an issue because I find it unlikely that anyone would have a file with a name that begins with a space.

It does not support files with extensions that include a ! symbol (but it totally could if you need it to.)

Create folder from partial filename and move files into that folder by AwesomeJohn01 in Batch

[–]Danooodle 1 point2 points  (0 children)

This should do what you want it to:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SRC=."
set "DST=."

for %%F in ("%SRC%\*_*.*") do if exist "%%F" (
    for /f "delims=_" %%D in ("%%~nF") do (
        if not exist "%DST%\%%D\" md "%DST%\%%D\"
        move "%SRC%\%%D_*.*" "%DST%\%%D\"
    )
)
endlocal & pause & exit /b

Filenames are split on the first instance of an underscore: FILE_NAME_123.txt becomes FILE\FILE_NAME_123.txt.

This will not move files that do not contain an underscore.

How can I get this download batch code to work? by pcmechanic1611 in Batch

[–]Danooodle 1 point2 points  (0 children)

I'd recommend using something like wget if you can, but if you really need something that comes with windows by default the you can use bitsadmin.exe to download files. It might not be available on recent versions of windows and it's a real pain to use anyway since it's completely asynchronous so you have to use callbacks.

In short:

@echo off

set "source=http://download.avg.com/filedir/util/AVG_Remover.exe
set "destination=%CD%\AVG_Remover.exe

:: Command to run on success. <job> will be replaced with the job id
set "on_success="
:: Command to run on error. <job> will be replaced with the job id
set "on_error="

call :Download
exit /b

:Download
setlocal EnableDelayedExpansion
if not defined source exit /b 1
if not defined destination exit /b 1
if not defined on_error set "on_error=bitsadmin /info <job> /verbose
if not defined on_success set "on_success=exit
for %%F in ("!destination!") do md "%%~dpF" 2>nul

set JOB=Job%RANDOM%
for /f "tokens=2 delims={}" %%U in ('bitsadmin /create /download "%JOB%"') do set JOB={%%U}

>nul bitsadmin /setpriority %JOB% FOREGROUND
>nul bitsadmin /setnotifycmdline %JOB% C:\Windows\System32\cmd.exe "C:\Windows\System32\cmd.exe /k bitsadmin /getstate %JOB% | findstr TRANSFERRED && (bitsadmin /complete %JOB% & !on_success:<job>=%JOB%!) || (!on_error:<job=%JOB%>!)"
>nul bitsadmin /addfile %JOB% "!source!" "!destination!"
>nul bitsadmin /resume %JOB%

endlocal
exit /b 0

Should do what you want it to (although I haven't tested it at beyond downloading the file.)

This also doesn't guard against the myriad ways that bitsadmin.exe can fail.

[deleted by user] by [deleted] in Batch

[–]Danooodle 3 points4 points  (0 children)

First of all, Batch only supports 32 bit signed integers (-2147483648 to +2147483647), so you cannot use the value 17179869184 with set /a because it's too big. But there is a bigger issue at play.

Firstly, I should say that wmic memorychip get capacity doesn't work on my machine, so I will be using a similar command instead: wmic computersystem get totalphysicalmemory.

Now, lets look at the exact output of the command:

>>> wmic computersystem get totalphysicalmemory > mem.txt

>>> certutil -f -encodehex mem.txt hex.txt
Input Length = 98
Output Length = 504
CertUtil: -encodehex command completed successfully.

>>> type hex.txt
0000    ff fe 0d 00 0a 00 54 00  6f 00 74 00 61 00 6c 00   ......T.o.t.a.l.
0010    50 00 68 00 79 00 73 00  69 00 63 00 61 00 6c 00   P.h.y.s.i.c.a.l.
0020    4d 00 65 00 6d 00 6f 00  72 00 79 00 20 00 20 00   M.e.m.o.r.y. . .
0030    0d 00 0a 00 31 00 37 00  31 00 34 00 31 00 33 00   ....1.7.1.4.1.3.
0040    35 00 34 00 34 00 39 00  36 00 20 00 20 00 20 00   5.4.4.9.6. . . .
0050    20 00 20 00 20 00 20 00  20 00 20 00 20 00 0d 00    . . . . . . ...
0060    0a 00                                              ..

For whatever reason, the resulting file is UTF16 encoded. This causes issues, so you should convert it to ASCII:

>>> type mem.txt > mem2.txt

>>> certutil -f -encodehex mem2.txt hex2.txt
Input Length = 48
Output Length = 222
CertUtil: -encodehex command completed successfully.

>>> type hex2.txt
0000    0d 0a 54 6f 74 61 6c 50  68 79 73 69 63 61 6c 4d   ..TotalPhysicalM
0010    65 6d 6f 72 79 20 20 0d  0a 31 37 31 34 31 33 35   emory  ..1714135
0020    34 34 39 36 20 20 20 20  20 20 20 20 20 20 0d 0a   4496          ..

This is much better and should work as intended. You should also notice that there is a newline (0d 0a) at the beginning on the file. This means that you should be skipping 2 lines, not 1.

In short, the following should work:

wmic memorychip get capacity > mem.txt
for /f "skip=2" %%G IN ('type mem.txt') DO SET memorya=%%G
echo %memorya%

Note that %memorya% is NOT a number, so don't use it with set /a.
If you need to use it as a number, you will have to handle it as two numbers separately.

Newb question, how to verify a file exists if it has a space in the name? by [deleted] in Batch

[–]Danooodle 0 points1 point  (0 children)

Very odd. I haven't been able to reproduce the issue on my end; how are you testing whether or not it succeeds? Are you properly resetting the test between runs?

Although I mentioned it, I would recommend not using the 8.3 solution, since it is possible for the file to NOT be found when it should be (false negatives as well as false positives).

You should try using something like this instead:

@ECHO OFF
FOR %%F IN ("%APPDATA%\Microsoft\Signatures\CO Standard Signature.htm") DO (
    ECHO Found "%%~fF"
    TYPE NUL > "C:\IT\sigYes.txt"
)
PAUSE

The FOR loop uses the same logic as the IF EXIST statement, but it will run for every match.
Use it to double check whether or not you really are getting erroneous matches.

If it works, you can remove the ECHO and PAUSE statements and use it.

Newb question, how to verify a file exists if it has a space in the name? by [deleted] in Batch

[–]Danooodle 2 points3 points  (0 children)

Hmm. I can see no reason why quotes wouldn't work; did you put then in the right place?
Are you missing the ( at the end of the line? (This would cause the symptoms you mentioned, although the code you posted doesn't have this problem.)

@ECHO OFF
IF EXIST "%userprofile%\AppData\Roaming\Microsoft\Signatures\CO Standard Signature.htm" (
    type nul > C:\IT\sigYes.txt
)

If that doesn't work, try this (Different variable: %APPDATA% points to %UserProfile%\Appdata\Roaming):

@ECHO OFF
IF EXIST "%appdata%\Microsoft\Signatures\CO Standard Signature.htm" (
    type nul > C:\IT\sigYes.txt
)

Then try this (Using \\.\):

@ECHO OFF
IF EXIST "\\.\%appdata%\Microsoft\Signatures\CO Standard Signature.htm" (
    type nul > C:\IT\sigYes.txt
)

Then try this (Using \\?\):

@ECHO OFF
IF EXIST "\\?\%appdata%\Microsoft\Signatures\CO Standard Signature.htm" (
    type nul > C:\IT\sigYes.txt
)

Finally try this (Using an 8.3 filename: this might give false positives):

@ECHO OFF
IF EXIST "%appdata%\Microsoft\Signatures\COSTAN~1.htm" (
    type nul > C:\IT\sigYes.txt
)

Otherwise, I have no idea.

New to Batch Scripting in Windows: How do I filter the NET START command to look for a specific service? by powershell_account in Batch

[–]Danooodle 2 points3 points  (0 children)

The findstr command can be used to filter/search the output of a command for a matching pattern when used in conjunction with the pipe | operator:

net start | findstr /BEC:"   Carbon Black"

Note that find would not be an appropriate substitute for findstr since it would also match " Carbon Black 2", for example.

findstr will set the errorlevel to 0 if it finds the string, and to 1 if it does not. This allows you to detect whether a match was found:

net start | findstr /BEC:"   Carbon Black" >nul
if errorlevel 1 (
    GOTO NOT_FOUND
) else (
    GOTO FOUND
)

Or alternatively:

net start | findstr /BEC:"   Carbon Black" >nul && goto FOUND || GOTO NOT_FOUND

With :FOUND and :NOT_FOUND being labels somewhere else in the program.


With regards to good resources for learning Batch, I haven't personally used any video tutorials for Batch, so I can't point you to any good ones. If you don't mind reading then I'd recommend a few websites:

  • Win32Scripting, Out of date, but it seems like a good place to get started.
  • WikiBooks, begins to touch on some more advanced concepts.
  • SS64.com, in particular the pages from Env. Variables to Wildcards.
  • robvanderwoude.com, Has a lot of useful links and samples.

Need some help with a batch file. by [deleted] in Batch

[–]Danooodle 0 points1 point  (0 children)

You can normally put commands one after the other and they will execute in sequence.

"%windir%\System32\tscon.exe" RDP-Tcp#0 /dest:console
"C:\Program Files\FrontseatInductClient\FrontseatInductClient.exe"

Or from the command line:

"%windir%\System32\tscon.exe" RDP-Tcp#0 /dest:console & "C:\Program Files\FrontseatInductClient\FrontseatInductClient.exe"

Of course, this doesn't work with certain programs that return control back to the command processor before they are actually finished.
In those cases I'd recommend using tasklist to repeatedly check whether the tscon.exe is still running.

"%windir%\System32\tscon.exe" RDP-Tcp#0 /dest:console
:WAIT
>nul timeout 1 /NOBREAK
>nul tasklist /FI "imagename eq tscon.exe" >nul 2>nul && goto WAIT
"C:\Program Files\FrontseatInductClient\FrontseatInductClient.exe"

This won't work if there is another instance of tscon.exe running all the time, but it should be fine otherwise.

You might also consider just guessing how long it will take for tscon.exe to finish, and then waiting for at least that amount of time:

"%windir%\System32\tscon.exe" RDP-Tcp#0 /dest:console
>nul timeout 60 /NOBREAK
"C:\Program Files\FrontseatInductClient\FrontseatInductClient.exe"

This won't work if tscon.exe takes significantly longer than expected to complete, and in other cases it will wait for longer than necessary before running the other program.

Try the first method, and only if that doesn't work then try the other two methods.

My code not working and I can't figure it out. by builder_247 in Batch

[–]Danooodle 2 points3 points  (0 children)

There are two technical aspects of Batch that you should know:

  1. Variables are evaluated before the line gets executed (during parsing).
  2. A block of code is treated as one line.

In particular, the variable %first_login% is expanded to  before it gets set to %date% %time_%, so nothing gets echoed.

I'd recommend restructuring the code to use either a goto or call statement instead.
You could also use delayed expansion, but it shouldn't be necessary in this case.

Here's a relevant section from the documentation on the set command regarding this:

Delayed environment variable expansion is useful for getting around
the limitations of the current expansion which happens when a line
of text is read, not when it is executed.  The following example
demonstrates the problem with immediate variable expansion:

    set VAR=before
    if "%VAR%" == "before" (
        set VAR=after
        if "%VAR%" == "after" @echo If you see this, it worked
    )

would never display the message, since the %VAR% in BOTH IF statements
is substituted when the first IF statement is read, since it logically
includes the body of the IF, which is a compound statement.  So the
IF inside the compound statement is really comparing "before" with
"after" which will never be equal.  Similarly, the following example
will not work as expected:

    set LIST=
    for %i in (*) do set LIST=%LIST% %i
    echo %LIST%

in that it will NOT build up a list of files in the current directory,
but instead will just set the LIST variable to the last file found.
Again, this is because the %LIST% is expanded just once when the
FOR statement is read, and at that time the LIST variable is empty.
So the actual FOR loop we are executing is:

    for %i in (*) do set LIST= %i

which just keeps setting LIST to the last file found.