Solved Piping command output to sub

Various / CUSTOM BUILT
November 17, 2016 at 03:57:41
Specs: Windows 10, Intel i7 4770k, 32GB 1600MHz RAM
I'm working on a tiny script that requires me to pass the stdout of this code:
CERTUTIL -ENCODE "%~1" "%~N1.B64" | FIND /I "ERROR_" && SET ENCODE=1 & ECHO.

to a sub in order to process it further. I tried this:
CERTUTIL -ENCODE "%~1" "%~N1.B64" | FIND /I "ERROR_" && SET ENCODE=1 & ECHO. | CALL :SUB
but I got the error "Invalid attempt to call batch label outside of batch script.".

I also tried using FOR

FOR /F "TOKENS=*" %%A IN (
	'CERTUTIL -ENCODE "%~1" "%~N1.B64" ^| FIND /I "ERROR_" ^&^& SET ENCODE=1 ^& ECHO.'
) DO (
	CALL :SUB "%%A"
)

But %%A is empty.

Is there a different way to go about this?

Don't worry if plan A fails, there are 25 more letters in the alphabet ;)

message edited by RainBawZ


See More: Piping command output to sub

Reply ↓  Report •


✔ Best Answer
November 17, 2016 at 23:50:12
A whole lot of things. I'm not running win-10 (thank God), so I can't do an exact compare, so the rest of this is based on my klunky Win-7 32-bit.
Certutil returns an errorlevel. You can use that to direct the command output. I hate using temp files, so I'll try a "workaround" in this case.
Since the outcome (errorlevel) of command is not determined until completion of command, the command's output must be stored until completion, (each line, within the loop), and the command's errorlevel must also be saved (from inside the for(), NOT the loop). Then if the error occurs, we dump the output, otherwise go merrily on our way and ignore. I tried to use a variable to save the error, but that failed, so I used a string-marker:
:: begin script rain1.bat
@echo off & setlocal enabledelayedexpansion

fOR /F "TOKENS=*" %%A IN ('CERTUTIL -ENCODE "%~1" "%~N1.B64"^|^|echo ---- error ----') do (
set x=!x! *** %%A
)

:sub
rem verbose disabled foll line
rem echo %x% | find "---- error ----">nul&&echo err: %x%||echo ok
echo %x% | find "---- error ----"
goto :eof



#1
November 17, 2016 at 04:33:39
It might be helpful to know what this puts out:

CERTUTIL -ENCODE "%~1" "%~N1.B64"
19:33 2016-11-17

=====================

M2 Get custom script or take private lessons


Reply ↓  Report •

#2
November 17, 2016 at 04:41:07
Input Length = 1128
Output Length = 1608
CertUtil: -encode command completed successfully.

However only output containing "ERROR_" will be displayed because of the piping to FIND

It's the errors I'm trying to catch, in this case something like

EncodeToFile returned File exists. 0x80070050 (WIN32: 80 ERROR_FILE_EXISTS)
CertUtil: -decode command FAILED: 0x80070050 (WIN32: 80 ERROR_FILE_EXISTS)

My code displays it just fine, but I can't figure out how to pass it to a sub.

Don't worry if plan A fails, there are 25 more letters in the alphabet ;)

message edited by RainBawZ


Reply ↓  Report •

#3
November 17, 2016 at 06:03:28
LOL I don't see any error in this, but maybe everybody else does:

Input Length = 1128
Output Length = 1608
CertUtil: -encode command completed successfully.

=====================

M2 Get custom script or take private lessons


Reply ↓  Report •

Related Solutions

#4
November 17, 2016 at 20:14:46
I'm not sure how reliable ERRORLEVEL is in this situation, but it might be the only way to accomplish what you're looking for.
FOR /F "TOKENS=*" %%A IN (
	'CERTUTIL -ENCODE "%~1" "%~N1.B64" ^| FIND /I "ERROR_"'
) DO (
	CALL :SUB "%%A"
)
IF NOT ERRORLEVEL 1 SET ENCODE=1

How To Ask Questions The Smart Way


Reply ↓  Report •

