The Problem: I was messing around with Batch files and wanted to use multiple colors. I found a solution on Stack Overflow however, I accidentally created a file that is un deletable. It takes up 0kb, has no data in it, its file type is "file", and apparently it is constantly being used by Desktop even though no tasks are running
You can view the code below...
WARNING The code below will create an undeletable file named Immortal
#echo off
:StartScreen
SETLOCAL EnableDelayedExpansion
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
set "DEL=%%a"
)
cls
call :ColorText 08 "Immortal : File"
pause >nul
:ColorText
echo off
<nul set /p ".=%DEL%" > "%~2"
findstr /v /a:%1 /R "^$" "%~2" nul
del "%~2" > nul 2>&1
Attempted Solutions: I looked online for possible solutions and got some other people to help to. We did a virus check, disk error check, and even booted it in safe mode to try and delete it. Also we have all admin privileges on the file and even used an elevated command prompt to delete the file but nothing works! It is almost as if the file exists but doesn't exist at the same time.
Related
I want to make a Batch file to create windows firewall rules for an executable (for example, python). To do this, I have the following script:
REM ~ Open ports. Run with elevated administrator rights.
CALL :OPEN "python"
GOTO :EOF
:OPEN
IF ERRORLEVEL 1 (
GOTO :EOF
)
FOR /F %%i IN ('where %1') DO CALL :OPEN_PROGRAM "%1" %%i && GOTO :EOF
GOTO :EOF
:OPEN_PROGRAM
FOR %%j IN (TCP UDP) DO CALL :OPEN_PROGRAM_PORT %1 %2 "%%j"
GOTO :EOF
:OPEN_PROGRAM_PORT
netsh advfirewall firewall add rule name=%1 description=%1 dir=in action=allow edge=deferuser profile=private program=%2 protocol=%3
GOTO :EOF
This works fine as long as there are no spaces in the path to the executable.
If there are spaces in the path, then only the part up to the spaces is put in the %%i variable. I tried using 'where /F %1' , but then it still cuts the output on the space.
Is there a way to store the full output of where %1 in a variable? (Preferably without writing it to a file)
I would first advise you not to pass an filename without an extension. Doing so relies upon each of the extensions listed under %PATHEXT%, and you could have files named python.com, python.bat, python.cmd, python.vbs, python.vbe, python.js, python.jse, python.wsf, python.wsh, and python.msc, as well as python.exe. I'm sure you wouldn't want to unknowingly create firewall rules for all of those.
I would also advise that you do not use the where command for this. The reason being that it could return more than a single item. For example, try this, where notepad.exe and if memory serves, you'll probably see, C:\WINDOWS\System32\notepad.exe, followed by C:\WINDOWS\notepad.exe. That is because where.exe searches each location in %PATH% in order of their listing, and returns each, as the first two entries under %PATH% should by default be C:\WINDOWS\system32;C:\WINDOWS;.
My suggestion therefore would be to use another method, which returns the first item found under %PATH% as opposed to all, and this should, if you've used the variable properly, return the default, (most used) item. The method is the %~$PATH variable expansion, and is documented under the help information for the for command, i.e. entering for /? at the Command Prompt.
Example Script:
#Echo Off
SetLocal EnableExtensions
Rem ~ Open ports. Run with elevated administrator rights.
"%__AppDir__%reg.exe" Query HKU\S-1-5-19 1>NUL 2>&1 || (
Echo This script must be run elevated.
Echo Please use 'Run as administrator'
"%__AppDir__%timeout.exe" /T 3 /NoBreak 1>NUL
GoTo :EOF)
Call :OpenPorts "python.exe"
Pause
GoTo :EOF
:OpenPorts
For %%G In ("%~1") Do For %%H In (TCP UDP) Do (
"%__AppDir__%netsh.exe" AdvFirewall Firewall Add Rule^
Name="%~n1" Description="%~1" Dir=in Action=allow^
Edge=deferuser Profile=private Program="%%~$Path:G"^
Protocol=%%H)
Exit /B
I have removed all of the unnecessary Call commands, (using just the one), and deliberately used carets to split up your super long line, for readability; (which also allows you to include the localport= and/or remoteport= option, which I'd assume by your 'Open Ports' name you're going to want to include as a modification to the above later). I also took the liberty of including some code, to determine if the script was being run elevated, and display a message before closing, if it isn't.
Write the output of where.exe to a file, then read the file one line at a time. There is a way to do it without a temp file after the "===" line.
#ECHO OFF
SET "XTOFIND=%~1"
SET "TEMPFILE=%TEMP%\wherelist.tmp"
IF EXIST "%TEMPFILE%" (DEL "%TEMPFILE%")
"%__appdir__%where.exe" "%XTOFIND%" >"%TEMPFILE%"
FOR /F "tokens=*" %%A IN ('TYPE "%TEMPFILE%"') DO (
ECHO CALL :OPEN_PROGRAM "%%~A" %2 "%%J"
)
IF EXIST "%TEMPFILE%" (DEL "%TEMPFILE%")
ECHO ============
SET "XTOFIND=%~1"
FOR /F "tokens=*" %%A IN ('"%__appdir__%where.exe" "%XTOFIND%"') DO (
ECHO %%~A
ECHO CALL :OPEN_PROGRAM "%%~A" %2 "%%J"
)
EXIT /B 0
I am looking to build a tail to read log files on windows using only native cmd.
There are various ways to to read a file:
type file.txt
more file.txt
They however do not have a default option to read updates from a file, so does not represent anything like tail.
With a few little hacks and using more to read the file, skipping what was already read before, we are able to tail the file, "almost" realtime.
#echo off & set cnt=0
if "%~1" == "" echo no file specified, usage: "tail.cmd <filename>" & goto :eof
if not exist "%~1" echo file "%~1" does not exist & goto :eof
:tail_sub
2>nul (>>"%~1" echo off) && (goto :file) || (goto :tail_sub)
:file
for /f "tokens=1*delims=]" %%i in ('more "%~1" +%cnt% ^| find /v /n ""') do (
set "line=%%j"
set /a cnt+=1
call echo(%%line%%
)
goto :tail_sub
Currently, without adding a timeout to slow down the infinite loop, it consumes around 5.6MB memory, which is very acceptable in my view.
This does not yet take care of all special characters, like |<>&, but I will spend some time on this to cater for all scenarios I can think off.
This is my first post to this site, though I use it quite often. I wrote a batch file to do the following, ideally. Note: There are alot of echos in here, to help me debug.
1.) Clean up old log files, this works file
2.) Ping a list of systems and output successful results to one file and bad to another
3.) Check if software exists, if not download it
4.) Install software on endpoint
The issue I am encountering is the successful ping output files has trailing spaces. Because of this, the install commands don't work. It puts the trailing space in the UNC path. Since the spaces exist, the run command doesn't work.
HELP PLEASE, My desk is breaking, due to my forehead smashing into it.
#echo off
cls
set file=_0_Add_Systems_Here.txt
set log1=_3_Responsive.txt
set log2=_4_Non-Responsive.txt
set dir=%cd%
FOR /F "usebackq" %%i IN (`hostname`) DO SET host=%%i
echo Run Cleanup
start _2_Dont_Run_Me.bat
echo Ping
for /F "tokens=*" %%a in (%file%) do #ping %%a | find "TTL=" > nul && echo %%a >> %log1% || echo %%a >> %log2%
echo Output systems
for /F "tokens=*" %%a in (%log1%) do echo "%%a"
echo Check for Framepkg
if not exist framepkg.exe Copy \\<Removed>\c$\MFE\framepkg.exe | echo copying frame package.
if exist framepkg.exe echo Found frame package.
echo copy framepackage to system
for /F "tokens=*" %%b in (%log1%) do copy %dir%\framepkg.exe \\%%b\c$\framepkg.exe /y >> _5_McAfee_Deployment_Output.txt
for /F "tokens=*" %%b in (%log1%) do echo \\%%b\c$\framepkg.exe
echo start agent install
for /F "tokens=*" %%c in (%log1%) do psexec \\%%c cmd /c "c:\framepkg.exe /install=agent /forceinstall" >> \\%host%\%dir%\_5_McAfee_Deployment_Output.txt
....&& >>%log1% echo %%a||>>%log2% echo %%a
should fix your problem (the extra spaces in your code appear to cause the problem; the redirector location within the statement is not relevant - first is as good as last)
OR
....&& echo %%a\ >> %log1% || echo %%a\ >> %log2%
AND
for /F "delims=\" %%b in (%log1%)....
but that would place extra \ in your log files.
(reason for \ is that it can't exist in valid data)
So I'm trying to learn the ins and outs of findstr since it's come up a few times on other batch script questions I've had. I'm trying to have it look for a word (in this case 'webview') through multiple files in a directory, ideally it would pull the line it was found as well as the file name. However, the program gets stuck in this sort of infinite loop with it and I have to force an exit. Any help on if its being caused by the findstr or what is causing it would be amazing as I've been staring at it for several hours now. My current code is below:
ECHO off
SETLOCAL enabledelayedexpansion
ECHO Please input the path to the app directory you'd like scanned
SET /p directorypath=
CD %directorypath%
ECHO Scanning files for Webview
(
FOR /F "delims=" %%a in ('findstr /I /S /M "webview" *.json') DO (
SET "line=%%a"
SET "line=!line:*webview=!"
FOR /F "delims=<" %%b in (!line!) DO ECHO %%b
)) > WebviewScanResults.txt
:eof
UPDATE: Code updated and functional for use as a reference. I pretty much just run the above code a couple of time with different file types replacing *.json and it works fine.
Just an untested try, too late for me:
#ECHO off
SETLOCAL enabledelayedexpansion
ECHO Please input the path to the app directory you'd like scanned
SET /p directorypath=
PushD "%directorypath%"
ECHO Scanning files for Webview
(
FOR /F "tokens=1*delims=:" %%a in ('findstr /I /S "webview" *.html') DO (
SET "line=%%b"
SET "line=!line:*webview=!"
FOR /F "delims=<>" %%b in ("!line!") DO ECHO %%a:%%b
)) > WebviewScanResults.txt
My working batch file scans a long list of remote servers, copies anything there to a local server, checks the log file for a keyword, and if the keyword is found sends an email. I noticed it is always sending emails, even with a blank log file.
I discovered both FOR loops are using the %1 variable for their output - as seen in ECHO %1 and each line of the called :servermove. For lack of a better explanation it is not resetting %1 to null between loops.
I reviewed almost a dozen SO posts and am somewhat confident using SETLOCAL ENABLEDELAYEDEXPANSION would resolve this. That is where my understanding ends and I am unsuccessful thus far.
Here is the relevant code:
SET DATE=%date:~4,2%-%date:~7,2%-%date:~10,4%
SET HH=%time:~0,2%
SET MN=%time:~3,2%
SET TSTAMP=Time Run is %HH%%MN%
SET DATETIME=%DATE% at %HH%%MN%
SET LOGFILE="\\nt980a3\CreditFileImagesTransmission\LogFiles\%DATETIME%-File Move Log.txt"
SET MailDst=
SET MailSrc=
SET MailSrcName=Center to LDSD File Mover
SET OKMailSub=A Branch Has Sent You Some Files
ECHO %DATETIME% > %LOGFILE%
ECHO. >> %LOGFILE%
FOR /F "tokens=1" %%A IN (%~dp0SourceServers.txt) DO CALL :ServerMove %%A
:cleanuplogs
PUSHD "\\nt980a3\CreditFileImagesTransmission\LogFiles" &&(
FORFILES /S /M *.txt /D -45 /C "CMD /C DEL /Q #path"
) & POPD
:mailtest
FOR /F "tokens=*" %%A IN (%LOGFILE%) DO CALL :searchlog "%%A"
:searchlog
ECHO %1 | find "\\nt">NUL
IF NOT ERRORLEVEL 1 GOTO successmail
GOTO exit
:successmail
IF EXIST %temp%\to.txt DEL %temp%\to.txt
FOR %%a IN (%MailDst%) DO ECHO %%a>>%temp%\to.txt
"%~dp0sendmail.exe" /TO=%temp%\to.txt /FROM=%MailSrcName% ^<%MailSrc%^> /REF=%OKMailSub% /MESSAGE=%LOGFILE% /HOST=
:exit
EXIT
:ServerMove
DIR /S /B \\%1\CreditFileImagesTransmission\*.* >> %LOGFILE%
XCOPY /E /C /I /Y "\\%1\CreditFileImagesTransmission\*.*" "\\nt980a3\CreditFileImagesTransmission\%DATE%\%HH%%MN%\"
FOR /D %%P IN ("\\%1\CreditFileImagesTransmission\*.*") DO RMDIR "%%P" /Q /S
DEL /Q /S "\\%1\CreditFileImagesTransmission\*.*"
I tried changing :mailtest to use %%B in both instances but that also fails. Placing SETLOCAL ENABLEDELAYEDEXPANSION and its counterpart ENDLOCAL before one or the other loop and changing the %%A to !A! does not work either.
Would someone kindly point out the error in my ways and offer suggestions or resources that will help me resolve this?
%1 is the first parameter provided to the procedure - either from the command-line (in the main procedure) or the parameter following the procedure name in call :procedurename parameter1.
In your case, %1 to :servermove is an entry from SourceServers.txt and %1 to :searchlog is each line from %LOGFILE%.
Since you've censored your batch, what you've posted makes little sense. For instance, the :searchlogs routine will take the first line from %LOGFILE% and go to successmail or cleanlogs depending on whether that first line contains the target string \\nt. What it does from there, we can't tell.
We're faced with an XY problem - trying to fix a solution, not a problem.
First problem: Don't use date as a user-variable. It's a "magic variable" which contains the date but it's overridden by a specific set statement.
Having run :servermove for each entry in SourceServers.txt, you are
- accumulating a directory list from \CreditFileImagesTransmission\*.* on that server.
- copying those files to server nt980a3 with a date/timestamp but not including the source-servername so any duplicate name anywhere will overwrite an earlier version. I suggest you include %1 into your destination-name.
- deleting subdirectories
- deleting files.
I'd suggest you simply remove the directory \\%1\CreditFileImagesTransmission\, then re-create it.
I'd also suggest that you add an extra line
goto :eof
after the del /q /s... line. This will cause execution to be transferred to the end-of-file (the colon in :eof is required) and may seem superfluous, but it ensures that the routine has a defined endpoint - if you add a further routine, there is no way the :servermove routine will continue into your new code.
After each server has been processed, you proceed to the :cleanuplogs routine, which I presume deletes logs older than 45 days.
Your next statement is a real problem. What it will do is grab the very first line of the logfile (which contains "%DATE% at %HH%%MN%" with the date resolved as you've set at the start and it then processes this line in :searchlog; there is no \\nt in this line, so errorlevel is set to 1, and the batch proceeds to :EXIT (not a good label in my view, since it's a keyword); executes an exitand should terminate the batch.
This appears not to be what it is actually doing, and I'm at a loss to explain why.
I'd suggest changing
:mailtest
FOR /F "tokens=*" %%A IN (%LOGFILE%) DO CALL :searchlog "%%A"
:searchlog
ECHO %1 | find "\\nt">NUL
IF NOT ERRORLEVEL 1 GOTO successmail
GOTO exit
to
:mailtest
find "\\nt" %LOGFILE%>NUL
IF NOT ERRORLEVEL 1 GOTO successmail
:failmail
echo "\\nt" was found in the log
pause
GOTO exit
but I can't test that...
:mailtest
FOR /F "tokens=*" %%A IN (%LOGFILE%) DO CALL :searchlog "%%A"
You are missing a GOTO :EOF or similar goto here because it will drop through to the routine below once the above is finished.
:searchlog
ECHO %1 | find "\\nt">NUL
IF NOT ERRORLEVEL 1 GOTO successmail
GOTO exit
I feel you can not carry the %1 of first for loop to others. Try to transfer that to another variable like below.
:ServerMove
set servername=%1
DIR /S /B \\%servername%\CreditFileImagesTransmission\*.* >> %LOGFILE%
XCOPY /E /C /I /Y "\\%servername%\CreditFileImagesTransmission\*.*" "\\nt980a3\CreditFileImagesTransmission\%DATE%\%HH%%MN%\"
FOR /D %%P IN ("\\%servername%\CreditFileImagesTransmission\*.*") DO RMDIR "%%P" /Q /S
DEL /Q /S "\\%servername%\CreditFileImagesTransmission\*.*"
Cheers, G