Powershell command from batch file not working as expected - batch-file

I am running a batch script, but I get an error stating that
-command is not recognized as internal or external command, operable program or batch file
I am not able to understand why. I also looked at my environmental variable path. That looks to be fine.
Below is the Script
#echo off
set PWSH = %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
%PWSH% -command $input ^| %1\post-commit-jenkins.ps1 %1 %2
pause
if errorlevel 1 exit %errorlevel%
Please provide your opinion and possible solution .

#echo off
set "PWSH=%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe"
%PWSH% -command $input ^| %1\post-commit-jenkins.ps1 %1 %2
pause
if errorlevel 1 exit %errorlevel%
Remove the space when you are setting a otherwise because it will be part of the variable name (not I have no idea what are the %1 and %2 arguments so I don't know what to expect further )

Related

Need a little tip on batch files

I'm very new to coding and iI'm having a problem that is probably trivial, but is making me pull out my hair.
I'm using a batch script to automate mounting a VHD, executing a file inside and then pause until the user presses any key, which makes the VHD get unmounted and the script exits.
This is the main batch file:
#echo off
set fileVHD=Gord
CD /D "%~dp0"
powershell -command "Start-Process mount.cmd '%~dp0%fileVHD%.vhd' -Verb runas"
timeout /t 1
for /f %%D in ('wmic volume get DriveLetter^, Label ^| find "%fileVHD%"') do set usb=%%D
CD /D %usb%
index.html
echo "!!!!!!!!!!!!!!!!!!!!Press any key to fully close this program.!!!!!!!!!!!!!!!!!!!!!!!!!"
pause
CD /D "%~dp0"
powershell -command "Start-Process unmount.cmd '%~dp0%fileVHD%.vhd' -Verb runas"
exit
This is the mount script (Not made by me):
#echo off
setlocal enabledelayedexpansion
if "%~1"=="" (
echo Usage: %~nx0 [vhd] [letter]
exit /b 1
)
set "vhdPath=%~dpnx1"
set "driveLetter=%2"
if "!driveLetter!"=="" (
echo Mounting "!vhdPath!"
) else (
echo Mounting "!vhdPath!" to "!driveLetter!":
)
REM
REM create diskpart script
REM
set "diskPartScript=%~nx0.diskpart"
echo select vdisk file="!vhdPath!">"!diskPartScript!"
echo attach vdisk>>"!diskPartScript!"
REM assign the drive letter if requested
if not "!driveLetter!"=="" (
echo select partition 1 >>"!diskPartScript!"
echo assign letter="!driveLetter!">>"!diskPartScript!"
)
REM Show script
echo.
echo Running diskpart script:
type "!diskPartScript!"
REM
REM diskpart
REM
diskpart /s "!diskPartScript!"
del /q "!diskPartScript!"
echo Done!
endlocal
When all the files are located in a system path that contains no spaces, everything works fine. But it breaks where there are spaces.
That means that somewhere in the code a path is badly defined by the lack of quotes, probably in the mount script. The trouble is that i don't fully grasp the mount script when it starts using all the "%~...." variable path names.
I had to mix in some powershell commands because for some reason the script wouldn't work unless executed as Administrator.
If someone could give some insight to a newbie, it would be greatly appreciated.
You need end quotes around your parameters when you change directory, i.e.
CD /D "%~dp0"
You can also see all of the %~ options by running 'help for' in a console window. In those scripts it's getting the path or filename from a variable.
Discovered the root of my problem.
The path from script 1 was not being passed faithfully to script 2, even using using quotes or multiquotes.
Thanks for all the input guys!

My Batch file loop stops because of open file

I am trying to build a batch file that pings multiple devices on our network and continues logging ping results data in an output file in an infinite loop. However, the infinite loop gets hung up because the output file is open. Once I manually close the output file, the loop begins another iteration and logs more data. How do I automate this step? I've gone through so many options with taskkill, but none of them will close the output file for some reason. Other Notepad files close, but not the output file running on notepad.
Thanks for you help! Code is below:
#echo off
if exist C:\Users\Tsgadmin\Desktop\data\computers.txt goto Label1
echo.
echo Cannot find C:\Users\Tsgadmin\Desktop\data\computers.txt
echo.
Pause
goto :eof
:Label1
:loop
echo ================================================= >> C:\Users\Tsgadmin\Desktop\ping_firepanels_output.txt
echo PingTest executed on %date% at %time% >> C:\Users\Tsgadmin\Desktop\ping_firepanels_output.txt
for /f %%i in (C:\Users\Tsgadmin\Desktop\data\computers.txt) do call :Sub %%i
notepad C:\Users\Tsgadmin\Desktop\ping_firepanels_output.txt
choice /n/t:c,<10>/c:cc
echo ================================================= >> C:\Users\Tsgadmin\Desktop\ping_firepanels_output.txt
echo. >> C:\Users\Tsgadmin\Desktop\ping_firepanels_output.txt
start notepad.exe
for /f "tokens=2" %%x in ('tasklist ^| findstr notepad.exe') do set PIDTOKILL=%%x
taskkill /F /IM notepad.exe > nul
goto loop
goto :eof
:Sub
echo Testing %1
ping -n 1 %1 >> C:\Users\Tsgadmin\Desktop\ping_firepanels_output.txt | find /i "(0% loss)"
echo %1 Testing done
echo %1 Testing done >> C:\Users\Tsgadmin\Desktop\ping_firepanels_output.txt
Here is your batch code rewritten for this task:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "LogFile=%USERPROFILE%\Desktop\ping_firepanels_output.txt"
set "ListFile=%USERPROFILE%\Desktop\data\computers.txt"
if exist "%ListFile%" goto PrepareForPings
echo/
echo Cannot find file: "%ListFile%"
echo/
endlocal
pause
goto :EOF
rem Delete existing log file before running the echo requests.
rem Get just file name with file extension without path from
rem log file name with path specified at top of the batch file.
:PrepareForPings
del "%LogFile%" 2>nul
for /F %%I in ("%LogFile%") do set "LogFileName=%%~nxI"
rem Always terminate (not kill) running Notepad instance with having
rem the log file opened for viewing before running first/next test run.
:PingLoop
%SystemRoot%\System32\taskkill.exe /FI "WINDOWTITLE eq %LogFileName% - Notepad" >nul 2>nul
echo =================================================>>"%LogFile%"
>>"%LogFile%" echo PingTest executed on %DATE% at %TIME%
echo/>>"%LogFile%"
for /F "usebackq" %%I in ("%ListFile%") do (
echo Testing %%I ...
%SystemRoot%\System32\ping.exe -n 1 -w 500 %%I>nul
if errorlevel 1 (
echo %%I is not available in network (no reply^).>>"%LogFile%"
) else echo %%I is available.>>"%LogFile%"
echo %%I testing done.
)
echo =================================================>>"%LogFile%"
echo/>>"%LogFile%"
start "" %SystemRoot%\notepad.exe "%LogFile%"
echo/
%SystemRoot%\System32\choice.exe /C NY /N /T 10 /D Y /M "Run again (Y/n): "
echo/
if errorlevel 2 goto PingLoop
endlocal
In general it is advisable to define environment variables with names of files specified multiple times in the batch file at top to make it easier to modify them in future.
On referencing those file environment variables it is strongly recommended to enclose the name in double quotes to get a working batch file also when file name with path contains a space character or one of these characters: &()[]{}^=;!'+,`~
If a file name enclosed in double quotes is specified as text file of which lines to read in a for /F command line, it is necessary to use option usebackq to get interpreted the file name enclosed in double quotes as file name and not as string to process by FOR.
The DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/ explains why it is better to use echo/ instead of echo. to output an empty line.
The TASKKILL command used to send Notepad the terminate signal for a graceful termination should be send only to the Notepad instance having the log file opened and not any other perhaps running Notepad instance.
An ECHO line redirected to a file with > or >> with a space left to redirection operator results in having this space also written as trailing space into the file. For that reason there should be no space between text to write into the file and redirection operator. A space right to > or >> would be no problem as not written into the file.
When a variable text is output on an ECHO line redirected into a file which could end with 1, 2, 3, ... 9, it is necessary to specify the redirection from STDOUT into the file with >> at beginning of the line as otherwise 1>>, 2>>, ... would be interpreted different as expected on execution of the ECHO command line. Read also the Microsoft article about Using Command Redirection Operators.
There is no subroutine necessary for this task. A command block starting with opening parenthesis ( and matching ) can be used here too. That makes the execution of the loop a bit faster, not really noticeable faster, but nevertheless faster.
There is a text written with echo into the log file containing also a closing parenthesis ) not within a double quoted string. This ) would be interpreted as matching ) for opening ( of true branch of IF condition. It is necessary to escape ) with caret character ^ to get ) interpreted as literal character by Windows command interpreter.
PING exits with exit code 1 if the echo request was not replied. Otherwise on successful reply the exit code is 0. It is better to evaluate the exit code via errorlevel than filtering the language dependent output.
New instance of Notepad with the log file to view is started by this batch file using command start to run Notepad in a separate process running parallel to command process executing the batch file. Otherwise the execution of the batch file would be halted as long as the started Notepad instance is not closed by the user. That different behavior can be easily seen on removing start "" at beginning of the command line starting Notepad.
The command CHOICE gives the user of the batch file the possibility to exit the loop by pressing key N (case-insensitive) within 10 seconds. Otherwise the user prompt is automatically answered with choice Y and the loop is executed once again by first terminating running Notepad.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
choice /?
del /?
echo /?
endlocal /?
for /?
goto /?
if /?
pause /?
ping /?
set /?
setlocal /?
start /?
taskkill /?
See also Windows Environment Variables for details on environment variables USERPROFILE and SystemRoot as used in this batch file.

