How to redirect the terminal output of a PowerShell script to a file - powershell

I have a script which when it runs, prints out lines to the terminal (with errors). I would like to redirect this output into files.
I read that I should add this line in my PS1 script: ".\myscript.ps1 *> &1 > outfile.log" but it doesn't work because of ampersand character is not allowed.

You don't need space symbol before ampersand.
.\myscript.ps1 *>&1 will redirect all output streams to the stream number 1
.\myscript.ps1 *>outfile.log will redirect all output streams to the file
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_redirection?view=powershell-6

If you just want to put your lines into another file from a terminal I would try this:
./myscript.ps1 2>outfile.log
"./" activates the script "2>" takes the stderr stream into (in this case) the outfile.log But I am not sure what you are supposed to do. Maybe if you could post your code or your task here that would be great.
if you want both streams in one outlog, I would do it like that "2>&1"

Related

Passing strings with spaces to PowerShell

Ultimately, I want to be able to call my PS script from VBA (Excel), but the easiest way to do that seems to be with system batch commands - so I'm testing my script with a BAT file.
The script returns a text file with the contents of a webpage, sans HTML tags. It works fine called alone with default parameters; it worked fine with no spaces in the output path parameter, but I've had no luck using a path that includes a space.
PS1 script, boiled down:
param ( [string]$outputPathName="" )
$outputPathName | Out-File "D:\Documents\Google Drive\out.txt"
BAT file to test it:
powershell.exe '"D:\Documents\Google Drive\GetWebPage.ps1"' -outputPathName '"D:\Documents\Google Drive\out.txt"'
I get the error message "Unexpected token '-outputPathName' in expression or statement." (I also get a similar error for the argument, but if the parameter name were recognized I might be able to get past this.)
How can I pass a named argument in from BAT script file to PS1 script file (with spaces in the path and argument)?

Start process, wait for it, and throw away all output

I'd like to do this in PowerShell:
myprogram.exe arg1 arg2 >nul 2>nul
How does it work? There are like a million options to start processes in PowerShell, it's impossible to know the right one you need at a time.
nul is a special device (see this answer on SuperUser for instance) that's available in CMD, but not in PowerShell. In PowerShell you can use $null instead. Starting with PowerShell v3 you can use *> to redirect all output streams, but since you want to redirect output from an external program there should only be output on STDOUT and STDERR (Success and Error output stream in PowerShell terms), so >$null 2>$null should be fine.
A notable difference between CMD and PowerShell is that PowerShell doesn't include the current working directory in the PATH (the list of directories that is searched when you call a program/script without a path). If you want to run myprogram.exe from the current directory you need to prepend it with the path to the current directory (./).
You may also want to use the call operator (&). Although it's not required in this particular case I consider using it good practice. If you specify the command as a string (for instance because the path or filename contains spaces, or you want to use a variable instead of a literal) you MUST use the call operator, otherwise the statement would throw an error.
Something like this
& ./myprogram.exe arg1 arg2 >$null 2>$null
or like this
& ./myprogram.exe arg1 arg2 *>$null
should work.

Powershell fails to run multi-line commands from stdin?

