【问题标题】:Calling PowerShell from batch, and retrieving the new value of a temporary environment variable set in the script?从批处理中调用 PowerShell,并检索脚本中设置的临时环境变量的新值?
【发布时间】:2010-08-05 11:42:02
【问题描述】:

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

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

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

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

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

这可能吗?

提前致谢:)

尼克

【问题讨论】:

    标签: scripting powershell variables batch-file environment


    【解决方案1】:

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

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

    有点尴尬,但确实有效:

    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
    

    【讨论】:

    • 另外,如果您在批处理文件中而不是从命令行运行此代码,则需要在变量名前使用双百分号(即将 %v 更改为 %%v在上面的例子中的两个地方)。
    • 如果您想了解更多详情,您可以在blogs.msdn.microsoft.com/oldnewthing/20120731-00/?p=7003看到他们
    【解决方案2】:

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

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

    :: 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
    

    现在,作为一个使用它的例子:

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

    这将显示在控制台屏幕上你知道了

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

    假设我们要检查 VM 是 Up 还是 Down,这意味着它是打开还是关闭,所以我们可以执行以下操作:

     :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
    

    现在,如何使用 :CheckMachineUpOrDown 函数?

    只要按照这个例子:

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

    如果 VM 开机,则显示 Up;如果机器关闭,则显示 Down。

    希望这有帮助。

    谢谢

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 不错的解决方案。我怀疑还有其他的东西如此简单明了。
      • 感谢您的回复,但我认为以上方法行不通?在这种情况下,我期望发生的是环境变量 'd' 的值将是 'powershell -noprofile "& { get-date }"'。 IE:不计算表达式右侧的内容。
      • @Nicholas,你是对的。我现在已经尝试过了,变量中实际上只存储了字符串。
      • 噢!如果只有 CMD 像 PowerShell 一样简单。好事@zdan 覆盖了 cmd.exe 方面,因为我使用 cmd.exe 的唯一目的是运行命令行实用程序和其他人的批处理文件。 :-)
      • 一旦你搞定了“for”命令的变幻莫测,CMD 实际上会变得有用(尽管只有在 powershell 不可用的情况下)。
      猜你喜欢
      • 2023-03-21
      • 2018-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多