I have a batch file in my PowerShell script that I want to run and write its output to a text file. I tried the following:
Start-Process C:\path\file.bat | Out-File C:\path\output.txt
I also tried using Tee-Object and Write-Output in place of Out-File, but nothing is being written to the text file.
You can use Start-Transcript and Stop-Transcript to let the PowerShell console write all console output to a text file.
Use it like this:
Start-Transcript -Path C:\temp\log.txt
&C:\path\file.bat
Stop-Transcript
See the documentation for more details.
If you want the output of the bat file, e.g. results of a build script, then I found the following worked best:
$Product = 'ProductName'
&C:\Path\$Product.bat | Out-File C:\Path\$Product-Output.txt
You just needed a couple more parameters:
Start-Process -FilePath 'C:\Path\File.bat' -RedirectStandardOutput 'C:\Path\Output.txt' -Wait -WindowStyle Hidden
-RedirectStandardOutput to send output to your text file, -Wait to wait for the batch file to complete and -WindowStyle Hidden to hide the window used for the batch file.
Related
What is the required syntax to redirect standard input/output on Windows PowerShell?
On Unix, we use:
$./program <input.txt >output.txt
How do I execute the same task in PowerShell?
You can't hook a file directly to stdin, but you can still access stdin.
Get-Content input.txt | ./program > output.txt
If there is someone looking for 'Get-Content' alternative for large files (as me) you can use CMD in PowerShell:
cmd.exe /c ".\program < .\input.txt"
Or you can use this PowerShell command:
Start-Process .\program.exe -RedirectStandardInput .\input.txt -NoNewWindow -Wait
It will run the program synchronously in same window. But I was not able to find out how to write result from this command to a variable when I run it in PowerShell script because it always writes data to the console.
EDIT:
To get output from Start-Process you can use option
-RedirectStandardOutput
for redirecting output to file and then read it from file:
Start-Process ".\program.exe" -RedirectStandardInput ".\input.txt" -RedirectStandardOutput ".\temp.txt" -NoNewWindow -Wait
$Result = Get-Content ".\temp.txt"
For output redirection you can use:
command > filename Redirect command output to a file (overwrite)
command >> filename APPEND into a file
command 2> filename Redirect Errors
Input redirection works in a different way. For example see this Cmdlet http://technet.microsoft.com/en-us/library/ee176843.aspx
Or you can do:
something like:
$proc = Start-Process "my.exe" "exe commandline arguments" -PassThru -wait -NoNewWindow -RedirectStandardError "path to error file" -redirectstandardinput "path to a file from where input comes"
if you want to know if process errored out, add following code:
$exitCode = $proc.get_ExitCode()
if ($exitCode){
$errItem = Get-Item "path to error file"
if ($errItem.length -gt 0){
$errors = Get-Content "path to error file" | Out-String
}
}
I find that this way I do have a better handle on execution of your scripts, when you need to handle external program/process. Otherwise I have encountered situations where script would hang out on some of external process errors.
You can also do this to have standard error and standard out go to the same place (note that in cmd, 2>&1 must be last):
get-childitem foo 2>&1 >log
Note that ">" is the same as "| out-file", and by default the encoding is unicode or utf 16. Also be careful with ">>", because it can mix ascii and unicode in the same text file. "| add-content" probably works better than ">>". "| set-content" might be preferable to ">".
There's 6 streams now. More info: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_redirection?view=powershell-5.1
I think all you can do is save to a text file and then read it into a variable after.
This is my first question on SO so here goes!
I'm getting started with a simple powershell script that I intend to use to benchmark some archiving software.
I want to run the archiver (7-zip on Windows 10 in this case) and write the console output to a text file to keep as a log.
Then, I want to append to that same log the start time, end time, file sizes... etc.
The problem is I'm having difficulty sending the output to the text file.
During multiple tries I never could make it work.
I tried Out-File and also the normal ">" redirect but it still ends empty.
I even tried setting -PassThru parameter on Start-Process but it only sent the object properties instead of the Host contents.
Curiously, when I make this command run in CMD with the ">" redirect, it works as expected and I find a text file with the expected contents.
This is my current powershell script:
$7zFilePath = "C:\Program Files\7-Zip\7z.exe"
$dateStart = Get-Date
$contentsToArchive = "D:\Temp -Local\Attack on Titan- Before the Fall-002.jpg"
$workingFolder = "D:\Temp"
$archiveName = "testing {0:yyyy-MM-dd hh.mm.ss.ffff}" -f ($dateStart)
$argument = "a -t7z -m0=LZMA2 -mmt=on -mx9 -md=64m -ms=16g -mfb=273 -mqs=on -mtc=on -mta=on -bb3 `"$workingFolder\$archiveName.7z`" `"$contentsToArchive`""
Set-Location $workingFolder
Start-Process -FilePath $7zFilePath -NoNewWindow -ArgumentList $argument | Out-File ".\$archiveName.txt"
I'm answering my own question because Santiago Squarzon and mklement0 already suggested the solution in the comments to my OP.
Santiago's allowed me to produce the result with Start-Process:
$7zFilePath = "C:\Program Files\7-Zip\7z.exe"
$contentsToArchive = "D:\Temp -Local\Attack on Titan- Before the Fall-002.jpg"
$workingFolder = "D:\Games\Emulation\ROMS\GoodGen V3.21"
$archiveName = "testing {0:yyyy-MM-dd HH.mm.ss.ffff}" -f ($dateStart)
$argument = "a -t7z -m0=LZMA2 -mmt=on -mx9 -md=64m -ms=16g -mfb=273 -mqs=on -mtc=on -mta=on -bb3 `"$workingFolder\$archiveName.7z`" `"$contentsToArchive`""
Set-Location $workingFolder
Start-Process $7zFilePath "$argument" -NoNewWindow -Wait -RedirectStandardOutput ".\$archiveName.txt"
Basically, to use Start-Process and produce a text file with the output I needed to specify it in the -RedirectStandardOutput parameter (which I wasn't using).
However, the output isn't displayed in the Host because it goes straight to the specified text file.
For this, mklement0's explanation and wiki were really useful. Using the & call was much better:
& $7zFilePath `"$argument`" | Out-File -FilePath ".\$archiveName.txt"
With this, I get the output in the Host, and also it's copied to the text file.
Many thanks to you both.
I have a powershell script, p.ps1, which runs a batch-file, b.bat. The batch file runs an application MyApp.exe. I also have a log file saved in local variable $LogFile.
Is there a way to configure the PowerShell script in a way that all nested applications including MyApp.exe will write to the same log file, without changing b.bat and MyApp.exe?
I've already tried:
Start-Process "cmd.exe" "/c b.bat" -Wait | Add-Content $LogFile
And
Start-Process "cmd.exe" "/c b.bat" -Wait | Out-File $LogFile -Append
Expected Results:
All outputs will be written to $LogFile, I don't care whether outputs will be written to another log file, configured by the code of MyApp.exe.
Actual Results:
All outputs of b.bat were written to $LogFile, but the outputs from MyApp.exe were written to another log file, configured by the code of MyApp.exe.
I think I found the solution:
From the powershell file:
$command = "& 'b.bat' 'arg1' 'arg2'"
Invoke-Expression $command | Add-Content $LogFile
From the myApp code, writing in C#:
Trace.WriteLine(msg);
This way, the c# program wrote everything to the screen. The powershell script caught the output and added it to the log file using Add-Content command.
What is the required syntax to redirect standard input/output on Windows PowerShell?
On Unix, we use:
$./program <input.txt >output.txt
How do I execute the same task in PowerShell?
You can't hook a file directly to stdin, but you can still access stdin.
Get-Content input.txt | ./program > output.txt
If there is someone looking for 'Get-Content' alternative for large files (as me) you can use CMD in PowerShell:
cmd.exe /c ".\program < .\input.txt"
Or you can use this PowerShell command:
Start-Process .\program.exe -RedirectStandardInput .\input.txt -NoNewWindow -Wait
It will run the program synchronously in same window. But I was not able to find out how to write result from this command to a variable when I run it in PowerShell script because it always writes data to the console.
EDIT:
To get output from Start-Process you can use option
-RedirectStandardOutput
for redirecting output to file and then read it from file:
Start-Process ".\program.exe" -RedirectStandardInput ".\input.txt" -RedirectStandardOutput ".\temp.txt" -NoNewWindow -Wait
$Result = Get-Content ".\temp.txt"
For output redirection you can use:
command > filename Redirect command output to a file (overwrite)
command >> filename APPEND into a file
command 2> filename Redirect Errors
Input redirection works in a different way. For example see this Cmdlet http://technet.microsoft.com/en-us/library/ee176843.aspx
Or you can do:
something like:
$proc = Start-Process "my.exe" "exe commandline arguments" -PassThru -wait -NoNewWindow -RedirectStandardError "path to error file" -redirectstandardinput "path to a file from where input comes"
if you want to know if process errored out, add following code:
$exitCode = $proc.get_ExitCode()
if ($exitCode){
$errItem = Get-Item "path to error file"
if ($errItem.length -gt 0){
$errors = Get-Content "path to error file" | Out-String
}
}
I find that this way I do have a better handle on execution of your scripts, when you need to handle external program/process. Otherwise I have encountered situations where script would hang out on some of external process errors.
You can also do this to have standard error and standard out go to the same place (note that in cmd, 2>&1 must be last):
get-childitem foo 2>&1 >log
Note that ">" is the same as "| out-file", and by default the encoding is unicode or utf 16. Also be careful with ">>", because it can mix ascii and unicode in the same text file. "| add-content" probably works better than ">>". "| set-content" might be preferable to ">".
There's 6 streams now. More info: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_redirection?view=powershell-5.1
I think all you can do is save to a text file and then read it into a variable after.
I'm trying to write a Powershell script for work that will take the output of w32tm.exe \monitor and output everything into a text file. I'm trying the following code, however something is wrong since I'm able to create the text file, but nothing is being written in it:
#Take output of w32tm.exe and output into a plain text file
$file = "C:\Documents and Settings\a411882\My Documents\Scripts\timeScript.txt"
$executable = "w32tm.exe /monitor"
invoke-expression $executable | out-file -filepath $file
What am I doing wrong here? I'm new to Powershell so any advice would be greatly appreciated!
EDIT:
I can get all of the data to be displayed on the console when I run this, however I want the data to be written on the text file.
EDIT 2:
I managed to get everything to finally output. I wanted to try avoiding using the > operator to write out to the text file in hopes of learning a little more on the out-file cmdlet however doing a simple invoke-expression $executable > $file managed to get the job done. I still don't understand why the cmdlet wouldn't work properly.
Perhaps Invoke-Expression isn't properly sending output to stdout? I wouldn't expect that, but stranger things have happened. Try running w32tm.exe on its own:
$file = "C:\Documents and Settings\a411882\My Documents\Scripts\timeScript.txt"
w32tm.exe /monitor | Out-File -FilePath $file
You could use Start-Process which allows you to redirect also the error output:
Start-Process w32tm.exe -ArgumentList "/monitor" -Wait -RedirectStandardOutput "output.txt" -RedirectStandardError "error.txt"