10

I hope the title is concise, but just in case:

I am calling a PowerShell script from a batch file. I want the PowerShell script to set the value of an environment variable, and for that new value to be available in the batch file when the PowerShell script finishes.

I know that it is possible to set an environment variable using $env in PowerShell, but the value does not persist when the PowerShell script terminates. I imagine this is probably because PowerShell gets executed in a separate process.

I am aware that I can return an exit code and use %ErrorLevel%, but that will only give me numbers, and there will be a conflict, since 1 indicates a PowerShell exception rather than a useful number.

Now, here's the caveat: I don't want the environment variable to persist. That is, I don't want it to be defined for the user or system, and therefore I want it to be unavailable as soon as the batch file exits. Ultimately, I simply want to communicate results back from a PowerShell script to the calling batch file.

Is this possible?

Thanks in advance :)

Nick

Nicholas Hill
  • 221
  • 1
  • 2
  • 5

3 Answers3

11

To get Keith's idea of using stdout to work, you can invoke powershell from your batch script like this:

FOR /F "usebackq delims=" %v IN (`powershell -noprofile "& { get-date }"`) DO set "d=%v"

A little awkward, but it works:

C:\>FOR /F "usebackq delims=" %v IN (`powershell -noprofile "& { get-date }"`) DO set "d=%v"
C:\>set d
d=August 5, 2010 11:04:36 AM
zdan
  • 28,667
  • 7
  • 60
  • 71
  • 2
    Also, if you are running this code in a batch file and not from the command line, you will need to use double percent signs in front of your variable name (i.e. change %v to %%v in both places in the example above). – deadlydog Mar 06 '13 at 22:12
  • If you want more details, you can see them at https://blogs.msdn.microsoft.com/oldnewthing/20120731-00/?p=7003 – Arithmomaniac Jul 07 '16 at 16:40
0

I know it's a little bit late to answer this question, but I would like to give it a try just in case any one needs more detailed solution. So, here it goes.

I created a batch function that would execute ps script for you and return a value, something like this:

:: A function that would execute powershell script and return a value from it.
:: <PassPSCMD> pass the powreshell command, notice that you need to add any returning value witth Write-Host
:: <RetValue> the returned value
:RunPS <PassPSCMD> <RetValue>
  Powershell Set-ExecutionPolicy RemoteSigned -Force
  for /F "usebackq tokens=1" %%i in (`Powershell %1`) do set returnValue=%%i
  set "%2=%returnValue%"
Goto:eof
:: End of :RunPS function

Now, as an example to use it:

set psCmd="&{ Write-Host 'You got it';}"
call :RunPS %psCmd% RetValue
echo %RetValue%

This will display on console screen You got it

As a more complicated example, I would add:

Let's assume that we want to check if a VM is Up or Down, meaning if it's powered on or off, so we can do the following:

 :CheckMachineUpOrDown <returnResult> <passedMachineName>
   set userName=vCenterAdministratorAccount
   set passWord=vCenterAdminPW
   set vCenterName=vcenter.somedmain.whatever
   set psCmd="&{Add-PSSnapin VMware.VimAutomation.Core; Connect-VIServer -server %%vCenterName%% -User %userName% -Password %passWord%; $vmServer = Get-VM %2;Write-Host ($vmServer.PowerState -eq 'PoweredOn')}"

   call :RunPS %psCmd% RetValue
   if "%RetValue%" EQU "True" (set "%1=Up") else (set "%1=Down")
 Goto:eof

:: A function that would execute powershell script and return a value from it.
:: <PassPSCMD> pass the powreshell command, notice that you need to add any returning value witth Write-Host
:: <RetValue> the returned value
:RunPS <PassPSCMD> <RetValue>
  Powershell Set-ExecutionPolicy RemoteSigned -Force
  for /F "usebackq tokens=1" %%i in (`Powershell %1`) do set returnValue=%%i
  set "%2=%returnValue%"
  Goto:eof
:: End of :RunPS function

Now, how to use :CheckMachineUpOrDown function?

just follow this example:

set Workstation=MyVMName
call :CheckMachineUpOrDown VMStatus %Workstation%
echo %VMStatus%

This will display Up if the VM is Powered On or Down if the machine is Off.

Hope this is helpful.

Thanks

-2

The most straight forward way to capture results from PowerShell is to use stdout in PowerShell. For example, this saves the date to the d env var in cmd.exe

set d = powershell -noprofile "& { get-date }"
Keith Hill
  • 194,368
  • 42
  • 353
  • 369
  • Nice solution. I doubt there is any other that is so easy and straightforward. – stej Aug 05 '10 at 14:46
  • 2
    Thanks for the response, but I do not think the above will work? What I would expect to happen in this case is that the value of the environment variable 'd' will be 'powershell -noprofile "& { get-date }"'. IE: The contents of the right side of the expression are not evaluated. – Nicholas Hill Aug 05 '10 at 15:02
  • @Nicholas, you are right. I have tried it now and there is really only string stored in the variable. – stej Aug 05 '10 at 15:30
  • Doh! If only CMD were as straight-forward as PowerShell. Good thing @zdan has got the cmd.exe side covered cuz the only thing I ever used cmd.exe for was runnning command line utilities and other people's batch files. :-) – Keith Hill Aug 05 '10 at 21:02
  • once you get the vagaries of the "for" command down, CMD can actually become useful (though only if powershell isn't available). – zdan Aug 06 '10 at 12:08