Check with batch if the process is answering or not - batch-file

:loop
>nul timeout /t 600 /nobreak
powershell -ExecutionPolicy Unrestricted -c "Get-Process -Name programm | Where-Object -FilterScript {$_.Responding -eq $false}"
if not errorlevel 1 goto loop
This is not working, I think the errorlevel is the problem, but I cant solve it.
I want to check if the process is answering or not. If not I want to check the process again after a timeout.
I thank you in advance for your help.

Read Errorlevel and Exit codes:
Almost all applications and utilities will set an Exit Code when
they complete/terminate. The exit codes that are set do vary, in
general a code of 0 (false) will indicate successful completion.
… When an external command is run by CMD.EXE, it will detect
the executable's Return or Exit Code and set the ERRORLEVEL to
match. In most cases the ERRORLEVEL will be the same as the Exit
code, but there are some cases where they can differ.
It's Exit Code for PowerShell as shown in the following examples:
Unsuccessful completion ( errorlevel 1 ):
==> powershell -noprofile -c "Get-Process -Name invalid_programm"
Get-Process : Cannot find a process with the name "invalid_programm". Verify the process name and call the cmdlet again.
At line:1 char:1
+ Get-Process -Name invalid_programm
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (invalid_programm:String) [Get-Process],ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
==> echo errorlevel=%errorlevel%
errorlevel=1
Successful completion ( errorlevel 0 )
==> powershell -noprofile -c "return 1"
1
==> echo errorlevel=%errorlevel%
errorlevel=0
Successful completion ( errorlevel set explicitly using the exit keyword)
==> powershell -noprofile -c "exit 2"
==> echo errorlevel=%errorlevel%
errorlevel=2
Hence, you could use the following code snippet (which should always successfully complete):
try {
$x = #(Get-Process -Name programm -ErrorAction Stop |
Where-Object -FilterScript {-not $_.Responding})
exit $x.Count
} catch {
exit 5000 # or other `absurd` value
}
Rewriting the above as an one-liner (using aliases), you could meet following scenarios:
A process with specified name not found
==> powershell -noprofile -c "try{$x=#(gps programm -EA Stop|? {-not $_.Responding});exit $x.Count} catch {exit 5000}"
==> echo errorlevel=%errorlevel%
errorlevel=5000
A process with specified name found & responding
==> powershell -noprofile -c "try{$x=#(gps cmd -EA Stop|? {-not $_.Responding});exit $x.Count} catch {exit 5000}"
==> echo errorlevel=%errorlevel%
errorlevel=0
One process with specified name found & NOT responding
==> powershell -noprofile -c "try{$x=#(gps HxOutlook -EA Stop|? {-not $_.Responding});exit $x.Count} catch {exit 5000}"
==> echo errorlevel=%errorlevel%
errorlevel=1
More processes with specified name found & NOT responding
==> powershell -noprofile -c "try{$x=#(gps -EA Stop|? {-not $_.Responding});exit $x.Count} catch {exit 5000}"
==> echo errorlevel=%errorlevel%
errorlevel=4
Please note incompleteness of above enumeration: we could imagine scenario where run more processes with specified name, some of them responding while other not-responding. (In other words, found & NOT responding does not imply that there does not exist another found & responding of the same name…)

Related

CMD check if registry key exist

I have multiple registry keys called
O365BusinessRetail - en-us
O365BusinessRetail - de-de
... and so on for many languages
I want to check if the registry keys exist or not. But this command will not work "Registry key could not be found"
reg query "HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\O365BusinessRetail*"
IF %ERRORLEVEL% == 1 exit 1
If %ERRORLEVEL% == 0 exit 0
I also tried
reg query "HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall" /v ? | findstr /C "O365BusinessRetail*"
IF %ERRORLEVEL% == 1 exit 1
If %ERRORLEVEL% == 0 exit 0
However with Powershell it works but I can't use it because Powershell is blocked on our side
if (Test-Path -Path registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\O365BusinessRetail*) {
exit 1 # same as: Write-Output 1
}
else {
exit 0 # same as: Write-Output 0
}
What is the best way to do that in CMD?
Thanks
Your submitted code should look like this:
#SystemRoot%\System32\reg.exe Query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" /F "O365BusinessRetail*" /K 1>NUL 2>&1
#Exit %Errorlevel%
If one or more subkeys beginning with the string O365BusinessRetail exist, the script will exit with the 0 error code. If none exist, it will exit with a 1 error code.
Please also note that it is possible that the applications are registered under another uninstall key branch or root key.