#5
November 17, 2016 at 23:50:12
✔ Best Answer
A whole lot of things. I'm not running win-10 (thank God), so I can't do an exact compare, so the rest of this is based on my klunky Win-7 32-bit.
Certutil returns an errorlevel. You can use that to direct the command output. I hate using temp files, so I'll try a "workaround" in this case.
Since the outcome (errorlevel) of command is not determined until completion of command, the command's output must be stored until completion, (each line, within the loop), and the command's errorlevel must also be saved (from inside the for(), NOT the loop). Then if the error occurs, we dump the output, otherwise go merrily on our way and ignore. I tried to use a variable to save the error, but that failed, so I used a string-marker:
:: begin script rain1.bat
@echo off & setlocal enabledelayedexpansion

fOR /F "TOKENS=*" %%A IN ('CERTUTIL -ENCODE "%~1" "%~N1.B64"^|^|echo ---- error ----') do (
set x=!x! *** %%A
)

:sub
rem verbose disabled foll line
rem echo %x% | find "---- error ----">nul&&echo err: %x%||echo ok
echo %x% | find "---- error ----"
goto :eof


Reply ↓  Report •

#6
November 19, 2016 at 08:50:25
Thanks for the replies!

I'll check out your suggestions once I get home to my project again in a day or so.

Don't worry if plan A fails, there are 25 more letters in the alphabet ;)


Reply ↓  Report •

#7
November 20, 2016 at 23:46:40
nbrane:
Your suggestion worked almost the way I was looking for.
FOR /F "TOKENS=*" %%A IN ('CERTUTIL -ENCODE "%~1" "%~N1.B64" ^| FIND /I "ERROR_" ^|^| ECHO ---- ERROR ----') DO (
	SET X=!X! *** %%A
)

When an error occurs, this text (or something along the lines of this) shows up on screen:
EncodeToFile returned File exists. 0x80070050 (WIN32: 80 ERROR_FILE_EXISTS)
CertUtil: -decode command FAILED: 0x80070050 (WIN32: 80 ERROR_FILE_EXISTS)

However it doesn't seem to get picked up by the FOR loop at all, it seems it prints the messages after completion, and not during the process.
Can I get around this in any way?

Don't worry if plan A fails, there are 25 more letters in the alphabet ;)


Reply ↓  Report •

#8
November 21, 2016 at 04:20:50
A process can't write data after it closes. It just can't. More likely, your utility is writing to standard error, and not standard out.

How To Ask Questions The Smart Way


Reply ↓  Report •

#9
November 21, 2016 at 11:01:31
Tried to redirect stderr to stdout, but didn't work out. Is there a way?
FOR /F "TOKENS=*" %%A IN ('CERTUTIL -ENCODE "%~1" "%~N1.B64" 2^>^&1 ^| FIND /I "ERROR_"') DO (
	SET X=!X! *** %%A
)

Don't worry if plan A fails, there are 25 more letters in the alphabet ;)

message edited by RainBawZ


Reply ↓  Report •

#10
November 21, 2016 at 20:03:57
Ha! Your code is almost what I posted, but you continue to put that extra FIND in the stream, gobbing things up:
FOR /F "TOKENS=*" %%A IN ('CERTUTIL -ENCODE "%~1" "%~N1.B64" ^| FIND /I "ERROR_" ^|^| ECHO ---- ERROR ----') DO (
SET X=!X! *** %%A
)

Compare to post #5 above, where there's no FIND "ERROR". My approach depended on the errorlevel setting, not the verbose output from certutil. Any error (generated within the FOR loop by CERTUTIL) kicks out a tag-string that is checked for in subsequent code, to determine what to do with the certutil messages stored in !x!.

message edited by nbrane


Reply ↓  Report •

#11
November 22, 2016 at 00:33:19
Alright so your code does catch messages, however it doesn't pick up the actual error messages. Here's what's being stored in !X!:
Input Length = 1128
Output Length = 1608
CertUtil: -encode command completed successfully.

However I need the actual error messages, which seem to not get put into !X!:
EncodeToFile returned File exists. 0x80070050 (WIN32: 80 ERROR_FILE_EXISTS)
CertUtil: -decode command FAILED: 0x80070050 (WIN32: 80 ERROR_FILE_EXISTS)

Also, when I try to pause after the FOR loop, they don't display. It looks like they are written to screen a while after certutil completed.

Don't worry if plan A fails, there are 25 more letters in the alphabet ;)


Reply ↓  Report •

#12
November 22, 2016 at 00:36:04
Never mind I was being stupid lol

Don't worry if plan A fails, there are 25 more letters in the alphabet ;)


Reply ↓  Report •


Ask Question