Ask for user credentials in Batch file - powershell

I'm trying to figure out how to prompt the user for entering his user credentials and process the password inside a batch file.
After some fair amount of tinkering I came up with the following code:
#echo off
set password=
FOR /F "tokens=* USEBACKQ" %%F IN (`powershell -NoLogo -NoProfile -Command ^(Get-Credential "ag\%username%"^).GetNetworkCredential^(^).password;`) DO (
set password=%%F
)
echo %password%
This works fine if the user enters a non empty password. But if the user enters nothing or simply closes the dialog window by clicking "cancel", the variable "password" suddenly contains the string "ECHO ist ausgeschaltet (OFF)." instead of an empty string.
Does anyone have an idea how I can return an empty string for the password in this case?
Thanks in advance
solid

An environment variable has always a value. If an empty string is assigned then the variable is removed (in the running process).
SET FOO=
The variable FOO is removed with the statement above.
So you need to check if a variable is defined and not empty.
if defined FOO echo FOO:%FOO%
if not defined FOO echo FOO is not defined

In reality password is not defined.
That you got ECHO ist ausgeschaltet (OFF) is the output of the ECHO command, as you call it with no data.
To see the real content, you could use set password or ECHO(, the strange opening parenthesis prevents problems when the content of your variable is empty
...
echo( %password%
set password
Btw. You should use the extended set syntax, to avoid problems with trailing whitepsaces.
set "password="
...
set "password=%%F"

Related

How to make this powershell command work inside a loop in batch?

Trying to find the difference. But when this powershell command is inside in the findstr, it fails. On its own, it returns the correct value. Also, without the loop, it returns the correct value.
echo:!newvalue!| findstr /R "^[0123456789][0123456789]\.[0123456789]$" >nul
if errorlevel 1 (
set newvalue=
) else (
FOR /F "usebackq delims=" %%i IN (`powershell -nop -c "'{0:n1}' -f (%newvalue% - 12.0)"`) DO (SET difference=%%i)
echo %difference%
)
Can anyone figure out what I'm missing/did wrong?
Thanks in advance.
I recommend reading How does the Windows Command Interpreter (CMD.EXE) parse scripts?
Windows command processor replaces all environment variable references using syntax %variable% inside a command block starting with ( and ending with matching ) already on parsing the command line using this command block. This means the command line echo %difference% inside ELSE branch command block of the IF command is modified by cmd.exe before command IF is executed at all. %difference% is replaced by current value of environment variable difference or an empty string in case of environment variable difference is not defined somewhere above the IF condition. In latter case echo  is the command line remaining after parsing the command block and therefore shows status of command echoing instead of the string value assigned to environment variable difference in the command line above. The solution with already enabled delayed environment variable expansion is using echo !difference! in ELSE command block.
A solution for this floating point subtraction without usage of PowerShell can be seen below:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
if defined NewValue goto Validate
:UserPrompt
set /P "NewValue=Enter value between 00.0 and 99.9: "
:Validate
echo:!NewValue!| %SystemRoot%\System32\findstr.exe /R "^[0123456789][0123456789]\.[0123456789]$" >nul
if errorlevel 1 set "NewValue=" & goto UserPrompt
for /F "tokens=1,2 delims=." %%I in ("%NewValue%") do set "PreComma=%%I" & set "PostComma=%%J"
set /A Difference=1%PreComma% - 112
set "Difference=%Difference%.%PostComma%"
echo Difference is: %Difference%
endlocal
After validating that the string assigned to environment variable NewValue indeed consists of two digits, a point and one more digit as requested and expected and described at How can I do a negative regex match in batch?, the floating point number string is split up on . into pre-comma and post-comma number strings.
The pre-comma number is subtracted by 12 using an arithmetic expression. But it must be taken into account that an integer number with a leading 0 is interpreted by cmd.exe on evaluation of the arithmetic expression as octal number. That is no problem for 00 to 07. But 08 and 09 would be invalid octal numbers and so Windows command processor would use value 0 resulting in a wrong subtraction result if simply set /A Difference=PreComma - 12 would have been used in batch file. The workaround is concatenating the string 1 with the pre-comma string to a number string in range 100 to 199 and subtract 112 to get the correct result.
The post-comma value does not need to be modified and so the Difference value is determined finally with concatenating the result of the arithmetic expression with the unmodified post-comma number string.
It is possible to get the Difference value also always with two digits by inserting following additional command lines above echo Difference is: %Difference%:
if %Difference:~0,1% == - (
if %Difference:~2,1% == . set "Difference=-0%Difference:~1%"
) else (
if %Difference:~1,1% == . set "Difference=0%Difference%"
)
This solution avoids also the problem that floating point result of PowerShell is formatted according to region and language settings. For example in Germany and Austria the decimal symbol is , and not . which means the subtraction result output by PowerShell for 15.3 - 12.0 is 3,3 and not 3.3.
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.
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
set /?
setlocal /?
See also single line with multiple commands using Windows batch file.
This is not technically an answer, as you've already received and accepted one a perfectly good one.
It is just to allow you to visualise a method of taking the string from your file, splitting it at the decimal point and subtracting 12, from a whole number greater or equal to 12, (see the accepted answer for whole numbers less than 12), all without 'loops' or PowerShell
#Echo Off
Rem Create a variable from the first line of your file
Set /P "newvalue="<"file.tmp"
Echo [%newvalue%]
Rem Exit if the string 'value' does not exist in '%newvalue%'
If "%newvalue%"=="%newvalue:*value=%" Exit /B
Rem ReSet the variable to everything after the string 'value'
Set "newvalue=%newvalue:*value=%"
Echo [%newvalue%]
Rem ReSet the variable to everything up to the first 'space' character
Set "newvalue=%newvalue: ="&:"%"
Echo [%newvalue%]
Rem ReSet the variable, removing the unneeded leading '=' character
Set "newvalue=%newvalue:~1%"
Echo [%newvalue%]
Rem Set a new variable to the whole number, i.e. everything up to the first '.' character
Set "whole=%newvalue:.="&:"%"
Echo [%whole%]
Rem Set a new variable to the decimal, i.e. everything after the '.' character
Set "decimal=%newvalue:*.=%"
Echo [%decimal%]
Rem Subtract 12 from the whole number
Set /A remainder=100+whole-112
Echo [%remainder%]
Rem ReJoin the variables to show the difference
Echo [%remainder%.%decimal%]
Pause
Obviously in your script proper, you'd only need:
#Echo Off
Set /P "newvalue="<"file.tmp"
If "%newvalue%"=="%newvalue:*value=%" Exit /B
Set "newvalue=%newvalue:*value=%"
Set "newvalue=%newvalue: ="&:"%"
Set "newvalue=%newvalue:~1%"
Set "whole=%newvalue:.="&:"%"
Set "decimal=%newvalue:*.=%"
Set /A remainder=100+whole-112
Echo %remainder%.%decimal%
Pause

How to do a postgres Select statement which contains round brackets in a batch?

I am trying to do a select in to a postgres DB via batch file.
The postgres DB offers a command line interface (psql) where you can pipe in DB commands which is here done in for loop. Look at how pg_cmd is stiched together. The select pd_SelCmd is echoed to pg_SelCall.
In the for statement the command is executed but since the select contains round brackets, they cause a miss interpretation and an error:
"FROM" cant be processed syntactically at this point.
How can the round brackets be kind of escaped to get the request to work?
The expected response from DB looks like:
max
-------------------------
2016-12-29 09:40:09.842
(1 Line)
The batch used so far was this
setlocal enabledelayedexpansion
Set "PgRootPath=C:\Program Files\PostgreSql\9.5.5-1\bin"
Call :GetDoneTime 56665454 DONE_TIME
echo = DONE_TIME=!DONE_TIME!
Goto :EOF
:GetDoneTime
set "ERRORLEVEL="
set "MC_UID=%~1"
set "ReturnDoneTimeValueRef=%~2"
set "DataVal=NULL"
set "PGPASSWORD=frontenduser"
set "PGCLIENTENCODING=utf-8"
set pd_SelCmd=SELECT max(t.endDate) FROM Ticket t JOIN Device d on t.device_id = d.id WHERE t.state in ('APPROVED','IN_PROGRESS', 'IN_ACTIVITY') AND d.uid='!MC_UID!';
set pg_SelCall="!PgRootPath!\psql" -U frontenduser -h localhost -d ppsdb
REM if call to psql produces an fatal error, the error number will be passed to for loop on third parameter in third line
set pg_cmd="echo !pd_SelCmd! | !pg_SelCall! || echo/ & echo/ & call echo NULL NULL %%^^^errorlevel%%"
set "pg_cmd=!pg_cmd:)=^)!"
REM Execute PG command. Resulting DataValue obtained from third row
REM Check for errors of call
for /f "skip=2 tokens=1,2,3" %%i in ('!pg_cmd!') do (
REM Get value in first and second parameter from split - which is from third row
set "DataVal=%%i %%j"
REM If error happend, report it. Error code is obtained in 3rd parameter.
if "!DataVal!"=="NULL NULL" (
echo ## Postgres DB operation failed with ERROR: %%~k
set "DataVal=NULL"
) else (
REM Check if result is not valid
if "!DataVal:~0,1!"=="(" set "DataVal=NULL"
)
goto GotDoneTime
)
:GotDoneTime
if not '!ReturnDoneTimeValueRef!'=='' set "!ReturnDoneTimeValueRef!=!DataVal!"
if "!DataVal!"=="NULL" exit /b 1
exit /b 0
Just a few errors here. Unfortunately, I don't know postgresql, nor do I have the requisite database, so I can't test it, but here goes...
First, labels are not allowed in a code-block (parenthesised series of statements) and :: is a broken label. Within a code block, rem should be used for remarks.
Next, replacing your '!pg_cmd! in the for loop with type q41353737.txt (where q41353737.txt is a file containing the expected data output from the command you posted) then dataval is set to 09:40:09.842 BUT since there is a fourth line in the file, the next line will also be processed and dataval will be set to Line).
To overcome this, you could simply change this to
rem If error happened, report it. Error code is obtained in 3rd parameter.
if not '%%~k'=='' echo ## Postgres DB operation failed with ERROR: %%~k
rem If operation succeeded, get value in second parameter from split - which is from second data column
if '%%~k'=='' SET DataVal=%%~j
goto done
)
:done
so that only the third line is processed and then the for loop is unceremoniously terminated.
Next problem is the problem of which you complain. The ) is terminating the for ... (, so you need to tell cmd that that particular ) is part of the command to be executed, not of the for, so you need to escape it with a caret (( becomes ^))
The easiest way is probably, just before the for to add a line
set "pg_cmd=!pg_cmd:)=^)!"
which should appropriately prefix all ) in the command withh the requisite caret.
I suspect you'll also have trouble with the other problem characters so a similar process applied to | will probably be required, ie.
set "pg_cmd=!pg_cmd:|=^|!"
Which is where I have to leave it, since I've no way of correctly executing the command itself.