FIND: Parameter format not correct when piping ping command

I am trying to get the response of a ping test onto a json file.
set RESPONSE=$(ping %IPADDRESS% -n 1 | find "time=")
echo %RESPONSE% >> results.json
When I try ping %IPADDRESS% -n 1 | find "time=" on cmd prompt directly it works fine. But when I run this in a script, I get the following error:
FIND: Parameter format not correct
Does anyone know why? many thanks.
I was able to bypass this issue thanks to Mark's advice of using for.
FOR /F "skip=7 tokens=9" %%G IN ('ping %IPADDRESS% -n 1') DO set REPONSE=%%G
echo "reponse time": "%REPONSE%", >> results.json
did it for me. (I'm pretty sure it's bad coding though, I was playing with the positions of the words, so if the ping command output ever changes, my code stops working.)
Unless I have misunderstood your question, I have a feeling that you're actually wanting your results.json to hold the line $(ping %IPADDRESS% -n 1 | find "time="), obviously with %IPADDRESS% expanded to its value. For that you'd probably be best advised to use delayed expansion, like this:
Set "RESPONSE=$(ping %IPADDRESS% -n 1 | find "time=")"
SetLocal EnableDelayedExpansion
(Echo !RESPONSE!) 1>> "results.json"
EndLocal
Another way to get a JSON file would be:
powershell -NoLogo -NoProfile -Command ^
"Test-Connection -ComputerName localhost -Count 1 |" ^
"Select-Object -Property ResponseTime |" ^
"ConvertTo-Json |" ^
"Out-File -FilePath 'C:\src\t\results.json' -Encoding ascii"
This produces:
{
"ResponseTime": 0
}
If the system is running pwsh, the following can be used.
PS C:\> Test-Connection -ComputerName www.ibm.com -Count 1 |
Select-Object -Property Latency |
ConvertTo-Json
{
"Latency": 38
}
PS C:\> $PSVersionTable.PSVersion.ToString()
7.0.1

Display Line (n) in a text file In Command Prompt

