Echo text after the set command in batch - batch-file

Is there way to echo text after a set command? I have tried, but nothing seems to work. Here is my code:
#echo off
Echo Enter a website:
Set /p op="Https:\\" ".com"
:: The ".com" would be displayed behind the users input.
if %op%==%op% goto Show
:Show
cls
Echo Website: Http:\\%op%.com
pause
exit
How would I get the .com to be displayed after the input? I would preferably like to have the ".com" frozen in one spot, no matter how big the users input is.

I took the solution from this answer and slightly modified it in order to fulfill this request.
#echo off
setlocal EnableDelayedExpansion
for /F %%a in ('echo prompt $H ^| cmd') do set "BS=%%a"
for /F %%a in ('copy /Z "%~F0" NUL') do set "CR=%%a"
set "op="
set /P "=Https:\\.com!BS!!BS!!BS!!BS!" < NUL
:nextKey
set "key="
for /F "delims=" %%K in ('xcopy /W "%~F0" "%~F0" 2^>NUL') do if not defined key set "key=%%K" & set "key=!key:~-1!"
if "!key!" equ "!CR!" goto endInput
if "!key!" neq "!BS!" (
set "op=%op%%key%"
set /P "=.!BS!%key%.com!BS!!BS!!BS!!BS!" < NUL
) else if defined op (
set "op=%op:~0,-1%"
set /P "=.!BS!!BS!.com !BS!!BS!!BS!!BS!!BS!" < NUL
)
goto nextKey
:endInput
echo/
echo/
echo Website: Http:\\%op%.com
EDIT: New method added (requested in a comment)
#echo off
setlocal EnableDelayedExpansion
set /A spaces=10, backSpaces=spaces+4
set "spcs="
for /L %%i in (1,1,%spaces%) do set "spcs=!spcs! "
set "back="
for /F %%a in ('echo prompt $H ^| cmd') do set "BS=%%a"
for /L %%i in (1,1,%backSpaces%) do set "back=!back!!BS!"
set /P "op=Https:\\%spcs%.com!back!"
echo/
echo Website: Http:\\%op%.com

Per #Marged's comments, I suspect this is impossible (or at least extremely difficult) by batch file.
Here's a PowerShell solution should that be of use:
function Get-UserInput {
param (
[parameter(mandatory = $false)]
[string]$pre='Enter text:'
,
[parameter(mandatory = $false)]
[string]$post='_'
)
process {
[string]$text=''
while ($key.Key -ne 'Enter') {
write-host "`r$pre$text$post " -NoNewline #trailing space to hide deleted chars
#replace the above with the 3 below if you want user input to be a different colour to the defaults
#write-host "`r$pre" -NoNewline
#write-host $text -NoNewline -ForegroundColor Cyan
#write-host "$post " -NoNewline #trailing space to hide deleted chars
$key = [Console]::ReadKey($true)
switch ($key.Key)
{
'Backspace' { $text = $text.substring(0,($text.length-1)) }
default { $text = $text + $key.KeyChar }
}
}
write-host "" #undo no new line
write-output "$pre$text$post"
}
}
clear-host
$input = Get-UserInput -pre 'https://' -post '.com'
"User entered: '$input'"

Related

How To See Which One .bat file running on task scheduler

