【问题标题】:Passing Powershell variable to Windows Batch file将 Powershell 变量传递给 Windows 批处理文件
【发布时间】:2020-02-27 22:54:21
【问题描述】:

由于我的项目及其部署方式的限制,我需要在批处理文件中运行 powershell 命令并从 powershell 脚本中回显一个变量。此脚本通过 RS-232 从电视中检索型号,并以 HEX 格式返回型号。

我编写了脚本,并小心翼翼地将其压缩为一行运行。我什至可以在命令行中使用'powershell -command "[myCondensedScript]"',效果很好

for /F %%a in ('powershell.exe -command "$port = New-Object System.IO.Ports.SerialPort COM1, 9600, none, 8, one;[byte[]] $reqSerial = 1,48,65,48,65,48,54,2,67,50,49,55,3,112,13;[byte[]] $reqModel = 0x01,0x30,0x41,0x30,0x41,0x30,0x36,0x02,0x43,0x32,0x31,0x37,0x03,0x70,0x0D;[byte[]] $response = '';[byte[]] $readData = '';$port.DTREnable = $True;$port.Open();$port.Write($reqModel, 0, $reqModel.Count);$x=0;do {$x++;$readData = $port.ReadChar();If($x -eq 13 -or $x -eq 14 -or $x -eq 15 -or $x -eq 16 -or $x -eq 17 -or $x -eq 18 -or $x -eq 19 -or $x -eq 20 -or $x -eq 21) {$response += $readData;};}while($response.Length -ne 9);$port.Close();$hexResponse = $response.forEach([char]);$hexResponseString = [string]$hexResponse;$hexResponseString = $hexResponseString.replace(' ','');$finalHex = $hexResponseString+0;Write-Host $finalHex;"^; (Get-Variable -ValueOnly -Name finalHex^).value') do set HexCode=%%a

echo %HexCode%

输出很简单

   echo +

预期的输出是

563332330

我不确定变量缺少什么,因为我对变量和批处理文件不是很熟练。我已经广泛搜索并发现此页面有点帮助https://ss64.com/nt/for.html 我只是不明白我如何将 %%a 分配给我想要的确切变量。任何帮助将不胜感激!