My text file include with 23 lines (lines include: !#$:/;" )
How can i only display line 3? in or 7? or 19?
I tried all commands was in stackoverflow
Example:
setlocal enabledelayedexpansion
#echo off
for /f "delims=" %%i in (mytext.txt) do (
if 1==1 (
set first_line=%%i
echo !first_line!
goto :eof
))
that's only show first line
#Compo has given a good answer. This is only to expound on it. Using aliases like GC should not be put into scripts. At the command line, sure, go ahead and reduce typing if you feel like it. Also, spelling out the parameter names provides more information and aids faster understanding.
To get only line 3.
GC .\mytext.txt -T 3|Select -L 1
Get-Content -Path '.\mytext.txt' -TotalCount 3 | Select-Object -Last 1
From the CMD console (Command prompt): (to get only line seven (7)
PowerShell "GC .\mytext.txt -T 7|Select -L 1"
PowerShell -NoProfile "Get-Content -Path '.\mytext.txt' -TotalCount 7 | Select-Object -Last 1"
To get lines 3 through 7:
$FirstLine = 3
$LastLine=7
powershell -NoProfile -Command "Get-Content -Path '.\t.txt' -TotalCount $LastLine | Select-Object -Last ($LastLine - $FirstLine + 1)"
Or, in a cmd.exe batch script.
SET "FIRSTLINE=3"
SET "LASTLINE=7"
powershell -NoProfile -Command ^
"Get-Content -Path '.\t.txt' -TotalCount %LASTLINE% |" ^
"Select-Object -Last (%LASTLINE% - %FIRSTLINE% + 1)"
#echo off
setlocal
set "FILE_TO_PROCESS=%~f1"
set /a LINE_NUMBER=%~2
set /a trim=LINE_NUMBER-1
break>"%temp%\empty"&&fc "%temp%\empty" "%FILE_TO_PROCESS%" /lb %LINE_NUMBER% /t |more +4 | findstr /B /E /V "*****"|more +%trim%
endlocal
try with this bat (called lineNumber.bat) the first argument is the file you want to process the second is the line number:
call lineNumber.bat someFile.txt 5
There are a couple of ways to do this. Your first option is to go through the for loop normally and break out of the loop once you reach the desired line.
#echo off
:: Specify which line to return
set get_line=7
:: Skip all lines before it, then print the next line and abort
set /a get_line-=1
for /F "skip=%get_line% delims=" %%A in (mytext.txt) do (
echo %%A
goto :end_loop
)
:end_loop
Your other option is to store all lines before the unwanted line in a temp variable and then display the next line.
#echo off
setlocal enabledelayedexpansion
:: Specify which line to return
set get_line=7
:: Skip all lines before it, then print the next line and abort
set /a get_line-=2
(
for /L %%A in (0,1,%get_line%) do set /p skip_line=
set /p return_line=
) <file.txt
echo !return_line!
Note that the first option is not suited for returning the first line of the script.
Since you said 'display', why not give PowerShell a shot:
From the PowerShell console:
GC .\mytext.txt -T 3|Select -L 1
From the CMD console (Command prompt):
PowerShell "GC .\mytext.txt -T 7|Select -L 1"
From a batch file:
#(PowerShell "GC .\mytext.txt -T 19|Select -L 1"&Pause)

How can I get the exit code or exit status after finish a robotium test on the command line

Now I wrote a batch script to run the command like:
adb -s emulator-5556 shell am instrument -e class com.example.test.locationListTest -w com.example.test/android.test.InstrumentationTestRun
Then at the console I get results like FAILURE!!! Tests run: 5 fail:4 or OK.
I use if errorlevel 0 to determine the upper command, but it gives me 0 no matter the upper command gives me, OK or FAILURE.
I need to do this in batch script like this:
if(adb -s emulator-5556 shell ..... test.InstrumentationTestRun == SUCCESS )
do (.........)
else (.........)
Try this:
#echo off
setlocal
set "adb=adb -s emulator-5556 shell am instrument -e class com.example.test.locationListTest -w com.example.test/android.test.InstrumentationTestRun"
for /f "tokens=*" %%a in ('%adb%^|find /i "Ok"') do (
if not errorlevel 1 (
Echo Success
) else (
echo Failure
)
)
This way, errorlevel will work because it's coming from Find.
if errorlevel 0 is always true.
You need to use if not errorlevel 1 when you use that style of line for testing.
What about something simple, like:
adb -s emulator-5556 shell am instrument -e class com.example.test.locationListTest -w com.example.test/android.test.InstrumentationTestRun | grep "Failures"
if [ $? -eq 0 ]; then
echo "## TEST FAILED ##"
exit 1
fi
Rather than doing it via adb you can instead run your instumentation tests with gradle.
Here is an example bash script to do this:
#!/bin/bash
CMD="./gradlew connectedAndroidTest"
$CMD
RESULT=$?
if [ $RESULT -ne 0 ]; then
echo "failed $CMD"
exit 1
fi
exit 0

Streamlining a batch file calling a sql file

We currently have a scheduler to run audits. This scheduler will call a batch file with a parameter, and the batch file calls a sql script (based on the parameter), which in turn calls a stored proc.
For each audit that runs, a separate batch file, and sql file. Best case I'd like to combine the two below files into 1 file that can be used for every new audit. Worst case I'd at least like to combine to get 1 file for each audit instead of two. Hopefully you all can help?
Batch File
#echo on
Echo Running SQL Command File for '%1' Data Audit Check
del "D:\Internal_Reports\%1\%1.txt"
sqlcmd -S localhost -d database -i "D:\DataAudit\%1.sql" -s "," > D:\Temp\%1.csv -I -W -k 1
if %ERRORLEVEL% GTR 0 COPY "D:\Temp\%1.csv" "D:\Internal_Reports\%1\%1.txt"
if %ERRORLEVEL% NEQ 0 goto Error_1
echo No Errors
goto end
:Error_1
if %ERRORLEVEL% NEQ 1 goto Error_2
echo No Errors
goto end
:Error_2
echo Errorlevel %ERRORLEVEL%
set FileName=%1%2
echo Filename %FileName%
echo %ERRORLEVEL% > D:\ErrorLevel\%FileName%
EXIT /B %ERRORLEVEL%
:end
SQL File
set NoCount on
DECLARE
#createdBy varchar(16),
#dataAuditBatchId int,
#createdDtTm datetime
select
#createdBy = 'AutomatedAudit'
exec CreateNewDataAuditBatch #createdBy, #dataAuditBatchId output
-- Content Scripts
exec specificAuditStoredProc #createdBy, #dataAuditBatchId
select * from vAuditErrors where JobName in ('specificAuditStoredProc')
:exit(select Case When Counter = 0 then 0 Else 1 End 'errorCode'
from (select CAST(Count(*) AS varchar(4)) AS Counter from vAuditErrors
where JobName in ('specificAuditStoredProc'))
CountTable
)
Your best bet would be PowerShell in this case. You can combine both worlds of Batch Scripting and direct access to SQL.
Copy the below code into a text file: Audit.ps1
Create a File called: AuditFile.txt, put your SpecificAuditProc names on each line.
Then in your batch scheduler run this: "powershell -command "& c:\Audit.ps1 -name 'ProcName'"
Heres the code [Untested]:
param([Parameter(Mandatory=$true)][String]$name="")
$createdBy = "AutomatedAudit"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=LOCALHOST;Database=HT;Integrated Security=True"
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.Connection = $SqlConnection
$SqlCmd.CommandText = "[CreateNewDataAuditBatch]"
$SqlCmd.CommandType = [System.Data.CommandType]::StoredProcedure
$SqlCmd.Parameters.Add("#createdBy", $creadtedBy)
$SqlCmd.Parameters.Add("#dataAuditBatchId ")
$SqlCmd.Parameters["#dataAuditBatchId"].Direction = [system.Data.ParameterDirection]::Output
$SqlCmd.ExecuteNonQuery()
$dataAuditBatchId = $Command.Parameters["#dataAuditBatchId"].value
$SqlCmd.Dispose()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.Connection = $SqlConnection
$SqlCmd.CommandText = "[$name]"
$SqlCmd.CommandType = [System.Data.CommandType]::StoredProcedure
$SqlCmd.Parameters.Add("#createdBy", $creadtedBy)
$SqlCmd.Parameters.Add("#dataAuditBatchId ", $dataAuditBatchId)
$SqlCmd.ExecuteNonQuery()
$SqlCmd.Dispose()
$sqlcheck = #(Invoke-Sqlcmd -Query "select * from vAuditErrors where JobName in ('$name')" -ServerInstance "LOCALHOST\HT")
if ($sqlcheck.Count -ne 0) {
$sqlcheck > D:\Internal_Reports\$name\$name.txt
$sqlcheck.Count >> D:\ErrorLevel\$name
}
$Connection.Close()
$Connection.Dispose()
This is a simple problem to solve in pure batch PROVIDED you clarify a few points.
What is "%1" here? The database name perhaps?
Do you have just one SQL file and if not, what elements in the sample you posted need to be replaced for different databases?
(sorry - this isn't really an answer per se, but I'll make some (i hope, useful) comments on your btch as posted. The SO comment facility really doesn't suit here...
#echo on
Echo Running SQL Command File for '%1' Data Audit Check
del "D:\Internal_Reports\%1\%1.txt"
sqlcmd -S localhost -d database -i "D:\DataAudit\%1.sql" -s "," > D:\Temp\%1.csv -I -W -k 1
OK: so in all probability, %1 id the database name. So - why -d database and not -d %1 ??
Why the > D:\... and not '-o D:...` ??
if %ERRORLEVEL% GTR 0 COPY "D:\Temp\%1.csv" "D:\Internal_Reports\%1\%1.txt"
Ack! The fail-to-fail scenario in all its glory! Most commonly, you'd get ERRORLEVEL 0 from the sqlcmd BUT COPY can change ERRORLEVEL. If the COPY succeeds, then ERRORLEVEL will be 0, but if COPY fails, ERRORLEVEL would be non-zero and that's the value that will be used by the steps following...
if %ERRORLEVEL% NEQ 0 goto Error_1
echo No Errors
goto end
:Error_1
if %ERRORLEVEL% NEQ 1 goto Error_2
echo No Errors
goto end
You could arrive at :error_2 by simply executing
if errorlevel 2 goto error2
directly after the SQLCMD is executed (means "If errorlevel is 2 OR GREATER")
:Error_2
echo Errorlevel %ERRORLEVEL%
set FileName=%1%2
echo Filename %FileName%
echo %ERRORLEVEL% > D:\ErrorLevel\%FileName%
EXIT /B %ERRORLEVEL%
:end
Suddenly an unexplained %2 appears...?

Resources