Automate batch file prompts with powershell

I have a batch file which prompts the user a few times. I am looking to automate that with powershell. Is there any way to do this? I would need something like this:
Start-Process $InstallDir\Install.bat "y,*,$Version,y,y,y,y,y,y,y,y,y,y,y,y,y"
Install.bat runs an installation and there are a total of 16 prompts. The third I would like the be a variable that I have in my powershell script already, but the others will be static. Also, at the end of the script, you need to press any key to continue.
Is there any way to do this?
Depending on your batch file and what commands actually do the prompt, you might use input redirection <. Put the prompts into a text file pine by line and redirect that into your batch file.
Supposing the batch file prompts.bat contains the following commands...:
#echo off
set /P VAR="Please enter some text: "
echo/
echo Thank you for entering "%VAR%"!
choice /M "Do you want to continue "
if not ErrorLevel 2 del "%TEMP%\*.*"
pause
...and the text file prompts.txt contains the following lines...:
hello world
Y
n
End
...the console output of the command line prompts.bat < prompts.txt would be:
Please enter some text:
Thank you for entering "hello world"!
Do you want to continue [Y,N]?Y
C:\Users\operator\AppData\Local\Temp\*.*, Are you sure (Y/N)?
C:\Users\operator\AppData\Local\Temp\*.*, Are you sure (Y/N)? n
Press any key to continue . . .
(The del command shows two prompts here as it receives the RETURN behind Y which is not consumed by choice; since an empty entry is not accepted, the prompt appears one more time.)
Read-Host will display a prompt for entry, assigning it to a variable means you can then use that entry later in the script.
As your example is non-specific the below will only give you an idea of what you need to do.
$InstallDir = "C:\folder"
$Version = Read-Host -Prompt "Enter Version Number"
Start-Process "$InstallDir\Install.bat" -ArgumentList "y,*,$Version,y,y,y,y,y,y,y,y,y,y,y,y,y"