【问题讨论】:

    标签: windows powershell batch-file variables command-line


    【解决方案1】:

    您的命令在封闭的'...' 字符串的上下文中嵌入了未转义的' 字符,这将不起作用。

    改为使用usebackq解析选项将命令括在`...`中,这样可以简化引用和转义。

    以下示例命令演示了该技术(要在cmd.exe 提示符而不是从批处理文件中尝试此操作,请将%%a 替换为%a):

    for /f "usebackq delims=" %%a in (`
      powershell -c "$finalHex = '0x68 0x69' -replace '0x| '; $finalHex"
    `) do set "HexNum=%%a"
    echo %HexNum%
    

    上面打印了以下内容,证明嵌入的"..."'...'; 按原样工作(在使用"..." 围绕传递给-c 的PowerShell 命令的封闭引用的上下文中(-Command)作为一个整体,防止cmd.exe解释内容):

    6969
    

    PowerShell's CLI总结usebackq规则

    • "..." 中包含的PowerShell 命令作为一个整体 传递给-c / -Command 参数(在Windows PowerShell中暗示 /em>,但在 PowerShell [Core] 6+ 中必需

      • 由于cmd.exe不解释"..."字符串的内容(%...%环境变量引用除外),cmd.exe元字符(具有特殊句法含义的字符,例如&)可以用作-是。
    • 单引号 (') 可以按原样使用。

    • 如果您需要在整个"..." 命令字符串中嵌入双引号("):

      • 在 PowerShell [Core] 6+ (pwsh.exe) 中,使用 ""
      • 在 Windows PowerShell (powershell.exe) 中,使用 \"",但请注意字符串内部的空格随后将被规范化(折叠成一个单个空格); \" 避免了这种情况,但随后要求您 ^-转义任何 cmd.exe 元字符,例如 &
    for /f "usebackq delims=" %%i in (`
      REM In PowerShell [Core] 6+ (pwsh.exe), use "" instead of \""
      powershell -noprofile -c "(\""hi &    there\"").Replace('i', '@')"
    `) do @echo [%%i]
    

    上面的结果(注意规范化的空白;在 PowerShell [Core] 6+ 和 "" 这不会发生):

    [hi & there]
    

    至于你的具体命令

    • 删除 ^(插入符号),因为 `...` 引用不再需要它们;将传递给powershell -c的命令作为一个整体括在"..."中。

    • 防止污染输出流以确保只返回感兴趣的值,这意味着:

      • 删除Write-Host 命令。

      • $null = ... 放在 $port.Open()$port.Write(...)$port.Close() 调用之前,以确保它们不会隐式创建输出(有关说明,请参阅 this answer) .

    • 只需将$finalHex 单独使用作为最后一条语句即可输出(不需要(Get-Variable ...))。

    【讨论】:

      【解决方案2】:

      我解析了其中的 powershell 部分。最后的两个插入符号 ^ 对我来说没有意义。你能解释一下它们的意义吗?再仔细看看最后一行。

      # Removed " from "$Port below

      $port = New-Object System.IO.Ports.SerialPort COM1, 9600, none, 8, one;
      [byte[]] $reqSerial = 1,48,65,48,65,48,54,2,67,50,49,55,3,112,13;
      [byte[]] $reqModel = 0x01,0x30,0x41,0x30,0x41,0x30,0x36,0x02,0x43,0x32,0x31,0x37,0x03,0x70,0x0D;
      [byte[]] $response = '';[byte[]] $readData = '';$port.DTREnable = $True;
      $port.Open();
      $port.Write($reqModel, 0, $reqModel.Count);$x=0;
      
      do {$x++;$readData = $port.ReadChar();
      
          If($x -eq 13 -or $x -eq 14 -or $x -eq 15 -or $x -eq 16 -or $x -eq 17 -or $x -eq 18 -or $x -eq 19 -or $x -eq 20 -or $x -eq 21) 
          {$response += $readData;};
      
      }
      while($response.Length -ne 9);
      $port.Close();
      
      $hexResponse = $response.forEach([char]);
      $hexResponseString = [string]$hexResponse;
      $hexResponseString = $hexResponseString.replace(' ','');
      $finalHex = $hexResponseString+0;
      Write-Host $finalHex;"^; (Get-Variable -ValueOnly -Name finalHex^).value
      

      【讨论】:

      • 使powershell部分在powershell中工作。查看 Powershell.exe 的“-EncodedCommand”
      • 好问题!我从之前部署的脚本(不是我写的,但有效)中取出了那段,我认为插入符号在那里是为了逃避分号;和结束括号)。让我烦恼的是 begin paren 没有插入符号(。我尝试删除它们并为 begin paren 添加一个,但无济于事。我离开了它们,因为它在以前的部署中有效。不幸的是,以前部署的人没有在这里更长。:(
      【解决方案3】:

      如果这在 powershell 中有效,那么您可以尝试将其放回您拥有的命令行中。

      $port = New-Object System.IO.Ports.SerialPort COM1, 9600, none, 8, one;
      [byte[]] $reqSerial = 1,48,65,48,65,48,54,2,67,50,49,55,3,112,13;
      [byte[]] $reqModel = 0x01,0x30,0x41,0x30,0x41,0x30,0x36,0x02,0x43,0x32,0x31,0x37,0x03,0x70,0x0D;
      [byte[]] $response = '';[byte[]] $readData = '';$port.DTREnable = $True;
      $port.Open();
      $port.Write($reqModel, 0, $reqModel.Count);
      $x=0;
      
      do {$x++;$readData = $port.ReadChar();
      
          If($x -eq 13 -or $x -eq 14 -or $x -eq 15 -or $x -eq 16 -or $x -eq 17 -or $x -eq 18 -or $x -eq 19 -or $x -eq 20 -or $x -eq 21) 
          {$response += $readData;};
      
      }
      while($response.Length -ne 9);
      $port.Close();
      
      $hexResponse = $response.forEach([char]);
      $hexResponseString = [string]$hexResponse;
      $hexResponseString = $hexResponseString.replace(' ','');
      $finalHex = $hexResponseString+0;
      (Get-Variable -ValueOnly -Name finalHex).value
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-05-12
        • 1970-01-01
        • 2023-01-23
        • 2019-11-19
        • 1970-01-01
        • 1970-01-01
        • 2017-08-13
        相关资源
        最近更新 更多