I'm wanting to pass arbitrary scripts to Powershell via stdin.
(In practice, I'd like to avoid having to put the script into a temporary file, but for the purposes of this question I will pipe the contents of a file to powershell.)
So I'm doing something like so (in this example, from a Windows cmd shell):
type myfile.txt | powershell -
It works if myfile.txt contains something like this:
1..3 | % { $_ *2 }
echo done
(It outputs 2\n4\n6\ndone.)
However, if I split this first statement across multiple lines like so, then Powershell simply exists without generating any output at all:
1..3 |
% { $_ *2 }
echo done
This seems to fail for any multiline statement. For example, this also fails to produce output:
1..3 | % {
$_ *2 }
echo done
I'm surprised by this since each are legal Powershell scripts that would work normally if placed into a .ps1 file and run as normal.
I've tried various things including escaping the EOL using line continuation chars, to no avail. The same effect occurs if the parent shell is Powershell, or even Python (using subprocess.Popen with stdin=PIPE). In each case, Powershell exits without any error, and the exit code is 0.
Interestingly, if I run the following, only "before.txt" gets created.
"before" | out-file before.txt
1..3 |
% { $_ *2 }
"after" | out-file after.txt
echo done
Any ideas why Powershell would have trouble reading a multi-line command, if read from stdin?
I'm going to consider this answered by this:
How to end a multi-line command in PowerShell since it shows that an extra newline is required.
However, I'm going to raise this to MS as a bug since this should not be required when reading from a non-tty, or when -NonInteractive switch is specified.
Please vote on my bug report to the Powershell team.
This is not a complete answer, but from what I can tell, the problem has to do with the input being sent in line by line.
To demonstrate the line-by-line issue, I invoke powershell this way:
powershell.exe -command "gc myfile.txt" | powershell.exe -
vs
powershell.exe -command "gc myfile.txt -raw" | powershell.exe -
The first example replicates what you see with type, the second reads the entire contents of the file, and it works as expected.
It also works from within PowerShell if you put the script contents in a string and pipe it into powershell.exe -.
I had a theory that it had to do with line-by-line input lacking line breaks, but it's not so clear cut. If that were the case, why would the first option work but not the second (removing the line break splitting the single pipeline should have no effect, while removing the line break between the pipeline and the echo should make it fail). Maybe there's something unclear about the way powershell is handling the input with or without line breaks.

CMD: Export all the screen content to a text file

In command prompt - How do I export all the content of the screen to a text file(basically a copy command, just not by using right-clicking and the clipboard)
This command works, but only for the commands you executed, not the actual output as well
doskey /HISTORY > history.txt
If you want to append a file instead of constantly making a new one/deleting the old one's content, use double > marks. A single > mark will overwrite all the file's content.
Overwrite file
MyCommand.exe>file.txt
^This will open file.txt if it already exists and overwrite the data, or create a new file and fill it with your output
Append file from its end-point
MyCommand.exe>>file.txt
^This will append file.txt from its current end of file if it already exists, or create a new file and fill it with your output.
Update #1 (advanced):
My batch-fu has improved over time, so here's some minor updates.
If you want to differentiate between error output and normal output for a program that correctly uses Standard streams, STDOUT/STDERR, you can do this with minor changes to the syntax. I'll just use > for overwriting for these examples, but they work perfectly fine with >> for append, in regards to file-piping output re-direction.
The 1 before the >> or > is the flag for STDOUT. If you need to actually output the number one or two before the re-direction symbols, this can lead to strange, unintuitive errors if you don't know about this mechanism. That's especially relevant when outputting a single result number into a file. 2 before the re-direction symbols is for STDERR.
Now that you know that you have more than one stream available, this is a good time to show the benefits of outputting to nul. Now, outputting to nul works the same way conceptually as outputting to a file. You don't see the content in your console. Instead of it going to file or your console output, it goes into the void.
STDERR to file and suppress STDOUT
MyCommand.exe 1>nul 2>errors.txt
STDERR to file to only log errors. Will keep STDOUT in console
MyCommand.exe 2>errors.txt
STDOUT to file and suppress STDERR
MyCommand.exe 1>file.txt 2>nul
STDOUT only to file. Will keep STDERR in console
MyCommand.exe 1>file.txt
STDOUT to one file and STDERR to another file
MyCommand.exe 1>stdout.txt 2>errors.txt
The only caveat I have here is that it can create a 0-byte file for an unused stream if one of the streams never gets used. Basically, if no errors occurred, you might end up with a 0-byte errors.txt file.
Update #2
I started noticing weird behavior when writing console apps that wrote directly to STDERR, and realized that if I wanted my error output to go to the same file when using basic piping, I either had to combine streams 1 and 2 or just use STDOUT. The problem with that problem is I didn't know about the correct way to combine streams, which is this:
%command% > outputfile 2>&1
Therefore, if you want all STDOUT and STDERR piped into the same stream, make sure to use that like so:
MyCommand.exe > file.txt 2>&1
The redirector actually defaults to 1> or 1>>, even if you don't explicitly use 1 in front of it if you don't use a number in front of it, and the 2>&1 combines the streams.
Update #3 (simple)
Null for Everything
If you want to completely suppress STDOUT and STDERR you can do it this way. As a warning not all text pipes use STDOUT and STDERR but it will work for a vast majority of use cases.
STD* to null
MyCommand.exe>nul 2>&1
Copying a CMD or Powershell session's command output
If all you want is the command output from a CMD or Powershell session that you just finished up, or any other shell for that matter you can usually just select that console from that session, CTRL + A to select all content, then CTRL + C to copy the content. Then you can do whatever you like with the copied content while it's in your clipboard.
Just see this page
in cmd type:
Command | clip
Then open a *.Txt file and Paste. That's it. Done.
If you are looking for each command separately
To export all the output of the command prompt in text files. Simply follow the following syntax.
C:> [syntax] >file.txt
The above command will create result of syntax in file.txt. Where new file.txt will be created on the current folder that you are in.
For example,
C:Result> dir >file.txt
To copy the whole session, Try this:
Copy & Paste a command session as follows:
1.) At the end of your session, click the upper left corner to display the menu.
Then select.. Edit -> Select all
2.) Again, click the upper left corner to display the menu.
Then select.. Edit -> Copy
3.) Open your favorite text editor and use Ctrl+V or your normal
Paste operation to paste in the text.
If your batch file is not interactive and you don't need to see it run then this should work.
#echo off
call file.bat >textfile.txt 2>&1
Otherwise use a tee filter. There are many, some not NT compatible. SFK the Swiss Army Knife has a tee feature and is still being developed. Maybe that will work for you.
How about this:
<command> > <filename.txt> & <filename.txt>
Example:
ipconfig /all > network.txt & network.txt
This will give the results in Notepad instead of the command prompt.
From command prompt Run as Administrator. Example below is to print a list of Services running on your PC run the command below:
net start > c:\netstart.txt
You should see a copy of the text file you just exported with a listing all the PC services running at the root of your C:\ drive.
If you want to output ALL verbosity, not just stdout. But also any printf statements made by the program, any warnings, infos, etc, you have to add 2>&1 at the end of the command line.
In your case, the command will be
Program.exe > file.txt 2>&1

How can I redirect the output of a command (running in a batch loop) to a file?

I have a windows batch file, which iterates over files in a folder and runs a command on each file. Specifically I am running xmllint to validate some files:
for %%i in (c:\temp\*.xml) do (
C:\XMLLINT\xmllint -noout -schema "C:\schemas\schema.xsd" "%%~dpnxi" >> c:\output.txt
)
It currently shows the output on screen. I want to show the output of all these commands placed in an output file. How can I achieve this? By using the append operator (>>) nothing is accomplished except for a blank file being created.
Is it because of xmllint?
If you're trying to redirect error output from the program, it might be writing to stderr. You can try to redirect it with:
for %%i in (c:\temp\*.xml) do (
C:\XMLLINT\xmllint -noout -schema "C:\schemas\schema.xsd" "%%~dpnxi" >> c:\output.txt 2>&1
)
Basically the 2>&1 at the end means redirect anything from stderr (which is 2) to stdout (which is 1). Since stdout is redirected to a file, you should now see the stderr stream in the file. Hope this works for you!
I've never used it, but if its documentation is here, have you tried just removing your "-noout" option, or adding an: "-output c:\output.txt"?