Windows batch redirect output to console - batch-file

The summary of this question is I have a command I'm running in batch, Some.exe args but it is not outputting to the console. It does however output to a text file if used like Some.exe args > test.txt. I've tried stuff like #Some.exe args and Some.exe args > CON to get it to output to the console, but neither seems to work.
Are there any other approaches which might work?
This follows on from a previous question I asked DOORS make console the interactive window.
I'm calling a program called DOORS through a batch script. It runs a simple script, hello.dxl that looks like
cout << "Hello world"
The batch script, Run.bat looks like
"C:\Program Files\IBM\Rational\DOORS\9.6\bin\doors.exe" -u test -pass testPass -b hello.dxl
When this is run, no output appears on the screen and there are no popup windows or anything (if hello.dxl said print("Hello World") an interactive window would pop-up, but not with cout)
If I add > test.txt to the end of the command
"C:\Program Files\IBM\Rational\DOORS\9.6\bin\doors.exe" -u test -pass testPass -b hello.dxl > test.txt
It outputs the Hello World to test.txt successfully. Something I noticed is when using print("Hello World") there was no output sent to the test.txt file and an interactive window popped up so it looks like cout is the way to go.
So I though the output might just not be being output anywhere, so I tried adding > CON instead to try to force it to go to the console.
"C:\Program Files\IBM\Rational\DOORS\9.6\bin\doors.exe" -u test -pass testPass -b hello.dxl > CON
But that still resulted in a blank output.
I also tried adding an #, before the command, as suggested in this Batch - redirect program output to current console, like
#"C:\Program Files\IBM\Rational\DOORS\9.6\bin\doors.exe" -u test -pass testPass -b hello.dxl
or
#"C:\Program Files\IBM\Rational\DOORS\9.6\bin\doors.exe" -u test -pass testPass -b hello.dxl > CON
But no luck there either
I would have tried to reproduce this issue without DOORS but I don't know what is causing it in the first place.
Edit: I'm not really looking to use > test.txt & type test.txt as that is the current workaround I am using. But ideally I don't want it outputting to a text file

Turns out this approach has limited functionality, as soon as I tried opening a module, it made the interactive window pop up and no output was visible in the interactive window or the the console window
This is not an issue with the > test.txt & type test.txt workaround
Based on #PA.'s suggestion that the program is somehow preventing output to stdout but not if it was redirected, so I wrote a small C# console app which looks like
using System;
using System.Diagnostics;
using Process process = new();
process.EnableRaisingEvents = true;
process.ErrorDataReceived += ErrOut;
process.OutputDataReceived += StdOut;
process.StartInfo.FileName = args[0].Trim();
process.StartInfo.Arguments = args[1].Trim();
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();
static void ErrOut(object sender, DataReceivedEventArgs dataReceivedEventArgs)
{
if (dataReceivedEventArgs.Data != null)
{
Console.WriteLine(dataReceivedEventArgs.Data);
}
}
static void StdOut(object sender, DataReceivedEventArgs dataReceivedEventArgs)
{
if (dataReceivedEventArgs.Data != null)
{
Console.WriteLine(dataReceivedEventArgs.Data);
}
}
I then exported this to a single exe using the command
dotnet publish /p:DebugType=None /p:DebugSymbols=false /p:PublishReadyToRun=true /p:PublishSingleFile=true /p:PublishReadyToRunShowWarnings=true /p:PublishTrimmed=false /p:IncludeNativeLibrariesForSelfExtract=true /p:IncludeAllContentForSelfExtract=true "RedirectOutput.csproj" -o "." -c release
which I added then just added the folder with that exe in to my path environment variable.
Now I can just do
RedirectOutput "C:\Program Files\IBM\Rational\DOORS\9.6\bin\doors.exe" "-u test -pass testPass -b hello.dxl"
and I get the desired output