Batch %1 get path with whitespace

I have set up a batch file to be default to open .txt files. In an earlier question I found out that %1 gives me the path of the file which was actually calling the batch file. The Problem is: if the file name contains white space, it gets interpreted as multiple parameters.
Example:
opening file "C:\Users\Desktop\space true.txt"
%1 gives:"C:\Users\Desktop\space" and then %2 gives: "true.txt"
How could I get just the full file path with the name and white space without trying to do a loop to attempt to get the full path by combining %1%2%3%4...
UPDATE-----------------------
Sorry there was a miss communication. The code below is working. The trick was to put "%*" instead of "%1"
here the code:
#echo on
set var= "%*"
c:
cd "C:\Users\MyText Editor"
start javaw -jar "MyTextEditor.jar"%var%
pause
I do the whole changing the path, because the file which I double click and the the the batch file are in different directories. I had to change it to this.
UPDATE 2 --------------------------
The solution which worked best for me was from this fine gentlemen dbenham.
#echo off
pushd "C:\Users\MyText Editor"
start javaw -jar "MyTextEditor.jar" %*
The only complain I have is, that there is a case, where %* does not return the path with quotes. So I am searching for a final solution. Something like this "%~*" But this doesn't work.
Thanks in advance
The following is not quite correct - I thought the file associations would put quotes around the file name like drag and drop does. But I was mistaken
This line is the source of your problem:
set var= "%*"
When files are dragged onto your batch script, or if a text file is double clicked, any file name(s) containing space will automatically be enclosed within quotes.
When you add your own additional quotes, it defeats the purpose of the quotes - the space is no longer quoted.
For example, a string like "name with space.txt" is treated as a single arg, but with added quotes, ""name with space.txt"" becomes three arguments.
There is no need for your var variable. You can use %* directly in your START command.
#echo on
pushd "C:\Users\MyText Editor"
start javaw -jar "MyTextEditor.jar" %*
pause
I'm not sure the above works properly if multiple files are passed. I suspect you may want the following:
#echo on
pushd "C:\Users\MyText Editor"
for %%F in (%*) do start javaw -jar "MyTextEditor.jar" %%F
pause
There is one potential problem. Windows has a bug in that file names containing & are not automatically quoted as they should. See "Droplet" batch script - filenames containing ampersands for more info.
EDIT - The following should work
OK, I did some tests and I believe your best bet is to modify the command associated with .txt files.
I tested association changes via the command line. This must be done via an elevated command prompt with admin rights. On my machine I go to the Start menu, click on "All Programs", click on "Accessories" folder, right click "Command Prompt", and select "Run as administrator", then click "Yes" to allow the program to make changes to the system.
The following command will show which file type needs to be modified
assoc .txt
On my machine it reports .txt=txtfile, so txtfile is what must be modified using FTYPE.
I believe the following should work for you:
ftype txtfile="C:\pathToYourScrpt\yourScript.bat" "%1"
Obviously you would need to fix the path to your batch script :-)
Once you have made the change, the filename will automatically be quoted every time your script is invoked via a file association.
Your batch script can then look like the following, and it should work no matter how it is invoked (excepting drag and drop with file name containing & but no space):
#echo off
pushd "C:\Users\MyText Editor"
for %%F in (%*) do start javaw -jar "MyTextEditor.jar" %%F
It seems to me you should be able to eliminate the batch script and configure FTYPE TXTFILE to open your java editor directly. I should think something like the following:
ftype txtfile="c:\pathToJava\javaw.exe" -jar "C:\Users\MyText Editor\MyTextEditor.jar" "%1"
When calling your batch file, you must enclose your parameter in quotes if there is spaces in it.
E.g.: Batch.cmd "C:\Users\Desktop\space true.txt"
Eric
%*
Here's a list of characters.
& seperates commands on a line.
&& executes this command only if previous command's errorlevel is 0.
|| (not used above) executes this command only if previous command's errorlevel is NOT 0
> output to a file
>> append output to a file
< input from a file
| output of one command into the input of another command
^ escapes any of the above, including itself, if needed to be passed to a program
" parameters with spaces must be enclosed in quotes
+ used with copy to concatinate files. E.G. copy file1+file2 newfile
, used with copy to indicate missing parameters. This updates the files modified date. E.G. copy /b file1,,
%variablename% a inbuilt or user set environmental variable
!variablename! a user set environmental variable expanded at execution time, turned with SelLocal EnableDelayedExpansion command
%<number> (%1) the nth command line parameter passed to a batch file. %0 is the batchfile's name.
%* (%*) the entire command line.
%<a letter> or %%<a letter> (%A or %%A) the variable in a for loop. Single % sign at command prompt and double % sign in a batch file.
Your problem is really that the syntax of your set command is wrong. In a batch
file, a set command looks like this:
set "var=%1"
That will give you your variable exactly as received. If the user quoted it,
then the variable's value will have quotes around it. To remove the quotes,
you'd put a ~ in front of the number:
set "var=%~1"
Notice how the quotes go around the entire assignment, and not just around the
value you are assigning. It is not set var="%1".
If you use set var= "%*", you haven't really fixed the fundamental problem
that your syntax is wrong. Plus, often you really do want %1 and not the
entire command line.
Here is an example script to test various quoting behaviors:
#echo off
set var="%*"
echo 1. var="%%*" --^> [%var%] (wrong)
set "var=%*"
echo 2. "var=%%*" --^> [%var%]
set "var=%1"
echo 3. "var=%%1" --^> [%var%]
set "var=%~1"
echo 4. "var=%%~1" --^> [%var%]
set "var=%~2"
echo 5. "var=%%~2" --^> [%var%]
set "var=%~3"
echo 6. "var=%%~3" --^> [%var%]
And here is the output of that script. Note how arg1, arg2, and arg3 are all
quoted:
C:\batch> all_args.cmd "arg 1" "this is arg 2" "arg 3"
1. var="%*" --> [""arg 1" "this is arg 2" "arg 3""] (wrong)
2. "var=%*" --> ["arg 1" "this is arg 2" "arg 3"]
3. "var=%1" --> ["arg 1"]
4. "var=%~1" --> [arg 1]
5. "var=%~2" --> [this is arg 2]
6. "var=%~3" --> [arg 3]
You can see that numbers 4, 5, and 6 correctly pulled out their quoted arguments
and saved the value into var. You typically want to save the argument without quotes, and then quote it when you use it in your script. In other words, your script should look like this:
#echo on
set "var=%~1"
c:
cd "C:\Users\MyText Editor"
start javaw -jar "MyTextEditor.jar" "%var%"
pause
#echo on
set var= "%*"
c:
cd "C:\Users\MyText Editor"
start javaw -jar "MyTextEditor.jar"%var%
pause
Becomes removing redundant commands
start "" javaw -jar "C:\Users\MyText Editor\MyTextEditor.jar" "%*"
pause
Echo is already on unless turned off by you.
We don't put things into variables for no reason, and it's already in %*. It just makes convoluted code and removes meaning from the name of the variable.
When programming (unlike typing) we don't change paths (and cd /d C:\Users\MyText Editor does drive and folder anyway).
We specify full path on the command line. This makes your meaning quite clear.
The main problem was there was no space between .jar and %var% and start command the first quotes on the line are assumed to the CMD's window title. I would code the path to javaw and not use start. Start is asking the Windows' graphical shell to start the file, not CMD.
Here's a batch file that starts vbs files. I don't specify path to cscript as it's a Windows' command.
It's complexity is to make use fairly idiot proof and easy for others.
#echo off
Rem Make sure filter.vbs exists
set filter=
set filterpath=
Call :FindFilter filter.vbs
Rem Add filter.bat to the path if not in there, setx fails if it's already there
setx path %~dp0;%path% 1>nul 2>nul
Rem Test for some command line parameters
If not "%1"=="" goto main
echo.
echo -------------------------------------------------------------------------------
echo.
echo Filter.bat
echo ==========
echo.
echo The Filter program is a vbs file for searching, replacing, extracting, and
echo trimming console output and text files.
echo.
echo Filter.bat makes Filter.vbs easily usable from the command line. It
echo controls unicode/ansi support and debugging.
echo.
echo Type Filter Help or Filter HTMLHelp for more information.
echo.
cscript //nologo "%filter%" menu
Goto :EOF
:Main
echo %date% %time% %~n0 %* >>"%~dp0\FilterHistory.txt"
rem echo Batch file ran
rem echo %*
Rem /ud Unicode and Debug
If %1==/ud FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //u //x %%j&Goto :EOF
Rem /u Unicode
If %1==/u FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //u %%j&Goto :EOF
Rem /d Ansi Debug
If %1==/d FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //x %%j&Goto :EOF
Rem -ud Unicode and Debug
If %1==-ud FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //u //x %%j&Goto :EOF
Rem /u Unicode
If %1==-u FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //u %%j&Goto :EOF
Rem -d Ansi Debug
If %1==-d FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //x %%j&Goto :EOF
Rem ANSI
cscript "%filter%
" //nologo %*&Goto :EOF
Goto :EOF
:FindFilter
If Exist "%~dpn0.vbs" set filter=%~dpn0.vbs&set filterpath=%~dp0&goto :EOF
echo find filter 1
If Not "%~dpnx$PATH:1" == "" set filter=%~dpnx1&set filterpath=%~dp1&goto :EOF
echo find filter 2
If Exist "%temp%\filter.vbs" set filter=%temp%\filter.vbs&set filterpath=%temp%&goto :EOF
copy "%~dpnx0" "%~dpn0.bak"
if not errorlevel 1 (
echo creating "%~dpn0.vbs"
goto :EOF
)
copy "%~dpnx0" "%temp%\filter.bak"
echo Error %errorlevel%
if not errorlevel 1 (
echo creating "%temp%\filter.bak"
Goto :EOF
)
Goto :EOF

