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

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

Related

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 to pass batch file variables to PowerShell script? [duplicate]

This question already has an answer here:
Displaying SET variable
(1 answer)
Closed 3 years ago.
I am attempting to pass a number of variables processed by my batch file to a Powershell script. The problem I face is that firstly the entire results from the batch file come up in command prompt and next to the variables I intend to pass are not passed to the Powershell Script. Additionally, the variable I have to output the contents of the log file in just send the command back to the screen.
I have tried the following links and these links got me as far as I am now:
Batch file to execute a Powershell script
Pass variable from batch to powershell
Pass parameter from a batch file to a PowerShell script
Pass batch variables with spaces in them to powershell script?
Batch File side
set LOG_FILE = "GDGAGnklasj;oks;fk;dkf lkl;"
set oName = Name
set oStart = "%YYYY%%MM%%DD% %TIME%"
set oStatus = 0
set oEnd = "%YYYY%%MM%%DD% %TIME%"
set oDateRan = %YYYY%%MM%%DD%
set oLog =for /f "delims=" %%i in (%LOG_FILE%) do set content=%content% %%i
echo Updating Database >> %LOG_FILE% 2>&1
cmd /S powershell.exe -ExecutionPolicy Bypass -File "C:\Reporting\updateTool.ps1" "%oName%" "%DateRan%" "%oStart%" "%oEnd%" "%oStatus "%oLog%
PowerShell Script
param (
[string]$oName
)
"This is $oName"
My intent is to set the variables within the batch file then send them to Powershell for processing.
Be very careful of spaces.
set oName=taco
PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "& '.\ScriptName.ps1' -oName '%oName%' "
Oh Easy-Peasy, I do this for my Power shells that we need CMD wrappers for quite a bit.
I have to run to the train so this is going to be a bit meh at the moment I will firm it up in a bit, right now just going to paste in some example code so I can make it your code
Okay, what, umm, what did you intend for this Particular code to.l do ? I can't seem to figure out what you were intending with this, is it just some dummy code?
set oLog =for /f "delims=" %%i in (%LOG_FILE%) do set content=%content% %%i
echo Updating Database >> %LOG_FILE% 2>&1
Okay on further review I think you want to read the log into a couple of sttring variables in CMD, then use one of them in your call of the script..... but, why?
The strings will append to each other and you will be limited to 8191 characters max, and PowerShell can easily read the content of the log file because you pass the name to Powershell.
That seems like a better plan, no?
All your code where you have YYYY MM DD those are variables you will need to define before using, not sure if that is understood if so all good.
.CMD Script:
#(
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO OFF
SET "_PSScript=C:\Reporting\UpdateTool.ps1"
REM SET "_DebugPreference=Continue"
SET "_DebugPreference="SilentlyContinue"
SET "_LOG_FILE=GDGAGnklasj;oks;fk;dkf lkl;"
SET "_oName=Name."
SET "_oStart=%YYYY%%MM%%DD% %TIME: =0%"
SET /a "_Status=0"
SET "_oEnd=%YYYY%%MM%%DD% %TIME: =0%"
SET "_oDateRan=%YYYY%%MM%%DD%"
)
SET "_PSCMD=Powershell "%_PSScript%" -DebugPreference "%_DebugPreference%" -LOG_FILE "%_LOG_FILE%" -oName "%_oName%" -oStart "%_oStart%" -Status %_Status% -oEnd "%_oEnd%" -oDateRan "%_oDateRan%" "
%_PSCMD% 2>&1 >> "_LOG_FILE"
PS1:
## Script: UpdateTool.ps1
#
param(
[String]$LOG_FILE = 'c:\admin\default.log',
[String]$oName = 'default name'
[String]$oStart = $(Get-date -F "yyyyMMdd HH:mm:ss.ms"),
[Int]$oStatus = 0,
[String]$oEnd = $(Get-date -F "yyyyMMdd HH:mm:ss.ms"),
[String]$oDateRan = $(Get-date -F "yyyyMMdd"),
$DebugPreference = "SilentlyContinue"
)

Double quotes not escaping from string when calling Powershell command from within Batch script?