i have one task scheduler with 2 .bat file on action.
List .bat file on action tab
when task scheduler running how to i know which one .bat is running ?
this is xml file task scheduler:
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date>2020-07-21T08:40:20.4842672</Date>
<Author>WIN-9DQ9EVI3R22\Administrator</Author>
<URI>\RESTORE</URI>
</RegistrationInfo>
<Triggers>
<CalendarTrigger>
<Repetition>
<Interval>PT5M</Interval>
<StopAtDurationEnd>false</StopAtDurationEnd>
</Repetition>
<StartBoundary>2020-07-21T00:00:00</StartBoundary>
<Enabled>true</Enabled>
<ScheduleByDay>
<DaysInterval>1</DaysInterval>
</ScheduleByDay>
</CalendarTrigger>
</Triggers>
<Principals>
<Principal id="Author">
<UserId>S-1-5-21-316211975-241055689-3246940587-500</UserId>
<LogonType>Password</LogonType>
<RunLevel>LeastPrivilege</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command>"D:\Batch File\LS_RESTORE_221.bat"</Command>
</Exec>
<Exec>
<Command>"D:\Batch File\LS_RESTORE_MAINDB.bat"</Command>
</Exec>
</Actions>
</Task>
see at the xml file i have 2 .bat on action tag
this is .bat file script
sqlcmd -Q "exec SP_LS_RESTORE" -S WIN-9DQ9EVI3R22 -d dbSaaS_HOST_221 -o "D:\Batch File\LS_Restore_out_221.txt"
You can give a try for this batch file :
#echo off
Color 0B & Title Showing No Microsoft Scheduled Tasks List by Hackoo 2020
Set "TmpFile=%~n0_Abs_cmdline.txt"
Set "LogFile=%~n0_cmdline.txt
If Exist "%TmpFile%" Del "%TmpFile%"
If Exist "%LogFile%" Del "%LogFile%"
Set ProcessNames="cmd.exe" "wscript.exe" "cscript.exe"
SetLocal EnableDelayedExpansion
for %%A in (%ProcessNames%) Do (
Call :GetCommandLine %%A ProcessCmd
If defined ProcessCmd (
echo !ProcessCmd!>>"%TmpFile%"
)
)
If Exist "%TmpFile%" Call :Extract "%TmpFile%" "%LogFile%"
If Exist "%LogFile%" Start "" "%LogFile%"
echo(
echo( ****************************************************************************************************
echo( No Microsoft Scheduled Tasks List
echo( ****************************************************************************************************
Set "EXT=BAT"
#For /F "tokens=2,9 delims=," %%a in (
'SCHTASKS /Query /NH /FO CSV /V ^|find /I /V "Microsoft" ^|find /I /V "ADOBE" ^|findstr /I /C:"%EXT%"'
) do (
REM Set TaskName=%%~a
Set TaskPath=%%~b
REM Call :Trim_Dequote !TaskName! TaskName
Call :Trim_Dequote !TaskPath! TaskPath
REM echo "!TaskName!"
echo( "!TaskPath!"
)
Pause & exit
::-----------------------------------------------------------------------------------
:Trim_Dequote <Var> <NewVar>
Set "VbsFile=%Tmp%\%~n0.vbs"
(
echo Wscript.echo Trim_Dequote("%~1"^)
echo Function Trim_Dequote(S^)
echo If Left(S, 1^) = """" And Right(S, 1^) = """" Then Trim_Dequote = Trim(Mid(S, 2, Len(S^) - 2^)^) Else Trim_Dequote = Trim(S^)
echo End Function
)>"%VbsFile%"
for /f "delims=" %%a in ('Cscript //nologo "%VbsFile%"') do (
set "%2=%%a"
)
Del "%VbsFile%" /F >nul 2>&1
exit /b
::---------------------------------------------------------------------------------------------------------------
:GetCommandLine <ProcessName> <ProcessCmd>
Set "ProcessCmd="
for /f "tokens=2 delims==" %%P in (
'2^>nul wmic process where caption^="%~1" get commandline /format:list ^| findstr /I "%~1" ^| find /I /V "%~nx0"'
) do (
if not defined %2 Set "%2=%%P"
)
Exit /b
::---------------------------------------------------------------------------------------------------------------
:Extract <InputData> <OutPutData>
(
echo Data = WScript.StdIn.ReadAll
echo Data = Extract(Data,"(^?^!.*(\x22\w\W^)^).*(\.ps1^|\.vbs^|\.vbe^|\.js^|\.jse^|\.cmd^|\.bat^|\.wsf^|\.exe^)(^?^!.*(\x22\w\W^)^)"^)
echo WScript.StdOut.WriteLine Data
echo Function Extract(Data,Pattern^)
echo Dim oRE,oMatches,Match,Line
echo set oRE = New RegExp
echo oRE.IgnoreCase = True
echo oRE.Global = True
echo oRE.Pattern = Pattern
echo set oMatches = oRE.Execute(Data^)
echo If not isEmpty(oMatches^) then
echo For Each Match in oMatches
echo Line = Line ^& Trim(Match.Value^) ^& vbcrlf
echo Next
echo Extract = Line
echo End if
echo End Function
)>"%tmp%\%~n0.vbs"
cscript /nologo "%tmp%\%~n0.vbs" < "%~1" > "%~2"
If Exist "%tmp%\%~n0.vbs" Del "%tmp%\%~n0.vbs"
exit /b
::---------------------------------------------------------------------------------------------------------------
EDIT on 23/08/2020 #16:45 :
This is a Hybrid code Batch and Powershell that help us to show All No Microsoft Scheduled Tasks.
Show_No-Microsoft_Tasks.bat
<# : Batch portion
#rem # The previous line does nothing in Batch, but begins a multiline comment block
#rem # in PowerShell. This allows a single script to be executed by both interpreters.
#echo off
Title Get Schedule Tasks with a Hybrid code Batch and Powershell Script by Hackoo 2020
echo(
rem # This a Powershell command executes the hybrid portion at the bottom of this script
rem #for /f "delims=" %%I in ('powershell -noprofile "iex (${%~f0}|out-string)"') do echo %%I
>"%~dpn0.txt" (
#for /f "delims=" %%I in ('powershell -noprofile "iex (${%~f0}|out-string)"') do echo %%I
)
REM TimeOut /T 3 /NoBreak>nul
If Exist "%~dpn0.txt" Start "" "%~dpn0.txt" & exit /b
rem # End multi-line PowerShell comment block. Begin PowerShell scripting.
: end Batch / begin PowerShell hybrid code #>
Function getTasks($path) {
$out = #()
# Get root tasks
$schedule.GetFolder($path).GetTasks(0) | % {
$xml = [xml]$_.xml
$out += New-Object psobject -Property #{
"Name" = $_.Name
"Path" = $_.Path
"LastRunTime" = $_.LastRunTime
"NextRunTime" = $_.NextRunTime
"Actions" = ($xml.Task.Actions.Exec | % { "$($_.Command) $($_.Arguments)" }) -join "`n"
}
}
# Get tasks from subfolders
$schedule.GetFolder($path).GetFolders(0) | % {
$out += getTasks($_.Path)
}
#Output
$out
}
$tasks = #()
$schedule = New-Object -ComObject "Schedule.Service"
$schedule.Connect()
# Start inventory
$tasks += getTasks("\")
# Close com
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($schedule) | Out-Null
Remove-Variable schedule
# To show All No Microsoft Scheduled Tasks
$tasks | ? { $_.Path -notmatch "Micro*" }
Read-Host 'Type any key to continue'
$tasks | ? { $_.Path -notmatch "Micro*" } | Out-GridView
Read-Host 'Type any key to continue'
<#
# Output all tasks
#$tasks | Out-GridView
#Read-Host 'Type any key to continue'
# To show only tasks with those extensions in their TaskPath
#$tasks | ? { $_.Actions -match "(\.vbs|\.vbe|\.cmd|\.bat|\.hta)" } | Out-GridView
#Read-Host 'Type any key to continue'
#>

Batch file to change color of text depending on output string from log file

I'm trying to read a log file with a batch file.
If the batch file finds SUCCESS in the log file, the text should be in green.
If the batch file finds WARNING in the log file, the text should be in cyan.
If the batch file finds ERROR in the log file, the text should be in red.
It works when it finds either of the one value, but if the log file contains two or more of the different results like SUCCESS and WARNING it doesn't work.
Trying to read a log file with batch file on Windows.
#echo off
set LogPath=C:\Mworks\logs
set /p MM-DD="Enter Month and Day (MM-DD) to Search logs for success close eg. 08-24: "
set YEAR=2019
#echo searching for %LogPath%\%YEAR%-%MM-DD%*.log
FOR /F "eol=- tokens=1-8 delims= " %%i in ('find /I "LOG ROTATE COMPLETE" %LogPath%\%YEAR%-%MM-DD%*.log') do set result=%%p
echo %result%
(
IF /I %result%==ERROR (goto :ERROR)
)
(
if /I %result%==SUCCESS (goto :SUCCESS)
)
(
if /I %result%==WARNING (goto :WARNING)
)
REM somehow need to catch value at token 8 and color the lines accordingly
REM proper use of enableDelayedExpansion might help but it's quite tough simply with batch script.
REM I've seen hackoo's version of pinger doing it but the code is hard to understand, which part controls what.
:SUCCESS
color 0A
REM this line needs to be on GREEN
FOR /F "eol=- tokens=1-8 delims= " %%i in ('find /I "LOG ROTATE COMPLETE" %LogPath%\2019-%MM-DD%*.log') do #echo %%i %%j %%k %%l %%m %%n %%o %%p
goto end
:ERROR
color 0C
REM this line nees to be on RED
FOR /F "eol=- tokens=1-8 delims= " %%i in ('find /I "LOG ROTATE COMPLETE" %LogPath%\2019-%MM-DD%*.log') do #echo %%i %%j %%k %%l %%m %%n %%o %%p
goto end
:WARNING
REM This line needs to be on CYAN
color 0B
FOR /F "eol=- tokens=1-8 delims= " %%i in ('find /I "LOG ROTATE COMPLETE" %LogPath%\2019-%MM-DD%*.log') do #echo %%i %%j %%k %%l %%m %%n %%o %%p
:end
pause
The code doesn't work if it find more than one result where result could be SUCCESS, WARNING, ERROR.
**LOG BEGUN 2019-08-24 03:42:28,662
loading c:Mworksconfiglog4j2.xml
INFO 2019-08-24 03:42:34,100 Initializing configs... :: oracle.retail.mworks.config.mworksProperties [mworks]
INFO 2019-08-24 03:42:34,100 Loading Properties - jar:file:/C:/Mworks/lib/menv-engine.jar!/dtv/res/config/actions.properties :: dtv.util.ResourceUtils [mworks]
INFO 2019-08-24 03:42:34,115 Loading Properties - file:/C:/Mworks/cust_config/version1/actions.properties :: dtv.util.ResourceUtils [mworks]
INFO 2019-08-24 03:42:34,131 Loading Properties - jar:file:/C:/Mworks/lib/menv-engine.jar!/dtv/res/config/environment.properties :: dtv.util.ResourceUtils [mworks]
INFO 2019-08-24 03:42:34,131 Loading Properties - file:/C:/Mworks/cust_config/version1/environment.properties :: dtv.util.ResourceUtils [mworks]
INFO 2019-08-24 03:42:34,146 Loading Properties - jar:file:/C:/Mworks/lib/menv-engine.jar!/dtv/res/config/update.properties :: dtv.util.ResourceUtils [mworks]
INFO 2019-08-24 03:42:34,162 Loading Properties - file:/C:/Mworks/cust_config/version1/update.properties :: dtv.util.ResourceUtils [mworks]
INFO 2019-08-24 03:42:34,162 Loading Properties - jar:file:/C:/Mworks/lib/menv-engine.jar!/dtv/res/config/local.properties :: dtv.util.ResourceUtils [mworks]
INFO 2019-08-24 03:42:34,162 Loading Properties - file:/C:/Mworks/cust_config/version1/local.properties :: dtv.util.ResourceUtils [mworks]
INFO 2019-08-24 03:42:34,584 Loading registration data from c:\Mworks\res\data\registrationdata.json :: oracle.retail.mworks.registration.RegistrationDataManager [mworks]
INFO 2019-08-24 03:42:35,287 Gathering local Client data. :: oracle.retail.mworks.registration.RegistrationDataManager [mworks]
INFO 2019-08-24 03:42:36,334 loading jar:file:/C:/Mworks/lib/menv-engine.jar!/dtv/res/config/MBeanInfoConfig.xml :: dtv.util.config.ConfigHelper [mworks]
INFO 2019-08-24 03:42:36,883
INFO 2019-08-24 03:42:36,883 Waiting for services to start... :: oracle.retail.mworks.mworks [mworks]
ntly running actions: [startup-lead, create-update-directories, LOG ROTATE] :: oracle.retail.mworks.action.Action [ActionExec-1]
INFO 2019-08-24 03:42:40,447 Action [CreateUpdateDirectories :: oracle.retail.mworks.atoms.CreateUpdateDirectories] complete. State: SUCCESS, Result: -----------------------------------
The text below should be in RED
----------------------------------
INFO 2019-08-24 03:42:40:03,060 LOG ROTATE complete. Status: ERROR Created update directories. :: oracle.retail.mworks.atoms.Atom [ActionExec-1]
INFO 2019-08-24 03:42:40,447 Currently running actions: [startup-lead, LOG ROTATE] :: oracle.retail.mworks.action.Action [ActionExec-1]
INFO 2019-08-24 03:42:40,447 Action [create-update-directories] returned state [SUCCESS] with message [Created update directories.] ::
The text below should be in cyan
---------------------------------------
INFO 2019-08-24 04:44:03,060 LOG ROTATE complete. Status: WARNING
LOT OF lines DELETED
The text below should be in green
----------------------------------------
INFO 2019-08-24 05:44:03,060 LOG ROTATE complete. Status: SUCCESS :: oracle.retail.xenvironment.action.Action [ActionExec-2]
sample log
This is my mono color output
something like this:
#Echo Off
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"
)
call :chooseColor 0A "This is colored Green means SUCCESS"
echo.
call :chooseColor 0B "This is colored Cyan means WARNING"
echo.
call :chooseColor 0C "This is colored Red means ERROR"
echo.
pause
goto eof
:chooseColor
echo off
<nul set /p ".=%DEL%" > "%~2"
findstr /v /a:%1 /R "^$" "%~2" nul
del "%~2" > nul 2>&1i
:eof
output should be like this
A pure batch solution using ANSI Escape codes requires a more recent Win10 version.
Difficulty is the ESC symbol hex 0x1b, dec 27 which not all editors provide easily.
Here solved using certutil to convert hex to binary.
EDIT stacked a for to the for /f with a lowercase %%f
:: Q:\Test\2019\08\31\SO_57736435.cmd
#echo off
:restart
set "MM-DD="
set /p MM-DD="Enter Month and Day (MM-DD) to Search logs for success close eg. 08-24: "
if not defined MM-DD Exit /B 0
set "LogPath=C:\Mworks\logs"
set "File=%LogPath%\log.2019-%MM-DD%*.log"
if not exist "%File%" (Echo %File% doesn't exist&pause&goto :restart)
:: ANSI Escape codes, supported with Win10 again
Call :GetCSI
FOR %%f in ("%File%") Do FOR /F "usebackq tokens=1-8* delims= " %%A in ("%%f"
) do if /I "%%A%%D%%E%%F%%G"=="INFOLogRotateComplete.Status:" (
Call :%%H "%%A %%B %%C %%D %%E %%F %%G %%H %%I"
) Else (
Echo:%%A %%B %%C %%D %%E %%F %%G %%H %%I
)
Pause
exit /B 0
:Warning
Echo(%CSI%36m%~1%CSI%0m
Goto :Eof
:Success
Echo(%CSI%32m%~1%CSI%0m
Goto :Eof
:Error
Echo(%CSI%31m%~1%CSI%0m
Goto :Eof
:GetCSI
echo 1B 5B>CSI.hex
Del CSI.bin >NUL 2>&1
certutil -decodehex CSI.hex CSI.bin >NUL 2>&1
Set /P CSI=<CSI.bin
Goto :Eof
Batch is definitely the wrong script language for this, you need:
full featured Regular Expression support
the capability to easily color single lines
BTW your batch has a bunch of errors/shortcummings
This PowerShell script (using a single fixed file name) should do what you are after:
## create a hash table with the color mappings
$FG = #{SUCCESS='green';WARNING='cyan';ERROR='red'}
# Regular Expression with a capture group to grep
# the Status, see https://regex101.com/r/d0swXC/1
$RE = '^INFO (.*?) LOG ROTATE complete\. +Status: (?<Status>[^ ]+).*'
ForEach($Line in Get-Content .\file.log){
if ($Line -match $RE){
Write-Host -ForegroundColor $FG[$Matches.Status] $Line
} Else {
Write-Host $Line
}
}
A fast alternative to color efficiently with cmd batch since Windows XP by using PowerShell as a subprocess linked to the console output through a named pipe. It can be done with FindStr too, but PowerShell offers more options and seems quicker.
The main interest in keeping PowerShell as a subprocess, using a pipe to communicate, is that the display is far more faster than launching PowerShell or FindStr for each line to display.
Other good points :
No need for temporary files
Echoing though a pipe permits the display of the full ASCII table without bothering escapes.
Works fine with fd redirection. To color only stderr as example, or to redirect to a file / other process.
Here is a sample code for doing that :
::
:: Launch a PowerShell child process in the background linked to the console and
:: earing through named pipe PowerShellCon_%PID%
::
:: Parameters :
:: [ PID ] : Console Process ID used as an identifier for the named pipe, launcher PID by default.
:: [ timeout ] : Subprocess max life in seconds, 300 by default. If -1, the subprocess
:: will not terminate while the process %PID% is still alive.
:: Return :
:: 0 if the child PowerShell has been successfully launched and the named pipe is available.
:: 1 if it fails.
:: 2 if we can't get a PID.
:: 3 if PowerShell is not present or doesn't work.
::
:LaunchPowerShellSubProcess
SET LOCALV_PID=
SET LOCALV_TIMEOUT=300
IF NOT "%~1" == "" SET LOCALV_PID=%~1
IF NOT "%~2" == "" SET LOCALV_TIMEOUT=%~2
powershell -command "$_" 2>&1 >NUL
IF NOT "!ERRORLEVEL!" == "0" EXIT /B 3
IF "!LOCALV_PID!" == "" (
FOR /F %%P IN ('powershell -command "$parentId=(Get-WmiObject Win32_Process -Filter ProcessId=$PID).ParentProcessId; write-host (Get-WmiObject Win32_Process -Filter ProcessId=$parentId).ParentProcessId;"') DO (
SET LOCALV_PID=%%P
)
)
IF "!LOCALV_PID!" == "" EXIT /B 2
START /B powershell -command "$cmdPID=$PID; Start-Job -ArgumentList $cmdPID -ScriptBlock { $ProcessActive = $true; $timeout=!LOCALV_TIMEOUT!; while((!LOCALV_TIMEOUT! -eq -1 -or $timeout -gt 0) -and $ProcessActive) { Start-Sleep -s 1; $timeout-=1; $ProcessActive = Get-Process -id !LOCALV_PID! -ErrorAction SilentlyContinue; } if ($timeout -eq 0 -or ^! $ProcessActive) { Stop-Process -Id $args; } } | Out-Null ; $npipeServer = new-object System.IO.Pipes.NamedPipeServerStream('PowerShellCon_!LOCALV_PID!', [System.IO.Pipes.PipeDirection]::In); Try { $npipeServer.WaitForConnection(); $pipeReader = new-object System.IO.StreamReader($npipeServer); while(($msg = $pipeReader.ReadLine()) -notmatch 'QUIT') { $disp='write-host '+$msg+';'; invoke-expression($disp); $npipeServer.Disconnect(); $npipeServer.WaitForConnection(); }; } Finally { $npipeServer.Dispose(); }" 2>NUL
SET /A LOCALV_TRY=20 >NUL
:LaunchPowerShellSubProcess_WaitForPipe
powershell -nop -c "& {sleep -m 50}"
SET /A LOCALV_TRY=!LOCALV_TRY! - 1 >NUL
IF NOT "!LOCALV_TRY!" == "0" cmd /C "ECHO -NoNewLine|MORE 1>\\.\pipe\PowerShellCon_!LOCALV_PID!" 2>NUL || GOTO:LaunchPowerShellSubProcess_WaitForPipe
IF "!LOCALV_TRY!" == "0" EXIT /B 1
EXIT /B 0
This "code" is written with delayed expansion ON but can be rewrite to work without it. There is many security points to consider, do not use it directly in the wild.
How to use it :
#ECHO OFF
SETLOCAL ENABLEEXTENSIONS
IF ERRORLEVEL 1 (
ECHO Extension inapplicable
EXIT /B 1
)
::
SETLOCAL ENABLEDELAYEDEXPANSION
IF ERRORLEVEL 1 (
ECHO Expansion inapplicable
EXIT /B 1
)
CALL:LaunchPowerShellSubProcess
IF NOT ERRORLEVEL 0 EXIT /B 1
CALL:Color Cyan "I write this in Cyan"
CALL:Blue "I write this in Blue"
CALL:Green "And this in green"
CALL:Red -nonewline "And mix Red"
CALL:Yellow "with Yellow"
CALL:Green "And not need to trouble with ()<>&|;,%""^ and so on..."
EXIT /B 0
:Color
ECHO -foregroundcolor %*>\\.\pipe\PowerShellCon_!LOCALV_PID!
ECHO[|SET /P=>NUL
GOTO:EOF
:Blue
ECHO -foregroundcolor Blue %*>\\.\pipe\PowerShellCon_!LOCALV_PID!
ECHO[|SET /P=>NUL
GOTO:EOF
:Green
ECHO -foregroundcolor Green %*>\\.\pipe\PowerShellCon_!LOCALV_PID!
ECHO[|SET /P=>NUL
GOTO:EOF
:Red
ECHO -foregroundcolor Red %*>\\.\pipe\PowerShellCon_!LOCALV_PID!
ECHO[|SET /P=>NUL
GOTO:EOF
:Yellow
ECHO -foregroundcolor Yellow %*>\\.\pipe\PowerShellCon_!LOCALV_PID!
ECHO[|SET /P=>NUL
GOTO:EOF
::
:: Launch a PowerShell child process in the background linked to the console and
:: earing through named pipe PowerShellCon_%PID%
::
:: Parameters :
:: [ PID ] : Console Process ID used as an identifier for the named pipe, launcher PID by default.
:: [ timeout ] : Subprocess max life in seconds, 300 by default. If -1, the subprocess
:: will not terminate while the process %PID% is still alive.
:: Return :
:: 0 if the child PowerShell has been successfully launched and the named pipe is available.
:: 1 if it fails.
:: 2 if we can't get a PID.
:: 3 if PowerShell is not present or doesn't work.
::
:LaunchPowerShellSubProcess
SET LOCALV_PID=
SET LOCALV_TIMEOUT=300
IF NOT "%~1" == "" SET LOCALV_PID=%~1
IF NOT "%~2" == "" SET LOCALV_TIMEOUT=%~2
powershell -command "$_" 2>&1 >NUL
IF NOT "!ERRORLEVEL!" == "0" EXIT /B 3
IF "!LOCALV_PID!" == "" (
FOR /F %%P IN ('powershell -command "$parentId=(Get-WmiObject Win32_Process -Filter ProcessId=$PID).ParentProcessId; write-host (Get-WmiObject Win32_Process -Filter ProcessId=$parentId).ParentProcessId;"') DO (
SET LOCALV_PID=%%P
)
)
IF "!LOCALV_PID!" == "" EXIT /B 2
START /B powershell -command "$cmdPID=$PID; Start-Job -ArgumentList $cmdPID -ScriptBlock { $ProcessActive = $true; $timeout=!LOCALV_TIMEOUT!; while((!LOCALV_TIMEOUT! -eq -1 -or $timeout -gt 0) -and $ProcessActive) { Start-Sleep -s 1; $timeout-=1; $ProcessActive = Get-Process -id !LOCALV_PID! -ErrorAction SilentlyContinue; } if ($timeout -eq 0 -or ^! $ProcessActive) { Stop-Process -Id $args; } } | Out-Null ; $npipeServer = new-object System.IO.Pipes.NamedPipeServerStream('PowerShellCon_!LOCALV_PID!', [System.IO.Pipes.PipeDirection]::In); Try { $npipeServer.WaitForConnection(); $pipeReader = new-object System.IO.StreamReader($npipeServer); while(($msg = $pipeReader.ReadLine()) -notmatch 'QUIT') { $disp='write-host '+$msg+';'; invoke-expression($disp); $npipeServer.Disconnect(); $npipeServer.WaitForConnection(); }; } Finally { $npipeServer.Dispose(); }" 2>NUL
SET /A LOCALV_TRY=20 >NUL
:LaunchPowerShellSubProcess_WaitForPipe
powershell -nop -c "& {sleep -m 50}"
SET /A LOCALV_TRY=!LOCALV_TRY! - 1 >NUL
IF NOT "!LOCALV_TRY!" == "0" cmd /C "ECHO -NoNewLine|MORE 1>\\.\pipe\PowerShellCon_!LOCALV_PID!" 2>NUL || GOTO:LaunchPowerShellSubProcess_WaitForPipe
IF "!LOCALV_TRY!" == "0" EXIT /B 1
EXIT /B 0
For windows 10, In native batch replacing %~dp0input.txt with the logs path:
::: Author T3RRY : Created 09/04/2021 : Version 1.0.1
:::
::: Purpose : Color and cursor position macro for windows 10 batch files
::: - Allows rapid display of colored output at specified screen position.
::: For more information, read the usage.
:::
::: Uses macro parameter and switch handling template.
::: - See : https://pastebin.com/gzL7AYpC
#Echo off
:# Windows Version control. Assigns flag true if system is windows 10.
Set "Win10="
Ver | Findstr /LIC:" 10." > nul && Set "Win10=true"
:# Test if virtual terminal codes enabled ; enable if false
:# removes win10 flag definition if version does not support Virtual Terminal sequences
If defined Win10 (
Reg Query HKCU\Console | %SystemRoot%\System32\findstr.exe /LIC:"VirtualTerminalLevel REG_DWORD 0x1" > nul || (
Reg Add HKCU\Console /f /v VirtualTerminalLevel /t REG_DWORD /d 1
) > Nul || Set "Win10="
)
If not defined Win10 (
Echo(Virtual terminal sequences not supported on your system
Exit /B 1
)
If "%~1" == "" (
Mode 200,150
Cls
)
(Set \n=^^^
%= \n macro newline variable. Do not modify =%)
:# assign virtual terminal control character 0x27 'escape' variable \E
For /F %%a in ( 'Echo prompt $E ^| cmd' )Do Set "\E=%%a"
:# Virtual Terminal 'VT' sequence Resource :
:# https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
::# usage: %$Cout% /Switch /Switch value
::# -----------------------------------------------------------------------------------------------------
::# Available Switches : Description:
::# -----------------------------------------------------------------------------------------------------
::# /Help : This help screen
::#
::# /S String : String to be output
::# /S String{FS} : '/' must be substituted with {FS}
::#
::# /C Integer : Declare output color using VT sequence
::# /C Integer,Integer : Chain mulitple VT color sequences
::# /C Integer;Integer : Combine multiple VT values into the one sequence
::#
::# /Y Integer : Move cursor to Line Integer [ absolute ]
::# /X Integer : Move cursor to Column Integer [ absolute ]
::# /U Integer : Move cursor Up by Integer
::# /D Integer : Move cursor Down by Integer
::# /R Integer : Move cursor Right by Integer
::# /L Integer : Move cursor Left by Integer
::#
::# /H - : Hide the cursor
::# /H + : Show the cursor
::# /Alt : Switch to alternate buffer [ main buffer is preserved ]
::# /Main : Return to main screen buffer [ alternate buffer is cleared ]
::# /K : Clears text to right of current cursor position
::# /Z Integer : Deletes Integer columns right of the cursor, shifting existing text left
::# /I Integer : Inserts whitespace into Integer columns right of Cursor, shifting text right
::# /N : Output a newline after other switches are executed.
::# -----------------------------------------------------------------------------------------------------
::#
:# Note on macro switch handling: Switches must not share a common prefix.
:# - IE:
:# - Invalid: D and DE [ switch assessment method would assign D as true if /DE used ]
:# - Valid : DA and DE
Set Switches= "help" "S" "C" "Y" "X" "U" "D" "R" "L" "H" "Alt" "Main" "K" "Z" "I" "N"
Set $Cout=For %%n in (1 2)Do if %%n==2 (%\n%
For %%G in ( %Switches% )Do set "Switch[%%~G]="%\n%
Set "leading.args=!args:*/=!"%\n%
For /F "Delims=" %%G in ("!leading.args!")Do Set "leading.args=!args:/%%G=!"%\n%
Set ^"args=!args:"=!" %\n%
Set "i.arg=0"%\n%
For %%G in (!leading.args!)Do (%\n%
Set /A "i.arg+=1"%\n%
Set "arg[!i.arg!]=%%~G"%\n%
)%\n%
For %%G in ( %Switches% )Do If not "!args:/%%~G=!" == "!args!" (%\n%
If not "!args:/%%~G: =!" == "!args!" Set "args=!args:/%%~G: =/%%~G !"%\n%
If not "!args:/%%~G =!" == "!args!" Set "switch[%%~G]=!Args:*/%%~G =!"%\n%
If not "!args:/%%~G:=!" == "!args!" Set "switch[%%~G]=!Args:*/%%~G:=!"%\n%
If not "!switch[%%~G]:*/=!" == "!switch[%%~G]!" (%\n%
Set "Trail[%%~G]=!switch[%%~G]:*/=!"%\n%
For %%v in ("!Trail[%%~G]!")Do (%\n%
Set "switch[%%~G]=!switch[%%~G]: /%%~v=!"%\n%
Set "switch[%%~G]=!switch[%%~G]:/%%~v=!"%\n%
)%\n%
Set "Trail[%%~G]="%\n%
If "!switch[%%~G]:~-1!" == " " Set "switch[%%~G]=!switch[%%~G]:~0,-1!"%\n%
If "!switch[%%~G]!" == "" Set "switch[%%~G]=true"%\n%
)%\n%
)%\n%
If "!Switch[help]!" == "true" (For /F "Tokens=1,2 Delims=#" %%Y in ('findstr /BLIC:"::#" "%~f0"')Do Echo(%%Z) ^& Timeout /T 1 /Nobreak ^> nul ^& Pause%\n%
If not "!Switch[C]!" == "" (Set "_Color_=%\E%[!Switch[C]:,=m%\E%[!m")Else Set "_Color_="%\n%
If not "!Switch[Y]!" == "" (Set "_Ypos_=%\E%[!Switch[Y]!d")Else Set "_Ypos_="%\n%
If not "!Switch[X]!" == "" (Set "_Xpos_=%\E%[!Switch[X]!G")Else Set "_Xpos_="%\n%
If not "!Switch[U]!" == "" (Set "_Yoffset_=%\E%[!Switch[U]!A")Else Set "_Yoffset_="%\n%
If not "!Switch[D]!" == "" Set "_Yoffset_=%\E%[!Switch[D]!B"%\n%
If not "!Switch[R]!" == "" (Set "_Xoffset_=%\E%[!Switch[R]!C")Else Set "_Xoffset_="%\n%
If not "!Switch[L]!" == "" Set "_Xoffset_=%\E%[!Switch[L]!D"%\n%
If "!Switch[H]!" == "-" Set "_Cursor_=%\E%[?25l"%\n%
If "!Switch[H]!" == "+" Set "_Cursor_=%\E%[?25h"%\n%
If "!Switch[Main]!" == "true" (Set "_Buffer_=%\E%[?1049l")Else Set "_Buffer_="%\n%
If "!Switch[Alt]!" == "true" Set "_Buffer_=%\E%[?1049h"%\n%
If not "!Switch[K]!" == "" (Set "_LineClear_=%\E%[K")Else Set "_LineClear_="%\n%
If not "!Switch[Z]!" == "" (Set "_Delete_=%\E%[!Switch[Z]!P")Else Set "_Delete_="%\n%
If not "!Switch[I]!" == "" (Set "_Insert_=%\E%[!Switch[I]!#")Else Set "_Insert_="%\n%
If not "!Switch[S]!" == "" (Set "_String_=!Switch[S]:{FS}=/!")Else Set "_String_="%\n%
^< nul set /P "=!_Buffer_!!_Cursor_!!_Ypos_!!_YOffset_!!_Xpos_!!_XOffset_!!_Delete_!!_Insert_!!_Color_!!_LineClear_!!_String_!%\E%[0m"%\n%
If "!Switch[N]!" == "true" Echo(%\n%
) Else Set args=
:# enable macro using Setlocal EnableExtensions EnableDelayedExpansion
CLS
If "%~1." == "/?." (
Setlocal EnableExtensions EnableDelayedExpansion
%$Cout% /help
Goto :EOF
)
For /F "usebackq Delims=" %%G in ("%~dp0input.txt")Do (
Set "Line=%%G"
Setlocal EnableExtensions EnableDelayedExpansion
If not "!Line:SUCCESS=!" == "!Line!" (
%$cout% /C 32 /N /S "!line:/={FS}!"
) Else If not "!Line:WARNING=!" == "!Line!" (
%$cout% /C 36 /N /S "!line:/={FS}!"
) Else If not "!Line:ERROR=!" == "!Line!" (
%$cout% /C 31 /N /S "!line:/={FS}!"
) Else (
%$cout% /N /S "!line:/={FS}!"
)
Endlocal
)
Goto :eof

Using two or more set /p in the same line

Im trying to make a script that the user need to fill 3 spaces in the same line.
Is it possibile?
For example filling a date: 25/02/2019 in this way: day here / month here / year here
Not line by line.
The normal way is that:
set /p "dd=Type the Day: "
set /p "mm=Type the Month: %dd% / "
set /p "aa=Type The Year: %dd% / %mm% / "
And the result will be: 22/05/2019
But i want put these 3 set /p in one single line, filling only this single line.
I tried this way:
set dd=%%a
set mm=%%b
set aa=%%c
set /p "test= "!dd! !mm! !aa!
echo %%a / %%b / %%c
pause
Also tried:
set /p "dd=Type the day: " / &set /p "mm=Type the month " &set /p "aa=Type the year "
But unfortunatelly didn't worked. The second way worked line by line.
Edit 1:
Follow my final script to change the Windows date by batch command:
#echo off
setlocal enableextensions
setlocal EnableDelayedExpansion
cd /d "%~dp0"
mode 42,12
:begin
cls
echo ------------------------------------------
echo MUDAR A DATA DO WINDOWS
echo ------------------------------------------
echo( &echo(
echo 1 - Escolher a data & echo( &echo 2 - Retornar para a data atual
echo( & echo( &echo(
choice /n /c:12 /m "Digite uma op‡Æo:"%1
call :lab%errorlevel%
:lab 1
cls
for /F %%a in ('echo prompt $H ^| cmd') do set "BS=%%a"
for /F %%a in ('copy /Z "%~F0" NUL') do set "CR=%%a"
set /P "=Digite a data: / / !CR!Digite a data: " < nul
call :GetDigits 2 3 Day=
set /P "=.%BS% / " < nul
call :GetDigits 2 1 Mon=
set /P "=.%BS% / " < nul
call :GetDigits 4 2 Year=
echo/
echo/
net stop w32time >nul 2>nul
sc config w32time start= disabled >nul 2>nul
date %Day%-%Mon%-%Year% <nul && (
echo Data modificada: %Day%/%Mon%/%Year%
timeout /nobreak /t 2 >nul 2>nul
goto begin
) || (
cls & echo Erro ao mudar a data.
echo( &echo( &echo(
pause
goto begin
)
:GetDigits HowMany FirstLimit Result=
setlocal EnableDelayedExpansion
set "digits=123456789"
set "%3="
choice /C "0!digits:~0,%2!" /N > nul
set /A digit=%errorlevel%-1
set /P "=%digit%" < nul
set "%3=!%3!%digit%"
for /L %%i in (2,1,%1) do (
choice /C "0%digits%" /N > nul
set /A digit=!errorlevel!-1
set /P "=!digit!" < nul
set "%3=!%3!!digit!"
)
for %%a in (!%3!) do endlocal & set "%3=%%a"
exit /B
:lab2
sc config w32time start= demand >nul
net start w32time >nul 2>nul
cls & w32tm /resync >nul 2>&1
echo Data atual retornada.
timeout /nobreak /t 2 >nul 2>nul
cls & goto begin
No comments... ;)
#echo off
setlocal EnableDelayedExpansion
for /F %%a in ('echo prompt $H ^| cmd') do set "BS=%%a"
for /F %%a in ('copy /Z "%~F0" NUL') do set "CR=%%a"
set /P "=Enter the date: DD / MM / YYYY!CR!Enter the date: " < nul
call :GetDigits 2 3 Day=
set /P "=.%BS% / " < nul
call :GetDigits 2 1 Mon=
set /P "=.%BS% / " < nul
call :GetDigits 4 2 Year=
echo/
echo/
echo Result: %Day%/%Mon%/%Year%
goto :EOF
:GetDigits HowMany FirstLimit Result=
setlocal EnableDelayedExpansion
set "digits=123456789"
set "%3="
choice /C "0!digits:~0,%2!" /N > nul
set /A digit=%errorlevel%-1
set /P "=%digit%" < nul
set "%3=!%3!%digit%"
for /L %%i in (2,1,%1) do (
choice /C "0%digits%" /N > nul
set /A digit=!errorlevel!-1
set /P "=!digit!" < nul
set "%3=!%3!!digit!"
)
for %%a in (!%3!) do endlocal & set "%3=%%a"
exit /B
This is the closest to what you want. It requires the choice command.
There's still a blinking curser that is mildly annoying but you can solve that with third party commands if you wish.
#echo off
choice /c "1234567890" /m "__/__/__" /n
set x1=%errorlevel%
if errorlevel 10 set x1=0
cls
choice /c "1234567890" /m "%x1%_/__/__" /n
set x2=%errorlevel%
if errorlevel 10 set x2=0
cls
choice /c "1234567890" /m "%x1%%x2%/__/__" /n
set x3=%errorlevel%
if errorlevel 10 set x3=0
cls
choice /c "1234567890" /m "%x1%%x2%/%x3%_/__" /n
set x4=%errorlevel%
if errorlevel 10 set x4=0
cls
choice /c "1234567890" /m "%x1%%x2%/%x3%%x4%/__" /n
set x5=%errorlevel%
if errorlevel 10 set x5=0
cls
choice /c "1234567890" /m "%x1%%x2%/%x3%%x4%/%x5%_" /n
set x6=%errorlevel%
if errorlevel 10 set x6=0
cls
echo Date - %x1%%x2%/%x3%%x4%/%x5%%x6%
pause>nul
If the system is a supported Windows platform, PowerShell can be called from a .bat file script to present a GUI calendar for date selection. Place the .ps1 script in the same directory as the .bat script. Adapted from https://learn.microsoft.com/en-us/powershell/scripting/samples/creating-a-graphical-date-picker?view=powershell-6
=== guical.bat
set "THEDATE="
for /f "delims=" %%d in ('powershell -NoLogo -NoProfile -File "%~dp0guical.ps1"') do (
set "THEDATE=%%~d"
)
if "%THEDATE%" == "" (
echo No date selected.
) else (
echo Selected date is %THEDATE%
)
=== guical.ps1
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object Windows.Forms.Form -Property #{
StartPosition = [Windows.Forms.FormStartPosition]::CenterScreen
Size = New-Object Drawing.Size 233, 270
Text = 'Select a Date'
Topmost = $true
}
$calendar = New-Object Windows.Forms.MonthCalendar -Property #{
ShowTodayCircle = $false
MaxSelectionCount = 1
}
$form.Controls.Add($calendar)
$OKButton = New-Object Windows.Forms.Button -Property #{
Location = New-Object Drawing.Point 38, 200
Size = New-Object Drawing.Size 75, 23
Text = 'OK'
DialogResult = [Windows.Forms.DialogResult]::OK
}
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)
$CancelButton = New-Object Windows.Forms.Button -Property #{
Location = New-Object Drawing.Point 113, 200
Size = New-Object Drawing.Size 75, 23
Text = 'Cancel'
DialogResult = [Windows.Forms.DialogResult]::Cancel
}
$form.CancelButton = $CancelButton
$form.Controls.Add($CancelButton)
$result = $form.ShowDialog()
if ($result -eq [Windows.Forms.DialogResult]::OK) {
$date = $calendar.SelectionStart
Write-Host "$($date.ToString('MM\/dd\/yyyy'))"
}
You could also use powershell directly from a for loop in your batch-file, if it suits your purpose better:
Something like this may be adequate; the end user is prompted to enter the date in a specific format, and continues only when PowerShell recognises the input as a valid date:
#Echo Off
Set "Input="
For /F "Tokens=*" %%A In ('PowerShell -NoP^
"$d=$Null;While(1){Try{$d=[DateTime](Read-Host 'Date [dd/MM/yyyy]')"^
";Break}Catch{}};$d.ToString('dd/MM/yyyy')" 2^>Nul')Do Set "Input=%%A"
Set Input 2>Nul&Pause

How to ask a question but only able to write numbers?

set PenaltyLimit = 0
:NewPass
echo Create a penalty limit
set/p "NewPenaltyLimit=>"
--> if %NewPenaltyLimit%==Numbers?? do (
#echo %NewPenaltyLimit% >> File/PenaltyLimit.txt)
FOR /F "usebackq tokens=* delims=" %%W in ("File/PenaltyLimit.txt") do SET PenaltyLimit=%%W
goto lock
:Fail2
#set /a penalty = %penalty% + 1
if %penalty%==%penaltylimit% goto DELETE
goto FAIL
What would you put in exchange for the line with the "-->"
Instead of breaking the batch file, writing something random, is it possible that you could somehow either stop someone entirely from writing anything but numbers or make it so the batch file will only read numbers? (Someone what example above this text)
#echo off
setlocal
:NewPass
echo Create a password
set/p "newpass=>" || goto :NewPass
:NewPenaltyLimit
cls
echo Create a penalty limit, Numbers only
set /p "NewPenaltyLimit=>" || goto :NewPenaltyLimit
set "NewPenaltyLimit=%NewPenaltyLimit:"=%"
if not defined NewPenaltyLimit goto NewPenaltyLimit
for /f "delims=1234567890" %%A in ("%NewPenaltyLimit%") do goto NewPenaltyLimit
cls
ping localhost -n 2 > nul
echo You chose %NewPenaltyLimit% goto lock
If you delimit the value of %NewPenaltyLimit% by integers
of 1234567890, the do goto :newPass should only happen
if characters other than integers exist.
Due to possibility of double quotes being input to the set /p prompt
which could cause a syntax error when expanded as text when the code
is parsed.
The double quotes will be substituted (removed) from the input value
immediately after input. This means that "86" will become 86 and
will be accepted as a valid number.
Example values:
a1 delimited creates a token with value of a which causes
the goto :NewPenaltyLimit to happen.
12 delimited creates no token as 1 and 2 are both delimiters.
If Delayed Expansion is allowed to be enabled.
This version can handle the input without removing double quotes:
#echo off
setlocal
:NewPass
echo Create a password
set/p "newpass=>" || goto :NewPass
:NewPenaltyLimit
cls
echo Create a penalty limit, Numbers only
set /p "NewPenaltyLimit=>" || goto :NewPenaltyLimit
setlocal enabledelayedexpansion
for /f "delims=1234567890" %%A in ("!NewPenaltyLimit!") do (
endlocal
goto NewPenaltyLimit
)
endlocal
cls
ping localhost -n 2 > nul
echo You chose %NewPenaltyLimit% goto lock
Delayed Expansion is only needed for only the for loop,
so this may be a better version.
!NewPenaltyLimit! is not expanded in the code when the code is parsed,
which means an input such as "86" will not cause error and will not be
accepted as a vaild number, as it has double quotes.
References:
View for /? for more helpful information.
View set /? for the information about substitution used in this answer.
View setlocal /? and if /? about Delayed Expansion.
You can try with embedding a powershell code:
<# : batch portion
#echo off & setlocal
for /f "tokens=*" %%a in ('powershell -noprofile "iex (${%~f0} | out-string)"') do set "number=%%a"
echo you've entered %number%
endlocal
goto :EOF
: end batch / begin powershell #>
do {
[Console]::Error.Write("Enter a number:")
$inputString = read-host
$value = $inputString -as [Double]
$ok = $value -ne $NULL
if ( -not $ok ) {[Console]::Error.WriteLine("You must enter a numeric value") }
}
until ( $ok )
write-host "$value"
One advantage is that this can support few types as Integer,Double,Unsigned integer and so on (in this case it is Double.)
You can try also with embedded jscript code (can be used on old XP machines):
#if (#X) == (#Y) #end /* JScript comment
#echo off
for /f "tokens=*" %%a in ('cscript //E:JScript //nologo "%~f0" "%~nx0" %* ') do set "number=%%a"
echo you've entered %number%
exit /b %errorlevel%
#if (#X)==(#Y) #end JScript comment */
WScript.StdErr.Write("Enter a number:");
WScript.StdIn.Read(0);
var strMyName = WScript.StdIn.ReadLine();
var num=parseInt(strMyName);
while(isNaN(num)){
WScript.StdErr.Write("Enter a number:");
WScript.StdIn.Read(0);
var strMyName = WScript.StdIn.ReadLine();
var num=parseInt(strMyName);
}
WScript.StdOut.WriteLine(num);
You can't use spaces around == comparisions. Your code says if %NewPenaltyLimit%<space>==<space>Numbers?? which will never match.

Batch: list available hard drives and work with chosen option

I would like to list all available, removable hard drives in a batch script and continue to work with the chosen option. I know there are options like
wmic logicaldisk get caption,volumename
to list the hard drives and
SET /P M=Type 1 or 2 then press ENTER:
IF %M%==1 GOTO One
IF %M%==2 GOTO Two
to create a menu. But how do I store the volumes in variables and list them in a menu?
Something like:
Choose from list:
1) D:\Harddrivename1
2) E:\Harddrivename2
Enter option: 2
Any help is appreciated!
Here's a function that'll let you create an array of drives that are not of type 3 (fixed):
rem // populates arrayname, arrayname.length, and arrayname.ubound
:getRemovableDrives <arrayname>
rem // unset array if exists
for /f "delims==" %%I in ('2^>NUL set %~1') do set "%%~I="
setlocal enabledelayedexpansion
set /a %~1.length = 0, %~1.ubound = -1
rem // note: nested for /f loops convert UCS-2 encoded WMI results to ANSI
for /f "skip=2 delims=" %%# in (
'wmic logicaldisk where "DriveType <> 3" get caption^,volumename /format:csv'
) do for /f "tokens=2,3 delims=," %%I in ("%%~#") do (
set "%~1[!%~1.length!].caption=%%~I"
set "%~1[!%~1.length!].volumename=%%~J"
set /a %~1.ubound = %~1.length, %~1.length += 1
)
rem // Trick to make private variables public
for /F "delims=" %%I in ('set %~1') do (
if defined %~1.ubound endlocal
set "%%~I"
)
exit /b
Here's a full example illustrating how to use the function:
#echo off & setlocal enabledelayedexpansion
:begin
call :getRemovableDrives drives
if %drives.length% equ 0 (
echo No removable drives found.
exit /b 1
)
set choices=
echo Removable drives:
echo;
for /L %%I in (0, 1, %drives.ubound%) do (
set "choices=!choices!%%I"
echo(%%I^) !drives[%%I].caption! (!drives[%%I].volumename!^)
)
echo(X^) exit
set "choices=%choices%x"
echo;
choice /C %choices% /N /M "Press a number (or X to quit): "
set /a choice = %ERRORLEVEL% - 1
if not defined drives[%choice%].caption exit /b 0
echo You chose !drives[%choice%].caption! (!drives[%choice%].volumename!^)
goto :begin
goto :EOF
rem // populates arrayname, arrayname.length, and arrayname.ubound
:getRemovableDrives <arrayname>
rem // unset array if exists
for /f "delims==" %%I in ('2^>NUL set %~1') do set "%%~I="
setlocal enabledelayedexpansion
set /a %~1.length = 0, %~1.ubound = -1
rem // note: nested for /f loops convert UCS-2 encoded WMI results to ANSI
for /f "skip=2 delims=" %%# in (
'wmic logicaldisk where "DriveType <> 3" get caption^,volumename /format:csv'
) do for /f "tokens=2,3 delims=," %%I in ("%%~#") do (
set "%~1[!%~1.length!].caption=%%~I"
set "%~1[!%~1.length!].volumename=%%~J"
set /a %~1.ubound = %~1.length, %~1.length += 1
)
rem // Trick to make private variables public
for /F "delims=" %%I in ('set %~1') do (
if defined %~1.ubound endlocal
set "%%~I"
)
exit /b
Hopefully you can use this to get you started. In case I guessed incorrectly about the drive type detection, see this page, Ctrl + F and find DriveType on the page.
This might get you started. It is in PowerShell. It gets a list of all removable (non-floppy) drives and presents a list for the user to chose from. If there is only one drive, it does not present the menu.
There is much to be done. There is no range or error checking on the user's input. And, of course, it is not stated what you want to do with the drive.
$drivelist = #(Get-WMIObject Win32_LogicalDisk -Filter "MediaType = 11")
if ($drivelist.Count -eq 0) { Write-Host 'There are no removable drives.'
} elseif ($drivelist.Count -eq 1) { $thedrive = $drivelist[0]
} else {
Write-Host 'Removable drives'
$i = 1
foreach ($drive in $drivelist) {
Write-Host $('{0}. {1} {2}' -f $i, $drive.DeviceId, $drive.VolumeName)
$i += 1
}
$dn = Read-Host -Prompt 'Enter the drive number.'
$thedrive = $drivelist[$dn - 1]
}
# At this point, $thedrive is a System.Management.ManagementObject#root\cimv2\Win32_LogicalDisk
# ready to be used for something.
$thedrive | Format-List * -Force

Resources