Echo **Echo 3> args.txt** >X.bat, how do i fix this code?

Echo Echo 3> args.txt >X.bat
I'm trying to place this line of code ( Echo 3> args.txt ) into a batch file named X, but what ends up happening
: X Batch File
echo
:Args text file
There is nothing inside
It place echo (Just echo) into x.batch and creates a blank args text file.
How do I fix the code so it will place Echo 3> args.txt into x batch?
Use
Echo Echo 3^> args.txt>X.bat
As > has a special meaning (redirect), it must be escaped with ^ to be interpreted as literal character.
One more hint:
Insert no space before >X.bat or this space would be appended to end of line in the created batch file.
cmd.exe executes this line as
Echo Echo 3> args.txt 1>X.bat
See also Microsoft's TechNet article Using command redirection operators.
EDIT:
If environment variable password could contain also special characters as listed at end of help output in a command prompt window after running cmd.exe /?, it would be even better to use:
#echo off
setlocal EnableDelayedExpansion
set "password=<hello>"
echo echo var1=!password!^>args.txt>>Enter_PassCode.bat
endlocal
The delayed environment variable expansion is explained in help of command set output by running set /? or help set. Delayed expansion is used here to avoid a syntax error on running this batch file because of < and > in string of environment variable password.
This example would append to Enter_PassCode.bat the line
echo var1=<hello>>args.txt
Executing this batch file would of course result again in an error on execution for <hello> as password.
A solution for making Enter_PassCode.bat executable without any error would be:
#echo off
setlocal EnableDelayedExpansion
set "password=<hello>"
echo #echo off>Enter_PassCode.bat
echo setlocal EnableDelayedExpansion>>Enter_PassCode.bat
echo set "password=!password!">>Enter_PassCode.bat
endlocal
echo echo var1=!password!^>args.txt>>Enter_PassCode.bat
echo endlocal>>Enter_PassCode.bat
This batch code produces Enter_PassCode.bat with content
#echo off
setlocal EnableDelayedExpansion
set "password=<hello>"
echo var1=!password!>args.txt
endlocal

