Batch knowing its invoker: cmd.exe or powershell? - powershell

I wonder how to check if a batch file is executed by cmd.exe or instead by powershell
I discovered that the ENV variable %CmdCmdLine%is set to something in cmd.exe and should not be set inside a powershell shell.
But if I run a batch file in powershell it temporary assumes a value like C:\WINDOWS\system32\cmd.exe /c ""C:\path\to\check-interpreter.bat""
Given also the inability of batch to check IF PATTERN I cannot find a way to let my batch file be able to know which command interpreter is running.
In the below code I tried to use findstr /R to check cmd at the start of the line. Infact inside cmd.exe the line should start with cmd.exe ... while in powershell should start with the full path C:\WINDOWS\system32\cmd.exe /c ...
Here my attempt:
#ECHO OFF
FOR /F "tokens=* USEBACKQ" %%F IN (`echo %CmdCmdLine% ^^^| findstr /R
"^cmd"`) DO (
SET var=%%F
)
ECHO var set to: %var%
REM IF [%var%]==[] ECHO var set to: %var%
IF DEFINED var (
ECHO CmdCmdLine founnd!
ECHO VAR : %var%
ECHO COMMANDLINE: %CmdCmdLine%
) ELSE (
ECHO CmdCmdLine NOT found..
)
The problem in the above code is that var is not populated at all:
# cmd.exe
C:\path\to>.\check-interpreter.bat
CmdCmdLine founnd!
COMMANDLINE: "C:\WINDOWS\system32\cmd.exe"
# powershell
PS C:\path\to> .\check-interpreter.bat
CmdCmdLine founnd!
COMMANDLINE: C:\WINDOWS\system32\cmd.exe /c ""C:\path\to\check-
interpreter.bat""

Related

How to use a PowerShell function return as a variable in a batch file

I was trying to use the return from myPowershellScript.ps1 to use as a variable in my batch file.
myPowershellScript.ps1
function GetLatestText
{
return "Hello World"
}
I was trying to use the For /F function. There may be a better way.
myBatch.bat
for /f "delims=" %%a in (' powershell -command "\\Rossi2\Shared\myPowershellScript.ps1" ') do set "var=%%a"
echo %var%
Desired output, would be to have 'Hello World' output in the cmd window.
I was trying to use the batch file as some old processes use them. For newer processes I do everything in PowerShell and it works fine.
The current output is blank.
Your syntax for trying to capture output from a PowerShell script from a batch file is correct (assuming single-line output from the script),[1] except that it it is more robust to use the -File parameter of powershell.exe, the Windows PowerShell CLI than the -Command parameter.
See this answer for when to use -File vs. -Command.
Your problem is with the PowerShell script itself:
You're defining function Get-LatestText, but you're not calling it, so your script produces no output.
There are three possible solutions:
Place an explicit call to Get-LatestText after the function definition; if you want to pass any arguments received by the script through, use Get-LatestText #args
Don't define a function at all, and make the function body the script body.
If your script contains multiple functions, and you want to call one of them, selectively: in your PowerShell CLI call, dot-source the script file (. <script>), and invoke the function afterwards (this does require -Command):
for /f "delims=" %%a in (' powershell -Command ". \"\\Rossi2\Shared\myPowershellScript.ps1\"; Get-LatestText" ') do set "var=%%a"
echo %var%
[1] for /f loops over a command's output line by line (ignoring empty lines), so with multiline output only the last line would be stored in %var% - more effort is needed to handle multiline output.
You can combine the batch and the powershell in single file (save this as .bat ):
<# : batch portion
#echo off & setlocal
for /f "tokens=*" %%a in ('powershell -noprofile "iex (${%~f0} | out-string)"') do set "result=%%a"
echo PS RESULT: %result%
endlocal
goto :EOF
: end batch / begin powershell #>
function GetLatestText
{
return "Hello World"
}
write-host GetLatestText

Getting a variable from a powershell script, in a batch file