This is more a workaround.
The idea is to a use a pipe program in order to redirect the output of the Windows program to the console:
SomeWinProg SomeArgs 2>>&1 | SomePipeProg PipeProgArgs
As a pipe program you may use a program that passes throug everything, like:
SomeWinProg SomeArgs 2>>&1 | findstr /r "/c:.*"
If this works or not depends on the Windows program.
Concerning the timing:
There may be some trouble when you have a long time running Windows program which produces sporadic output or when the output is done always to the same line (no line feeds, only carriage returns) and you want to have the output in real time.
In these cacses Windows programs like findstr or find are a little bit weak.
On github there is an implementation of mtee thats fits better:
SomeWinProg SomeArgs 2>>&1 | mtee nul

Related

Output command result to file

Windows cmd file has the following line
wget "http://ftp.gnu.org/gnu/wget/wget-1.5.3.tar.gz" -P C:\temp >> dld.log
After executing the dld.log file is empty.
What is wrong with output redirection?
It is necessary that the output of wget execution is written to the dld.log file
wget redirects output to stderr mostly to split off from the results data.
So direct answer to to make the current redirect code work is to use 2>&1 to direct sterr stream to stdout as in:
(wget "http://ftp.gnu.org/gnu/wget/wget-1.5.3.tar.gz" -P "C:\temp")>>dld.log 2>&1
However, wget has log functions built in which makes more sense. The switch is --output-file
wget "http://ftp.gnu.org/gnu/wget/wget-1.5.3.tar.gz" -P "C:\temp" --output-file=dld.log
See the wget manual for more info.

Error passing multiple commands to Cisco CLI via plink

