1

Due to restrictions around my project and how this is being deployed, I need to run a powershell command in a batch file and echo a variable from the powershell script. This scripts retrieves a model number from a TV over RS-232 and returns the model in HEX.

I wrote the script and meticulously condensed it to one line that runs. I can even 'powershell -command "[myCondensedScript]"' in the command line and it works great

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%

The output is simply

   echo +

The expected output would be

563332330

I'm not sure what I'm missing with the variable, as I'm not terribly skilled with variables and batch files. I have googled extensively and found this page to be somewhat helpful https://ss64.com/nt/for.html I just don't understand how I assign %%a to the exact variable I want. Any help would be greatly appreciated!

0

3 Answers 3

1

Your command has unescaped embedded ' characters in the context of the enclosing '...' string, which won't work.

Instead, use the usebackq parsing option and enclose the command in `...`, which simplifies quoting and escaping.

The following sample command demonstrate the technique (to try this at the cmd.exe prompt instead of from a batch file, replace %%a with %a):

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

The above prints the following, proving that embedded "...", '...', and ; worked as-is (in the context of using "..." for the enclosing quoting around the PowerShell command passed to -c (-Command) as a whole, which prevents cmd.exe from interpreting the contents):

6969

To summarize the usebackq rules with PowerShell's CLI:

  • Pass the PowerShell commands enclosed in "..." as a whole to the -c / -Command parameter (which is implied in Windows PowerShell, but required in PowerShell [Core] 6+).

    • Since cmd.exe doesn't interpret the contents of "..." strings (except %...% environment-variable references), cmd.exe metacharacters (characters with special syntactic meaning, e.g., &) can be used as-is.
  • Single quotes (') can be used as-is.

  • If you need to embed double quotes (") inside the overall "..." command string:

    • In PowerShell [Core] 6+ (pwsh.exe), use "".
    • In Windows PowerShell (powershell.exe), use \"", but note that string-internal whitespace will then be normalized (folded into a single space); \" avoids that, but then requires you to ^-escape any cmd.exe metacharacters such as &.
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]

The above yields (note the normalized whitespace; in PowerShell [Core] 6+ with "" this wouldn't happen):

[hi & there]

As for your specific command:

  • Remove the ^ (carets), as they are no longer needed with the `...` quoting; enclose the commands passed to powershell -c as a whole in "...".

  • Prevent pollution of the output stream to make sure that only the value of interest is returned, which means:

    • Remove the Write-Host command.

    • Place $null = ... before the $port.Open(), $port.Write(...), $port.Close() calls to make sure that they do not implicitly create output (see this answer for an explanation).

  • Simply use $finalHex by itself as the last statement in order to output it (no need for (Get-Variable ...)).

Sign up to request clarification or add additional context in comments.

Comments

0

I parsed the powershell part of it. The two carets, ^, at the end do not make sense to me. Can you explain the point of them? Look at the last line a little closer.

# 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

2 Comments

Make the powershell part work in powershell. Look into the "-EncodedCommand" for Powershell.exe
Great Question! I took that piece from a previously deployed script (not written by me, but works) and I assumed the carets were there to escape the semi-colon ; and end paren ). What vexes me is there's no caret for the begin paren (. I tried removing them and adding one for the begin paren, but to no avail. I left them since it's worked in previous deployments. Unfortunately the people that did the previous deployments are no longer here. :(
0

If this works in powershell then you can try to put it back into the command line you have.

$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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.