I have seen some similar questions on this here on stack overflow, but I cannot get any of the answers to far to work.
I have this .ps1 file that mounts a drive and echos the drive letter (expected $driverLetter = "G" || "H" || "I"):
$mountDisk = Mount-DiskImage -ImagePath $args[0] -Passthru
$driveLetter = ($mountDisk | Get-Volume).DriveLetter
echo $driveLetter
I'm running it from this batch file:
FOR /F "usebackq delims=" %%i IN (`powershell -File ./mountDisk.ps1 "%1"`) DO SET "d=%%i"
Echo %d%
Each time I get an empty variable. I've tried setting environment variables, but yield same result.
Here's how I'd probably do it, assuming that the initial path passed to the batch file is double-quoted as necessary.
#Echo Off & SetLocal EnableExtensions & Set "ISODrv="
If /I Not "%~x1" == ".iso" (Exit /B 1) Else For %%G In ("%~1") Do If "%%~aG" GEq "d" Exit /B 2
For /F %%G In ('%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -Command "(Mount-DiskImage -ImagePath \"%~1\" -PassThru | Get-Volume).Driveletter" 2^>NUL') Do Set "ISODrv=%%G"
If Not Defined ISODrv (Exit /B 3) Else Echo %ISODrv%
Doing it this way eliminates the need for pre-creating a PowerShell script, and then any subsequent modifications to the execution policy. It only proceeds with the image mount if the received input value was an existing ISO file too. If you're running this batch file from a process which retrieves its exit code, 1 means that the input did not end with the case insensitive string .iso, 2 would mean that the input did end with the case insensitive string .iso, but it was a directory, not a file, and 3 would indicate that there was an error returning the mounted ISO image drive letter.
Try the following to run the cmd from the PowerShell and pathing their variables to it
# The command to pass to cmd.exe /cript
$var = "echo hello world & ping $ip & pause"
$ip = "192.168.1.1"
$var2 = "ping $ip & pause"
# Start the process asynchronously, in a new window,
# as the current user with elevation (administrative rights).
# Note the need to pass the arguments to cmd.exe as an *array*.
Start-Process -Verb RunAs cmd.exe -Args '/c', $var2, $var

how do i search for a file and when found set the file path to a variable in a batch script

I am trying to create a batch file that will run and open a Powershell script to then run.
this is what i have so far
#echo off
for /r C:\folder %%a in (*) do if "%%~nxa"=="2WNRN4VMS2.txt" set p=%%~dpnxa
if defined p (
echo %p%
) else (
echo File not found
Pause
)
Powershell.exe -Command "& '%p%'"
exit
That is very simple using command DIR for searching for the file recursively in folder C:\folder and all its subfolders and command FOR for assigning the drive and path of found file to an environment variable:
#echo off
for /F "delims=" %%I in ('dir /A-D /B /S "C:\folder\2WNRN4VMS2.txt" 2^>nul') do set "FilePath=%%~dpI" & goto FoundFile
echo File not found
pause
goto :EOF
:FoundFile
Powershell.exe -Command "& '%FilePath%'"
Please note that the string assigned to environment variable FilePath ends with a backslash. Use in PowerShell command line %FilePath:~0,-1% if the path of the file should be passed without a backslash at end.
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.
dir /?
echo /?
for /?
goto /?
pause /?
set /?

teamcity command line interpretter : quotes are replaced

I need to run a simple command line within teamcity
FINDSTR /M /N /P /S /R /C:"goto end" D:\blabla\*
The double quote are replaced and somehow doubled when teamcity calls the command. The resulting command is
cmd.exe /c FINDSTR /M /N /P /S /R "/C:"goto end""
Which fails.
How can I prevent this from happening? The value for param /C requires a param with double quotes in my case. thanks
Put your command in a batch file and call that passing in whatever arguments (if any) you need.
Whenever you do anything like this on windows, always do this :)
Your example:
FINDSTR /M /N /P /S /R /C:"goto end" D:\blabla\*
Works as-is, in TeamCity 2018.1.3, using a Command Line runner with the above specified in the Custom Script section.

Batch file to look for file from today and run another .bat otherwise run vbs and exit

I have a batch file I would like to search a folder for any xlsm file updated today.
If it finds an xlsm file from today, it then runs another bat file. If there is no updated file it should run a .vbs file (to send an email) and then exit.
Currently I have the following:
#echo off
set var=%date:~-10%
dir "*.xlsm"|find "%var%">nul&&CALL Update.bat||EXIT
I think I probably need to include some sort of IF/ELSE instead of the current method, but my skills are lacking..
EDIT:
The actual solution I've gone with, based on the answer from #Monacraft is:
#echo off
forfiles /p C:\ /m *.xlsm /d 0 /c "cmd /c call Update.bat"
if ERRORLEVEL 1 start FailEmail.vbs
If using windows 7 you could do forfiles:
#echo off
set found=FALSE
forfiles /p "C:\...[path to folder]" /m *.xlsm /d +1 /c "cmd /c Echo Updating...&CALL Update.bat&set found=TRUE"
if /i %found%==False (
start email.vbs
) else (
Exit
)
And that should work fine
Mona
This worked for me:
#echo off
forfiles /p C:\ /m *.xlsm /d 0 /c "cmd /c call Update.bat"
if ERRORLEVEL 1 start FailEmail.vbs
I think your code should work - some small changes here.
It will just echo the commands to the screen, for you to test.
One point to consider is that the DIR command will also match *.xls files in the short name.
#echo off
set "var=%date:~-10%"
dir "*.xlsm"|find "%var%">nul && (echo CALL Update.bat) || (echo start failemail.vbs)
pause