cmd script that fails when text is found - shell

In the windows shell:
echo "foo bar" | find "foo"
succeeds (i.e. errorlevel = 0). However, I want a script that fails (i.e. errorlevel <> 0) when it finds a particular word in some input text. Any ideas?

A lttle trickery can emulate what you desire. Only the first three lines are required, the rest are just a test.
c:> echo "foo bar" | find "foo"
c:> if x%errorlevel%==x0 echo 1 | find "2"
c:> if not x%errorlevel%==x0 echo 1 | find "1" >nul 2>nul
c:> echo %errorlevel%
1

Related

How do I obtain regex matches of piped command using shell script?

First of all I'm trying to obtain a certain property from a KML file. For now, I tried
ogrinfo C:/test.kml -so -al | findstr "Extent"
which was recommended to me and outputs
Extent: (-100.054053, 33.702234) - (-94.647180, 37.125712)
I would require this in the form
-100.054053,-94.647180,33.702234,37.125712 for which I thought to use regex.
I tried the following just to see what it outputted:
ogrinfo C:/test.kml -so -al | findstr "Extent" | findstr /r /c:"-*[0-9]*\.[0-9]*"
but this still outputs
Extent: (-100.054053, 33.702234) - (-94.647180, 37.125712)
I read somewhere that Windows' FINDSTR only outputs the line where it matched and not the regex matches themselves. Is there some other way of doing it?
If I get that working I would save the matches in different variables somehow in a shell script. I'm no expert in shell scripting but I've been looking around and was thinking of doing something like this
#!/bin/bash
for /f "tokens=*" %%a in ('ogrinfo C:/test.kml -so -al ^| findstr "Extent" ^| findstr /r /c:"-*[0-9]*\.[0-9]*"') do (
echo %%a
#do something
)
done >output
but running this causes the shell to immediately disappears and can't even see the error.
Assumptions
You have a kml file with raw data.
You can extract a single line which starts with "Extent: " to get the values you want
Single line => there is only 1 line with that format in the kml file
The format of that line is:
Extent: (NUMBER1, NUMBER2) - (NUMBER3, NUMBER4)
A number can have the following characters: 0 1 2 3 4 5 6 7 8 9 . -
The output you want is:
NUMBER1,NUMBER3,NUMBER2,NUMBER4
Using Linux tools only, you can do this:
#!/bin/bash
#
datafile="data.kml"
# Ensure the data file exists
if [[ ! -f "$datafile" ]]
then
echo "ERROR: the data file does not exist."
exit 1
fi
# Extract the "Extent:" line
dataline=$(grep "Extent: " "$datafile")
# Make sure the line is of a valid format, and assign the number variables
if [[ $dataline =~ "Extent: ("([0-9.-]+)", "([0-9.-]+)") - ("([0-9.-]+)", "([0-9.-]+)")" ]] && number1="${BASH_REMATCH[1]}" && number2="${BASH_REMATCH[2]}" && number3="${BASH_REMATCH[3]}" && number4="${BASH_REMATCH[4]}"
then
echo "-----DEBUG-----"
echo "line==$dataline"
echo "1==$number1"
echo "2==$number2"
echo "3==$number3"
echo "4==$number4"
echo "-- END DEBUG --"
echo ""
echo "$number1,$number3,$number2,$number4"
else
echo "ERROR: there is no \"Extent: \" line in the data file ($datafile)"
fi
Details:
Everything is done in the if line.
=~ matches the left side with the pattern on the right side.
In the regular expression, you can define sections you want to reuse with ( ).
Ex: abcd(1)efgh(2)ijkl. The sections you can reuse are 1 and 2.
So in the if, each number is surrounded by parentheses.
When the =~ is processed, the BASH_REMATCH array is defined with each section.
The "DEBUG" echo statements can be removed or commented out.
If you have more than one "Extent: ..." in the KML file, you can loop on the lines and process each one at a time.

Are there certain MAC address vendor codes that don't work on windows or is there something else wrong with my code?