I've gotten some help with an earlier part of this batch file, but now I'm having trouble with the final component.
I've tried a few things with no success. I tried changing the CRLF to LF which did nothing. I also tried rephrasing the commands a few ways but I am still not getting anywhere. The following is my main batch file.
#echo on
REM delete deauth command file
SET OutFile="C:\temp\Out2.txt"
IF EXIST "%OutFile%" DEL "%OutFile%"
plink -v -ssh *#x.x.x.x -pw PW -m "c:\temp\WirelessDump.txt" > "C:\temp\output.txt"
setlocal
for /f %%a in (C:\temp\output.txt) do >> "Out2.txt" echo wir cli mac-address %%a deauth forced
REM Use commands in out2 to deauth
plink -v -ssh *#x.x.x.x -pw PW -m "c:\temp\Out2.txt"
pause
Below this sentence is the command found in Out2 which I think is giving the actual trouble. The number of lines varies but they are all this particular command just with differing MACs.
wir cli mac-address xxxx.xxxx.xxxx deauth forced
If Out2 has only a single line it runs fine, no issues. But when there are multiple lines, it fails with an error stating that the Line has an invalid autocommand. It's almost as if it was reading it as one contiguous command. As I mentioned above I changed from CRLF to LF hoping IOS would like it better, but that failed. I've tried adding extra lines between the commands, and I've tried calling the login every time from that file.
I am hoping that there is a way to tailor the commands to pass all lines one at a time to keep this down to a minimum of files.
I had another thought but it is kinda/very clunky. If there was a way to output each of those MAC deauth commands to their own file in a saperate folder (out1, out2, out3), and have the BAT able to run all the randomly generated files in that folder so that each one is a separated plink session.
Let me know if I need to change/add/elaborate on anything. Thanks in advance for anything you guys are willing to help with. I appreciate it.
EDIT: Martin has pointed out what the limitation actually is. It appears to be a limitation on Cisco to accept blocks of commands through SSH. So I still have the same question really, I just need some help figuring a workaround to this issue. I'm thinking the multiple file solution I mentioned above may have some possibility. But I'm too much of a noob to know how to make that work. I'll update if I have any breakthroughs though. Thanks for any contributions!
It's actually a known limitation of Cisco, that it does not support multiple commands in an SSH "exec" channel command.
Quoting section 3.8.3.6 -m: read a remote command or script from a file of PuTTY/Plink manual:
With some servers (particularly Unix systems), you can even put multiple lines in this file and execute more than one command in sequence, or a whole shell script; but this is arguably an abuse, and cannot be expected to work on all servers. In particular, it is known not to work with certain ‘embedded’ servers, such as Cisco routers.
Though you can probably still feed multiple commands to Plink input:
(
echo command 1
echo command 2
echo command 3
echo exit
) | plink -v -ssh user#host -pw password > output.txt
Or you can simply use an input file:
plink -v -ssh user#host -pw password < input.txt > output.txt
Similar question: A way of typing multiple commands in cmd.txt file using PuTTY batch against Cisco
This works without cmd.exe and using files:
function Invoke-PlinkCommandsIOS {
param (
[Parameter(Mandatory=$true)][string] $Host,
[Parameter(Mandatory=$true)][System.Management.Automation.PSCredential] $Credential,
[Parameter(Mandatory=$true)][string] $Commands,
[Switch] $ConnectOnceToAcceptHostKey = $false
)
$PlinkPath="$PSScriptRoot\plink.exe"
$commands | & "$PSScriptRoot\plink.exe" -ssh -2 -l $Credential.GetNetworkCredential().username -pw "$($Credential.GetNetworkCredential().password)" $Host -batch
}
Usage: dont forget your exit's and terminal length 0 or it will hang
PS C:\> $Command = "terminal lenght 0
>> show running-config
>> exit
>> "
>>
PS C:\> Invoke-PlinkCommandsIOS -Host ace-dc1 -Credential $cred -Commands $Command
....
Sounds like your file 'Out2.txt' has only LF at end of line. Simple way to convert that to CRLF is to use MORE command and redirect output to a new file and then use the new file.
more Out2.txt > Out2CRLF.txt
I ran into the same issue when trying to pull the full list of ACLs on an ASA via plink in powershell.
Essentially, due to the abuse issue referenced in the documentation: https://the.earth.li/~sgtatham/putty/0.72/htmldoc/Chapter3.html#using-cmdline-m, I was getting inconsistent results in pulling the ACLs. Sometimes I would get 0, sometimes only 1 or 2, and sometimes I would get all of them. (I personally, had about a 1 in 5 success rate).
As I would occasionally be successful I used a while loop that would catch the unsuccessful attempts and retry. Just be sure to put some timing on the while loop to prevent it from spamming ssh connections too much.
It is not a good solution, but it worked as a last resort.

Writing the same output to multiple logs

Is it possible to write the same output to more than one file in Batch?
My reason for wanting to do this is because I have a large batch script that produces a very detailed log. This is fine as it is, but i want to also output a trimmed back version of the log with a lot less detail in it. The Batch cannot be run multiple times either.
Say for instance I have a simple batch:
Echo This is a Batch Script >> Path\File1 & Path\File2
osql -S%SERVERNAME% -E -d%DATABASENAME% -Q%SQL% >> Path\File1
Appreciate any help.
Maybe you can use the tee command from Unix tools. Downloadable for free from here. Think of it like a "T" that a plumber might put in a pipe to send water two ways.
osql -S%SERVERNAME% -E -d%DATABASENAME% -Q%SQL% | tee file1 file2 file3
Have a look at some examples as I am not entirely sure what your full processing requirement is, see here.
If you want to do some processing on one stream you can do this:
osql -S%SERVERNAME% -E -d%DATABASENAME% -Q%SQL% | tee unfiltered.txt | FINDSTR /v "UglyStuff" > filtered.txt
Second answer, because it is different...
You could use some VBScript, like this to send your osql output to both stdout and stderr and then handle the two separately. This saves you needing to install any Unix tools.
Save this as tee.vbs
REM ############################################################################
REM File: tee.vbs
REM Author: Mark Setchell
REM I don't need any Unix purists to tell me it is not functionally idential to
REM the Unix 'tee' command, please. It does a job - that's all. And I also know
REM there is no error checking. It illustrates a technique.
REM ############################################################################
Set fso = CreateObject ("Scripting.FileSystemObject")
Set stdout = fso.GetStandardStream (1)
Set stderr = fso.GetStandardStream (2)
Do While Not WScript.StdIn.AtEndOfStream
REM Read in next line of input
Line = WScript.StdIn.ReadLine()
stdout.WriteLine(Line)
stderr.WriteLine(Line)
Loop
Then run your osql like this:
osql -S%SERVERNAME% -E -d%DATABASENAME% -Q%SQL% | cscript /nologo tee.vbs 2> unfiltered.txt | FINDSTR "goodstuff" > filtered.txt
Basically, whatever the tee.vbs script writes to stderr gets redirected to wherever 2> points, and whatever tee.vbs writes to stdout goes into the FINDSTR command.
Ideally, you could put your filtering inside the tee.vbs file for maximum flexibility.

