Scripting 从批处理调用PowerShell,并检索脚本中临时环境变量集的新值?

Scripting 从批处理调用PowerShell,并检索脚本中临时环境变量集的新值?,scripting,powershell,variables,batch-file,environment,Scripting,Powershell,Variables,Batch File,Environment,我希望标题简洁,但以防万一: 我正在从批处理文件调用PowerShell脚本。我希望PowerShell脚本设置环境变量的值,并在PowerShell脚本完成时使该新值在批处理文件中可用 我知道可以在PowerShell中使用$env设置环境变量,但当PowerShell脚本终止时,该值不会持续存在。我想这可能是因为PowerShell是在一个单独的进程中执行的 我知道我可以返回退出代码并使用%ErrorLevel%,但这只会给我数字,而且会有冲突,因为1表示PowerShell异常,而不是有用

我希望标题简洁,但以防万一:

我正在从批处理文件调用PowerShell脚本。我希望PowerShell脚本设置环境变量的值,并在PowerShell脚本完成时使该新值在批处理文件中可用

我知道可以在PowerShell中使用$env设置环境变量,但当PowerShell脚本终止时,该值不会持续存在。我想这可能是因为PowerShell是在一个单独的进程中执行的

我知道我可以返回退出代码并使用%ErrorLevel%,但这只会给我数字,而且会有冲突,因为1表示PowerShell异常,而不是有用的数字

现在,这里有一个警告:我不希望环境变量持续存在。也就是说,我不希望为用户或系统定义它,因此我希望它在批处理文件退出后立即不可用。最后,我只想将结果从PowerShell脚本传回调用批处理文件

这可能吗

提前感谢:)


Nick

从PowerShell捕获结果最直接的方法是在PowerShell中使用stdout。例如,这会将日期保存到cmd.exe中的d env var

set d = powershell -noprofile "& { get-date }"

要了解Keith使用stdout工作的想法,可以从批处理脚本中调用powershell,如下所示:

FOR /F "usebackq delims=" %v IN (`powershell -noprofile "& { get-date }"`) DO set "d=%v"
:: 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
有点尴尬,但它是有效的:

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

我知道现在回答这个问题有点晚了,但我想尝试一下,以防有人需要更详细的解决方案。好了,就这样

我创建了一个批处理函数,它将为您执行ps脚本并返回一个值,如下所示:

FOR /F "usebackq delims=" %v IN (`powershell -noprofile "& { get-date }"`) DO set "d=%v"
:: 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
这将显示在控制台屏幕上,你明白了吗

作为一个更复杂的例子,我要补充:

让我们假设我们想检查一个虚拟机是开着还是关着,也就是说它是开着还是关着,所以我们可以执行以下操作:

 :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
如果虚拟机已通电,则显示Up;如果机器已关闭,则显示Down

希望这是有帮助的


谢谢

很好的解决方案。我怀疑还有其他的方法能如此简单和直截了当。谢谢你的回复,但我认为上面的方法行不通吗?在这种情况下,我希望环境变量“d”的值是“powershell-noprofile”&{get date}”。IE:表达式右侧的内容没有计算。@Nicholas,你说得对。我现在已经试过了,实际上变量中只存储了字符串。Doh!要是CMD像PowerShell一样直截了当就好了。好在@zdan已经覆盖了cmd.exe的一面,因为我唯一使用cmd.exe的是运行命令行实用程序和其他人的批处理文件。:-)一旦您关闭“for”命令,CMD实际上会变得有用(尽管只有在powershell不可用的情况下)。此外,如果您在批处理文件中而不是从命令行运行此代码,则需要在变量名称前使用双百分号(即,在上述示例中,在两个位置将%v更改为%%v)。如果您想了解更多详细信息,请访问