Following #Asian's question and my recent interest in powershell, I tried to replicate the script I provided to answer Asian's question, however I am not having the same success that I did with the batch script. If you do not want to view the previous question, here is my batch-file for changing your MAC Address:
#echo off
dism >nul
if %errorlevel% NEQ 0 goto Elevate
(call )
netsh interface set interface Wi-Fi disable
timeout /t 1 /nobreak >null
netsh interface set interface Wi-Fi enable
choice /c RC /m "Would you like to randomize your MAC adress or customize it?"
if %Errorlevel% EQU 2 goto custom
set loopcount=5
:loop
set /a loopcount=loopcount-1
if %loopcount% LEQ 0 (goto exitloop)
set /a "ascii = %random% * 26 / 32768 + 65"
cmd /c exit /b %ascii%
set "rl1=%rl1%%=ExitCodeAscii%"
goto loop
:exitloop
set MAC="0E%random:~0,2%%rl1:~0,2%%random:~0,2%%rl1:~3,2%%rl1:~-1%%random:~0,1%"
goto after
:custom
echo What would you like to change your MAC address to?
echo Remember to always have the second digit of your MAC address to always be a 2, 6, A, or E
echo Format: AABBCCDDEEFF
echo/
set /p MAC="Input your MAC address here (no spaces or hyphens)> "
:after
reg add "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4d36e972-e325-11ce-bfc1-08002be10318}\0011" /v NetworkAddress /d %MAC% /f >null
netsh interface set interface Wi-Fi disable
timeout /t 1 /nobreak >null
netsh interface set interface Wi-Fi enable
echo Operation Successful
echo %mac% is your new MAC address
pause
goto :eof
:Elevate
Echo Error: The requested operation requires elevation
Echo Run file again as admin
Echo Closing file in 10 seconds...
timeout /t 10 /nobreak >nul
goto :eof
I tried to replicate it in powershell, however the script is very volatile on whether it works or not:
[string]$admin = [bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups -match "S-1-5-32-544")
if ($admin -eq "False"){
echo "Error: The requested operation requires elevation`nRun file again as administrator"
pause
exit}
rv * -ErrorAction SilentlyContinue
echo "This file will temporarily disable your Wi-Fi adapter"
While (!($C1)){
$choice1 = Read-Host -Prompt "Would you like to proceed? [Y/N]"
switch ($choice1) {
"N" {echo "Ok, press any key to exit this file:"
cmd /c pause > $null; exit}
"Y" {echo "Ok, proceeding with operation"; [int]$C1 = 1; break}
}
if (!($C1)){echo "Invalid input"}
}
rv * -ErrorAction SilentlyContinue
netsh interface set interface Wi-Fi disable;
$getwifi = netsh interface show interface | findstr "Wi-Fi"
if ($getwifi.substring(0,7) -ne "disable"){echo "Unexpected error: Press any key to exit"
cmd /c pause > $null; exit}
echo "Wi-Fi has been succesfully disabled, proceeding with operation"
While (!($C1)){
$choice1 = Read-Host -Prompt "Would you like to randomize your MAC Address or customize it? [R/C]"
switch ($choice1) {
"R" {
$test = #(...) | get-random
<# $test is a random value in a list of 25000+ MAC Address vendor codes provided in
https://gitlab.com/wireshark/wireshark/raw/master/manuf with the colons removed and columns
besides the MAC column removed as well #>
$test2 = [string](get-random -minimum 10 -maximum 99)+(-join ((65..90) | Get-Random -Count 2 | % {[char]$_}));
$test3 = [string](get-random -minimum 1 -maximum 9)+(-join ((65..90) | Get-Random -Count 1 | % {[char]$_}));
$MAC = $test + $test2 + $test3;
$C1 = 1}
"C" {$C1 = 2}
}
if (!($C1)){echo "Invalid input"}
}
if(!($MAC)){
do{
echo "What would you like to change your MAC address to?`nRemember to always have the second digit of your MAC address to always be a number`nFormat: 11BBCCDDEEFF";
$MAC = read-host -prompt "Input your MAC address here [no spaces or hyphens]";
if ($MAC.length -eq 12){$C1 = 1};
if (!($MAC.length -eq 12)){echo "Invalid input: Follow the format"; rv MAC}
} while(!($MAC))
}
reg add "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4d36e972-e325-11ce-bfc1-08002be10318}\0011" /v NetworkAddress /d $MAC /f >$null
netsh interface set interface Wi-Fi enable
echo "Operation Successful"
echo "$MAC is your new MAC address"
pause
Again, $test is a random value in a list of 25000+ MAC Address vendor codes provided in https://gitlab.com/wireshark/wireshark/raw/master/manuf with the colons removed and columns besides the MAC column removed as well. I believe the issue is in the $test variable where the computer will just reject a certain MAC address. If this is not the issue, can someone explain to me what is the issue, and if there are certain codes that will always work in changing the MAC address successfully, please provide me them. Thank you in advance.
Some addresses that work include:
AABBCCDDEEFF
001122334455
00AA11BB22CC
Other variants of 00----------
6E80F12CC8C9
I will write more sample addresses down when I test them.
Try macaddr=$(echo $FQDN|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/') &> /dev/null && echo macaddr. This will generate a random MAC address and echo it to you. This only works in Ubuntu/Bash though.
You can also do (1..12 | %{ '{0:X}' -f (Get-Random -Max 16) }) -join '' in PowerShell.

Passing parameters to powershell script

I'm trying to run a powershell script from the run dialog (will be used as a scheduled task), and I'm having troubles passing parameters.
The script will take in two parameters, named title and msg.
The script is located in: D:\Tasks Scripts\Powershell\script.ps1
This is what I'm trying to do:
powershell.exe -noexit 'D:\Tasks Scripts\Powershell\script.ps1' -title 'Hello world' -msg 'This is a test message'
But it fails upon reading the parameters.
Running .\script.ps1 -title 'Hello world' -msg 'This is a test message' on powershell works fine.
Use -file before the path to your script:
powershell.exe -noexit -file 'D:\Tasks Scripts\Powershell\script.ps1' etc...
I usually run powershell scripts from cmd.exe because this is portable
(works out-of-the-box on others' computers, like developer folks or clients):
no need to worry about Set-ExecutionPolicy or associating the .ps1 extension.
I create the file with .cmd extension (instead of .ps1), and copy&paste a short,
constant code to the first line(s) that invokes powershell.exe and passes the rest
of the file to it.
Passing arguments is tricky. I have multiple variants of the constant code
because the general case is painful.
when not passing arguments, the .cmd file looks like this:
#powershell -c ".(iex('{#'+(gc '%~f0' -raw)+'}'))" & goto :eof
# ...arbitrary PS code here...
write-host hello, world!
This uses the -Command argument of powershell.exe. Powershell reads the .cmd
file as text, puts it in a ScriptBlock with the first line commented out,
and evaluates it with the '.' command.
Further command line arguments
can be added to the Powershell invocation as required (e.g. -ExecutionPolicy Unrestricted,
-Sta etc.)
when passing arguments that do not contain spaces or are 'single-quoted'
(which is non-standard in cmd.exe), the one-liner is this:
#powershell -c ".(iex('{#'+(gc($argv0='%~f0') -raw)+'}'))" %* & goto :eof
write-host this is $argv0 arguments: "[$($args -join '] [')]"
param() declarations could be used as well, $args is not obligatory.
$argv0 is used to compensate for the missing $MyInvocation.PS* info.
Examples:
G:\>lala.cmd
this is G:\lala.cmd arguments: []
G:\>lala.cmd "1 2" "3 4"
this is G:\lala.cmd arguments: [1] [2] [3] [4]
G:\>lala.cmd '1 2' '3 4'
this is G:\lala.cmd arguments: [1 2] [3 4]
when passing arguments that are "double-quoted" but do not contain
the & and ' characters, I use a two-liner to replace all " with '
#echo off& set A= %*& set B=#powershell -c "$argv0='%~f0';.(iex('{'
%B%+(gc $argv0|select -skip 2|out-string)+'}'))" %A:"='%&goto :eof
write-host this is $argv0 arguments: "[$($args -join '] [')]"
(Note that the space is important in the A= %* assignment for the
argument-less case.)
Results:
G:\>lala.cmd
this is G:\lala.cmd arguments: []
G:\>lala.cmd "1 2" "3 4"
this is G:\lala.cmd arguments: [1 2] [3 4]
G:\>lala.cmd '1 2' '3 4'
this is G:\lala.cmd arguments: [1 2] [3 4]
the most general case passes the arguments via environment variables
thus Powershell's param() declaration does not work. In this case the
arguments are expected to be "double-quoted" and may contain ' or &
(except for the path of the .cmd file itself):
;#echo off & setlocal & set A=1& set ARGV0=%~f0
;:loop
;set /A A+=1& set ARG%A%=%1& shift& if defined ARG%A% goto :loop
;powershell -c ".(iex('{',(gc '%ARGV0%'|?{$_ -notlike ';*'}),'}'|out-string))"
;endlocal & goto :eof
for ($i,$arg=1,#(); test-path -li "env:ARG$i"; $i+=1) { $arg += iex("(`${env:ARG$i}).Trim('`"')") }
write-host this is $env:argv0 arguments: "[$($arg -join '] [')]"
write-host arg[5] is ($arg[5]|%{if($_){$_}else{'$null'}})
(Note that in the first line A=1& must not contain space.)
Result:
G:\>lala.cmd "a b" "c d" "e&f" 'g' "h^j"
this is G:\lala.cmd arguments: [a b] [c d] [e&f] ['g'] [h^j]
arg[5] is $null

Computername variable in cmd

In CMD the following variable will give you the name of the computer: %COMPUTERNAME%
I need a variable that takes a part of the computername.
I need a if statement that checks if the computername contains "KM" at the start and 00 at the end. It should not look at the number between KM and -00
KM100-00
KM200-00
This works here:
echo %computername%| findstr "^KM.*00$" >nul && echo found the right format
You can do this with substring commands, as per the following transcript:
pax> set xyzzy=KM100-00 KM200-00
pax> echo %xyzzy%
KM100-00 KM200-00
pax> echo %xyzzy:~0,2%
KM
pax> echo %xyzzy:~-2,2%
00
pax> if %xyzzy:~0,2%==KM if %xyzzy:~-2,2%==00 echo yes
yes
That final (chained) if statement is the one you're looking for to see if your variable starts with KM and ends with 00.
The expression %X:~Y,Z% will give you the Z characters starting at position Y (zero-based) of the variable X. You can provide a negative value of Y to make it relative to the end of the string.
echo %computername%| findstr /I /b "KM" | findstr /i /e "00" && echo computer name is like KM-XX-00
You can try also with hostname instead of echo %computername%
I recommend you to read this page, which is about substring usage in command prompt.
And why dont you try this;
set str=KM2000-00
echo.%str%
set pre=%str:~0,2%
echo.%pre%
set pst=%str:~-2%
echo.%pst%
IF %pre% == KM( IF %pst% == 00( echo.true ) )
pause

Check if process returns 0 with batch file

I want to start a process with a batch file and if it returns nonzero, do something else. I need the correct syntax for that.
Something like this:
::x.bat
#set RetCode=My.exe
#if %retcode% is nonzero
handleError.exe
As a bonus, you may consider answering the following questions, please :)
How to write a compound statement with if?
If the application My.exe fails to start because some DLL is missing will my if work? If not, how can I detect that My.exe failed to start?
ERRORLEVEL will contain the return code of the last command. Sadly you can only check >= for it.
Note specifically this line in the MSDN documentation for the If statement:
errorlevel Number
Specifies a true
condition only if the previous program
run by Cmd.exe returned an exit code
equal to or greater than Number.
So to check for 0 you need to think outside the box:
IF ERRORLEVEL 1 GOTO errorHandling
REM no error here, errolevel == 0
:errorHandling
Or if you want to code error handling first:
IF NOT ERRORLEVEL 1 GOTO no_error
REM errorhandling, errorlevel >= 1
:no_error
Further information about BAT programming: http://www.ericphelps.com/batch/
Or more specific for Windows cmd: MSDN using batch files
How to write a compound statement with
if?
You can write a compound statement in an if block using parenthesis. The first parenthesis must come on the line with the if and the second on a line by itself.
if %ERRORLEVEL% == 0 (
echo ErrorLevel is zero
echo A second statement
) else if %ERRORLEVEL% == 1 (
echo ErrorLevel is one
echo A second statement
) else (
echo ErrorLevel is > 1
echo A second statement
)
This is not exactly the answer to the question, but I end up here every time I want to find out how to get my batch file to exit with and error code when a process returns an nonzero code.
So here is the answer to that:
if %ERRORLEVEL% NEQ 0 exit %ERRORLEVEL%
The project I'm working on, we do something like this. We use the errorlevel keyword so it kind of looks like:
call myExe.exe
if errorlevel 1 (
goto build_fail
)
That seems to work for us. Note that you can put in multiple commands in the parens like an echo or whatever. Also note that build_fail is defined as:
:build_fail
echo ********** BUILD FAILURE **********
exit /b 1
To check whether a process/command returned 0 or not, use the operators && == 0 or not == 0 ||:
Just add operator to your script:
execute_command && (
echo\Return 0, with no execution error
) || (
echo\Return non 0, something went wrong
)
command && echo\Return 0 || echo\Return non 0
For details on Operators' behavior see: Conditional Execution || && ...
You can use below command to check if it returns 0 or 1 :
In below example, I am checking for the string in the one particular file which will give you 1 if that particular word "Error" is not present in the file and if present then 0
find /i "| ERROR1 |" C:\myfile.txt
echo %errorlevel%
if %errorlevel% equ 1 goto notfound
goto found
:notfound
exit 1
:found
echo we found the text.

Resources