Executing ssh command in c program using popen()

When I try executing this using popen it returns this error but when I run this in terminal it works!
popen("ssh -n -f *.*.*.* 'sshfs -o nonempty *.*.*.*:/home/foo/bar/ /foo1/foo2/foo3'", "r");
error:
ssh_exchange_identification: Connection closed by remote host
I use public and private key to ssh without passwords and they work properly as this command run flawlessly in terminal.
I changed it to this :
popen("ssh -n -f *.*.*.* `sshfs -o nonempty *.*.*.*:/home/foo/bar/ /foo1/foo2/foo3`", "r");
It return errors too.
error :
fuse: bad mount point `/foo1/foo2/foo3': No such file or directory
Cannot fork into background without a command to execute.
I also tried escipping the internal "" this way : \" \" but it hangs!
Replace ssh with /usr/bin/ssh, do the same with other commands, like sshfs. Specify the full path of the command, /usr/sbin/foo or whatever the case may be. popen does not necessarily use the same shell you have at the command line to execute commands. Check your documentation.

Appending output of a Batch file To log file

I have a batch file which calls a java program.
The output is redirected to a log file in the same directory.
However the log file is replaced everytime the batch file is run...
I would like to keep the old outputs in the log file and always append the new output to the log file.
Instead of using ">" to redirect like this:
java Foo > log
use ">>" to append normal "stdout" output to a new or existing file:
java Foo >> log
However, if you also want to capture "stderr" errors (such as why the Java program couldn't be started), you should also use the "2>&1" tag which redirects "stderr" (the "2") to "stdout" (the "1"). For example:
java Foo >> log 2>&1
This is not an answer to your original question: "Appending output of a Batch file To log file?"
For reference, it's an answer to your followup question: "What lines should i add to my batch file which will make it execute after every 30mins?"
(But I would take Jon Skeet's advice: "You probably shouldn't do that in your batch file - instead, use Task Scheduler.")
Timeout:
timeout command 1
timeout command 2
Example (1 second):
TIMEOUT /T 1000 /NOBREAK
Sleep:
sleep command (if sleep.exe is installed)
Example (1 second):
sleep -m 1000
Alternative methods:
Sleeping in a batch file
batch script, put to sleep until certain time
Here's an answer to your 2nd followup question: "Along with the Timestamp?"
Create a date and time stamp in your batch files
Example:
echo *** Date: %DATE:/=-% and Time:%TIME::=-% *** >> output.log
Use log4j in your java program instead. Then you can output to multiple media, create rolling logs, etc. and include timestamps, class names and line numbers.
It's also possible to use java Foo | tee -a some.log. it just prints to stdout as well. Like:
user at Computer in ~
$ echo "hi" | tee -a foo.txt
hi
user at Computer in ~
$ echo "hello" | tee -a foo.txt
hello
user at Computer in ~
$ cat foo.txt
hi
hello

Resources