CMD - If exists <file>

The below commands (with debug lines added - indented) should only redirect the echo's output to a file, should it already exist, according to my understanding.
However, it would seem that if exist %test0% always fills the file (creating it if non-existant) with the echo's output.
Does anyone know what is wrong?
#echo off
type test.bat
set test0="e:\documents and settings\administrator\desktop\test.log"
echo.&echo.
if exist %test0% (echo !!Exists!!) else (echo !!Doesn't Exist!!)
(if exist %test0% echo.&echo.&echo -------------------------------------------------&echo.&echo.)>>%test0%
And the file gets created(!)
EDIT: This above was a simplified example, and unfortunately MSalters answer doesn't help me solve the full command (I had hoped it would). The full one line if statement is:
if exist %test0% (echo.&echo.&echo -------------------------------------------------&echo.&echo.) else (set /p .=<nul)>>%test0%&set errorlevel=0||set errorlevel=1
How would I have whichever condition of the if matched output to the file (Hopefully with only one reference to the file, i.e., not one in each if conditional), and have the errorlevel set based on the existance of the file?
Could anyone help with the actual full command issue?
You should never set ERRORLEVEL directly. That name is reserved for reporting on the results of the prior command. When you set the value directly, you override the intended functionality and it ceases to expand to the actual ERRORLEVEL, it expands to the value you set instead. That can break all kinds of code.
You can force the ERRORLEVEL to a value by running a command with known result, redirecting output to nul if necessary: ver >nul sets ERRORLEVEL to 0, set /p .=<nul sets ERRORLEVEL to 1.
You can force the ERRORLEVEL to any particular value of your choosing by using cmd /c exit /b N, where N is an integral value.
You also have faulty logic. Your IF command succeeds (has no error) regardless whether the condition evaluates to TRUE or FALSE. If you want to set the ERRORLEVEL, then you need to do it within your parenthesized blocks.
There is nothing wrong with putting everything on one line, but I find the code easier to read when using multiple lines for complex statements like yours. I believe the following is what you are looking for.
if exist %test0% (
echo.
echo.
echo -------------------------------------------------
echo.
echo.
ver >nul
) >>%test0% else (
set /p .=<nul
)
Edit in response to comments
Not much change needed.
if exist %test0% (
(
echo.
echo.
echo -------------------------------------------------
echo.
echo.
set ERR=0
) >>%test0%
) else (
copy nul %test0%
set ERR=1
)
Check your parentheses. (x) >> output.log redirects the output of x to output.log. That means the redirection happens regardless of what the output is, and in particular always creates the file.
Now if you'd write if Y (echo Text >> output.log) the redirection would be conditional on Y, and might not happen.
[edit]
With the question as it's worded now, the simple solution seems to be:
Set %ERRORLEVEL% based on exist %test0%. No redirection has happened at this point.
Use %ERRORLEVEL% to determine what to do. You can change %test0% without altering %ERRORLEVEL%.
BTW, ERRORLEVEL is not %ERRORLEVEL%

How to create a user Environment variable that *calls* %date% or %time% each time it's invoked?

I'm trying to create 2 user environment variables with the following defintion:
datel=%date:~-4%%date:~3,2%%date:~0,2%
datetime=%date:~-4%%date:~3,2%%date:~0,2%-%time:~0,2%_%time:~3,2%_%time:~6,2%
so that every time I call:
echo %datel%
echo %datetime%
I get:
20110407
20110407-11_45_45
I can define the user environment variables without problems in the GUI (Computer->(Right Click)Properties->Advanced System Settings->Environment Variables) and when I do a "set" in a new cmd window I get the following:
>set da
datel=%date:~-4%%date:~3,2%%date:~0,2%
datetime=%date:~-4%%date:~3,2%%date:~0,2%-%time:~0,2%_%time:~3,2%_%time:~6,2%
But then "echoing" them is not what I expected:
C:\Users\jaravj
>echo %datel%
%date:~-4%%date:~3,2%%date:~0,2%
C:\Users\jaravj
>echo %datetime%
%date:~-4%%date:~3,2%%date:~0,2%-%time:~0,2%_%time:~3,2%_%time:~6,2%
Thanks a huge lot in advance.
Use call echo %datel% which results in another parsing pass (which you need here). echo by itself will not expand any environment variables, that does the shell upon parsing a line. Therefore you need to force that.
That's undocumented, however, so take that with a grain of salt. A more robust (i.e. actually supported) option might be to use a subroutine:
:expand
echo.%*
goto :eof
and then call it with
call :expand echo %datel%
Or use the delayed expansion, then you are able to expands two times in one line.
setlocal
set "datel=!date:~-4!!date:~3,2!!date:~0,2!"
setlocal EnableDelayedExpansion
echo %datel%
It's works because, first the batch line parser expands %datel% to !date:~-4!!date:~3,2!!date:~0,2! and after all percent expansions are done.
Then the escape characters are handled, and then as the last phase the parser expands the exclamations are expanded.
Explained in how cmd.exe parse scripts