Double quotes structure is not retained in my test message when passed through a powershell instance called through a batch script, as detailed below:
set test={"this":"is","a":"test"}
FOR /F "delims=" %%i in (' powershell -Command "& {$message = '%test%'; echo $message}" ') DO SET message=%%i
echo %test%
echo %message%
the output is as follows:
{"this":"is","a":"test"}
{this:is,a:test}
I would like to retain the quotes to further process the string in powershell, but as you can see, they are stripped when introduced into the $message variable.
Any insight as to how I might fix this?
Echoing %test% containing double quotes inside the d-quoted powershell command will break the enclosing d-quotes.
One way to overcome this, is using batch string substitution to escape the inner d-quotes with a backslash on the fly
:: Q:\Test\2019\04\25\SO_55855412.cmd
#Echo off
set "test={"this":"is","a":"test"}"
FOR /F "delims=" %%i in ('
powershell -Command "& {$message = '%test:"=\"%'; echo $message}"
') DO SET "message=%%i"
echo %test%
echo %message%
returns here:
> SO_55855412.cmd
{"this":"is","a":"test"}
{"this":"is","a":"test"}
Another solution is to NOT pass %test% as an argument, but to get the variable from the inherited environment
powershell -Command "& {$message = $env:test; echo $message}"
Sadly this doesn't work to pass a variable back, as on terminating the spawned app the inherited environment is discarded.

How to replace the given line of text file in looping structure using windows batch file

set instance=3
for /L %%A in (1,1,%instance%) do (
set /p var=LogfileName: trial.txt
set rep=LogfileName: logfile.txt
echo %var%
powershell -Command "(gc InputFile.txt) -replace '%var%', '%rep%' | Out-File InputFile.txt"
)
I am not able to replace the line in text file using this commands. And also I am not getting how to take the line number and store the string in that particular lile in file into a batch file variable.
% variables in batch files are expanded at parse time (when the statement is read). Since the entire for statement, including the action block, is read as one statement, %var% and %rep% are expanded before the loop is executed, meaning they evaluate to empty strings.
To have the variables inside the loop expanded at execution time you need to enable delayed expansion and use ! notation:
setlocal EnableDelayedExpansion
set instance=3
for /L %%A in (1,1,%instance%) do (
set /p var=LogfileName: trial.txt
set rep=LogfileName: logfile.txt
echo !var!
powershell -Command "(gc InputFile.txt) -replace '!var!', '!rep!' | Out-File InputFile.txt"
)
For further explanation see Raymond Chen's blog.

Using output from a PowerShell command in a windows batch file

I have a path in variable (script parameter) %2.
I need to do the following:
Extract the leaf (last folder from the path) to a variable.
Run the following command: robocopy %2 \\somepath\%leaf
I was told this could be done in PowerShell (cause I've tried going with batch file alone and failed miserably) Here's a pseudocode representation of what I'd like to achieve:
set leaf = powershell -command (split-path %2 -leaf)
robocopy %2 \\somepath\%leaf
Any idea how to write this correctly?
Thank you.
Whenever you want to set a batch variable to the output of a command, use for /f. Here's an example:
#echo off
setlocal
set "psCommand=powershell -command "(split-path '%~2' -leaf)""
for /f "delims=" %%I in ('%psCommand%') do set "leaf=%%I"
echo %leaf%
But this is a terribly inefficient way to retrieve the last folder of a path. Instead of invoking PowerShell, what you should do is this:
#echo off
setlocal
for %%I in ("%~2") do set "leaf=%%~nxI"
echo %leaf%
The %%~dpnxI notation gets
d = drive
p = path
n = name
x = extension
It's traditionally intended for files, rather than directories; but it works just as well for directories anyway. See the last couple of pages of for /? in a console window for complete details.
FOR %%a IN ("%~2") DO FOR %%b IN ("%%~dpa.") DO ECHO %%~nxb
Batch one-liner. Take the parameter (second parameter here), remove any quotes and re-apply them. Select the drive and path, add '.' then select the name and extension of the result making leaf required.
Obviously, if you require this in a variable,
FOR %%a IN ("%~2") DO FOR %%b IN ("%%~dpa.") DO set "leaf=%%~nxb"