Page 1 of 1

Remove Microsoft header from cmd, for example when executing code from alternate data stream

Posted: 09 Oct 2019 09:09
by Maylow
Hello everyone!
This is my first topic post here on this forum, my apologies in advance for any errors on my part about the use of this forum
(and maybe about my bad english ;) as it is not my native language (dutch here)).

I am working on a project where I make use of alternate data streams.
The goal is to develop some sort of object oriented programming mechanism in pure batch.
I have succeeded in doing so by using alternate data streams.
Object instances can be created out of classes and data encapsulation of private and protected methods and properties is provided.
However, when a data stream is redirected to cmd, the Microsoft header information is shown.
It's just a cosmetic issue, but still an annoying one I would like to solve.

The code I use in the project is way too large to put here.
I have created a small working example of the effect I'd like to tackle.
With prompt I can erase Microsoft header information of multiple cmd's, just not the first one.

test.cmd:

Code: Select all

@echo off
REM Delayed expansion is not necessary, it is just used for this example:
setlocal enableDelayedExpansion
REM Any file can be used as container for alternative data streams:
set "adsfile=ads.txt"

REM Set number of alternative data streams to use in example:
set "adscount=3"

for /l %%i in (1,1,%adscount%) do (
  REM Write code to alternative data stream:
   >%adsfile%:test%%i echo @echo off
  REM Prompt can be used to erase Microsoft header information:
  >>%adsfile%:test%%i echo prompt $S$E[2A$E[1D$E[K$E[1A$E[K
  >>%adsfile%:test%%i echo echo hi from test%%i
  if %%i lss %adscount% (
    REM Write call to next alternative data stream:
    set /a "next=%%i+1"
    >>%adsfile%:test%%i echo cmd /d /q ^<".\%adsfile%":test!next!
  )
  >>%adsfile%:test%%i echo exit /b
)

REM Test by executing first alternative data stream:
cmd /d /q < %adsfile%:test1
pause
endlocal
exit /b
When you run this, you will get something like:
{drive}:\{path}>test.cmd
Microsoft Windows [Version 10.0.18362.418]
(c) 2019 Microsoft Corporation. All rights reserved.

{drive}:\{path}>hi from test1
hi from test2
hi from test3
Press any key to continue . . .
Removing the line containing "prompt $S$E[2A$E[1D$E[K$E[1A$E[K" will result in:
{drive}:\{path}>test.cmd
Microsoft Windows [Version 10.0.18362.418]
(c) 2019 Microsoft Corporation. All rights reserved.

{drive}:\{path}>hi from test1
Microsoft Windows [Version 10.0.18362.418]
(c) 2019 Microsoft Corporation. All rights reserved.

{drive}:\{path}>hi from test2
Microsoft Windows [Version 10.0.18362.418]
(c) 2019 Microsoft Corporation. All rights reserved.

{drive}:\{path}>hi from test3
Press any key to continue . . .
So the prompt's erase effect works on multiple cmd's using redirected alternate data streams, just not on the first one.
I have tried things like putting "cmd /d /q < %adsfile%:test1" in a separate script.bat and performing "call script.bat", I have tried with cmd /d /c, with start, all to no avail.
The start command is actually not suited here as my project requires to have these cmd's run in the same command session.

Does anyone know how to solve this?
Thanks in advance!

Edit: replaced all alternative with alternate as that is the correct term.

Re: Remove Microsoft header from cmd when executing code from alternative data stream

Posted: 09 Oct 2019 10:30
by Aacini
Mmmm... A couple remarks about your post...

In first place, your problem is not related to Alternate Data Streams. The same effect happen when you redirect any text file into cmd.exe in that way.

The simplest way to avoid the initial cmd.exe message is using this format:

Code: Select all

cmd /d /q < %adsfile%:test1 > NUL
... and then redirect any output inside the text file to CON this way:

Code: Select all

echo hi from test > CON
This method and many other tricks related to use a redirected text file into cmd.exe are described at this thread.

Antonio

PS - I suggest you to include an extension in the ADS file (like "%adsfile%:test1.txt") as described here...

Re: Remove Microsoft header from cmd, for example when executing code from alternate data stream

Posted: 09 Oct 2019 11:45
by Maylow
Thanks for that quick of response!

Sorry, I wasn't implying it was only related to alternate data streams, you are right that the title might suggest it.
I changed the title of this topic a bit.

Your suggestions fixed the problem! Many thanks! :)
I thought I had tested that, but it turns out I forgot to escape the redirection to con.

The following code with solution and file extensions for streams implemented works as expected:

Code: Select all

@echo off
REM Delayed expansion is not necessary, it is just used for this example:
setlocal enableDelayedExpansion
REM Any file can be used as container for alternative data streams:
set "adsfile=ads.txt"

REM Set number of alternative data streams to use in example:
set "adscount=3"

for /l %%i in (1,1,%adscount%) do (
  REM Write code to alternative data stream:
  >>%adsfile%:test%%i.cmd echo echo hi from test%%i ^>con
  if %%i lss %adscount% (
    REM Write call to next alternative data stream:
    set /a "next=%%i+1"
    >>%adsfile%:test%%i.cmd echo cmd /d /q ^<".\%adsfile%":test!next!.cmd
  )
  >>%adsfile%:test%%i.cmd echo exit /b
)

REM Test by executing first alternative data stream:
cmd /d /q < %adsfile%:test1.cmd >nul
pause
endlocal
exit /b
Many thanks again :D

Edit: removed unnecessary code

Re: Remove Microsoft header from cmd when executing code from alternative data stream

Posted: 09 Oct 2019 13:55
by dbenham
A few commands do not work properly when redirected to CON. The one I can remember is CLS - it outputs a funny character to the screen instead of clearing the screen when redirected to CON.

You might consider redirecting to &2 (stderr) instead of CON. Screen output should then be the same as if stdout were not redirected at all.

You don't need the CMD /Q option since all prompt output is redirected to NUL.

Also, you no longer need the PROMPT command in any of your scripts since the header info has been redirected to NUL.

You might consider adding the CMD /V:ON option so you can use delayed expansion in your scripts.

Another option is to consider structuring your scripts as follows - then you don't need to remember to redirect stdout for individual commands.

Code: Select all

>&2 (
  command 1
  command 2
  etc.
)
Of course that won't work if you need to set a variable and percent expand it in the same "script". Also, you would need to redirect CMD output to NUL in your scripts again each time you "call" another script.

Either way, one nice result of redirecting prompt and header output to NUL and all wanted output to &2 is you can redirect your output to a file without any unwanted characters in the output. If you don't want stderr captured in your file, then you could redirect 2>CON, or 2>nul within your script.

Code: Select all

cmd /d >nul <yourScript 2>outputFile.txt
The redirection strategy also works on all Windows versions. The PROMPT with escape sequences only works on Windows 10.


Dave Benham

Re: Remove Microsoft header from cmd when executing code from alternate data stream

Posted: 09 Oct 2019 14:07
by Maylow
Manu thanks for all the great tips! :D

Yes I've experienced the funny thing with CLS :P

That's a nice idea about redirecting to stderr instead of CON, will do some tests with it.

Absolutely right about the cmd /q and prompt no longer necessary, the example was a little piece i wrote quickly.

I already use cmd /V:on in the project, I left it out in the example for brevity. Good advice still though.

The PROMPT escape sequences limited to Windows 10 is not a big problem since other stuff in the project also require Windows 10.

I am going to experiment a lot with all your suggestions.
Thanks again guys!

Re: Remove Microsoft header from cmd when executing code from alternative data stream

Posted: 09 Oct 2019 14:57
by Eureka!
Or ...
add /K to your original command to get rid of the version info:

Code: Select all

>>%adsfile%:test%%i echo cmd /d /q /k ^<".\%adsfile%":test!next!
and

Code: Select all

cmd /d /q /k < %adsfile%:test1

Succes ermee! :)

Re: Remove Microsoft header from cmd when executing code from alternate data stream

Posted: 09 Oct 2019 15:19
by Maylow
I have tried that already like the cmd /C option, that doesn't work as expected.

The solution is to redirect the < cmd option to >nul and to redirect output from inside the stream to >con.

Maar dank je! ;)

Re: Remove Microsoft header from cmd when executing code from alternative data stream

Posted: 09 Oct 2019 15:36
by dbenham
I believe one modification to Eureka's suggestion gives the correct result:

Remove PROMPT from each of your scripts, and then use:

Code: Select all

cmd /d /q /k prompt $h < %adsfile%:test1
Also use /K PROMPT $H whenever a script "calls" another script.

It worked for me

Re: Remove Microsoft header from cmd, for example when executing code from alternate data stream

Posted: 09 Oct 2019 16:29
by Maylow
I see, sounds very interesting. Going to experiment with that as well! :)

Re: Remove Microsoft header from cmd, for example when executing code from alternate data stream

Posted: 09 Oct 2019 21:33
by Squashman
What is your end game for using ADS? Just want to make you aware that the ADS is only local to the system you are using it on. If you try to upload or email a file with an ADS, only the main data stream is transferred.

Re: Remove Microsoft header from cmd, for example when executing code from alternate data stream

Posted: 09 Oct 2019 22:15
by Maylow
I have read about the limitations of alternate data streams, such as NTFS required, not transportable (upload/download/email) and such.

Fortunately this is not a problem for the project.

NTFS is a requirement of the project because other features of NTFS are also used (file compression/encryption).
Windows 10 is also a requirement of the project so in a way NTFS is pretty much assured as it is the default file system of Windows 10.
The usage of alternate data streams is intended to be local.

Its usage is to dynamically write batch scripts temporarily into alternate data streams which are then called and deleted on request if it no longer has usage and/or ultimately deleted when destroying all objects.

Still many thanks for bringing this up! :)
I hope I am able to finish and demonstrate my project soon.