Command for getting the file size

Could anybody please tell me a shell command for Windows 7 which would take a file path as argument and return the size of that file - Something like:
fileSize.cmd file.txt
...which will give me 1KB.
One question in SO noted the command echo %~z1, but for this, I have to write a separate batch file and use this command in it. I was thinking of modifying my existing bat file and incorporate this command somehow. My batch file looks like this:
p4 diff //sources/j2cs/output.txt >> diff_out.txt
I have to add above command in the existing bat file to find the file size of diff_out.txt.
You don't need an extra batch file, you could move your filename into %1 with a call to a function or you can use a FOR loop.
call :getFilesize diff_out.txt
echo %fileSize%
exit /b
:getFilesize
set filesize=%~z1
exit /b
Or
for %%A in (diff_out.txt) do set fileSize=%%~zA
another variant:
#echo off
set file=c:\bookmarks.html
%1 %0 :: %file%
set len=%~z2
echo %len%
pause
or with wmic:
D:\>set wql="drive='g:' and filename='function2' and extension='txt'"
D:\>wmic path cim_datafile where %wql% get name,filesize
FileSize Name
621 g:\function2.txt
D:\>
or:
set file=G:\function2.txt
echo set len=%%~z1 >_tmp.bat
call _tmp.bat %file% && del _tmp.bat
echo %len%

Resources