I'm very new to powershell and I'm looking to pipe all lines to an output file for logging with it's time, but I would rather not explicitly pipe all cmdlets to the log file to avoid visual clutter and to make the code easily extensible.
I'm not sure whether existing methods do what I'm asking and I just can't recognize it or what but any pointers or help would be appreciated.
If you want to capture all of the output generated in a PowerShell session (including other streams such as verbose or error messages) you can use Start-Transcript at the start of your script and Stop-Transcript at the end.
If you want to output specific log entries, consider using a Write-Log function as described in one of the answers here: Create Log File in Powershell
Or here's a simple version to get your started:
function Write-Log {
Param(
$Message,
$Path = "$env:USERPROFILE\log.txt"
)
function TS {Get-Date -Format 'hh:mm:ss'}
"[$(TS)]$Message" | Tee-Object -FilePath $Path -Append | Write-Verbose
}
Write-Log 'Some message'
This adds a timestamp to the start of the message and directs it to the Verbose output stream as well as a file via Tee-Object. You can then see the Verbose messages if you enable them via $VerbosePreference (or by supporting -Verbose in your script).
Alternatively, if you want to redirect all output from your script that isn't the other message streams (e.g just things sent to the standard pipeline) you could save the script, run it from within PowerShell and then pipe its output to another command such as Out-File, e.g:
.\yourscript.ps1 | Out-File output.txt
Related
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.
I am trying to write a migration/deployment script to deploy an application to an environment (DEV, QA, PROD) and I need to be able to fully log all output. This would include any status message I specifically put in the output stream (not a problem) as well as verbose output from all commands. For instance, if I'm calling Copy-Item, I want the full listing of each item copied.
I'm trying to figure out a way to do this throughout the entire script reliably. In other words, I don't want to rely on including -Verbose on every command (as it could be missed when someone else maintains the script in the future). I've been looking at things like $VerbosePreference as well as the possibility of calling my main cmdlet/function using -Verbose, with the hope being that either would apply to the entire script. But that appears to not be the case. While any Write-Verbose commands I use respect either approach, calls to Copy-Item only show the verbose listing if I specifically pass -Verbose to it. I'm really hoping I'm just missing something! Surely this is possible to do what I'm wanting!
Sample code:
function Main () {
[CmdletBinding()]
Param()
Begin {
Copy-Item C:\Temp\src\* -Destination C:\Temp\dest -Recurse -Force
Write-Output 'Main output'
Write-Verbose 'Main verbose'
Child
}
}
function Child () {
[CmdletBinding()]
Param()
Begin {
Copy-Item C:\Temp\src\* -Destination C:\Temp\dest -Recurse -Force
Write-Output 'Child output'
Write-Verbose 'Child verbose'
}
}
$VerbosePreference = 'SilentlyContinue'
Write-Output $VerbosePreference
Main
''
Main -Verbose
''
''
$VerbosePreference = 'Continue'
Write-Output $VerbosePreference
Main
''
Main -Verbose
Produces output:
SilentlyContinue
Main output
Child output
Main output
VERBOSE: Main verbose
Child output
VERBOSE: Child verbose
Continue
Main output
VERBOSE: Main verbose
Child output
VERBOSE: Child verbose
Main output
VERBOSE: Main verbose
Child output
VERBOSE: Child verbose
So, clearly $VerbosePreference and -Verbose are affecting the Write-Verbose, but that's about it. The Copy-Item is not displaying ANY output whatsoever (though it will if I specifically use -Verbose directly on that command).
Any thoughts? Am I going about this all wrong? Please help!
How about leveraging...
Tip: Create a Transcript of What You Do in Windows PowerShell
The PowerShell console includes a transcript feature to help you
record all your activities at the prompt. As of this writing, you
cannot use this feature in the PowerShell application. Commands you
use with transcripts include the following:
https://technet.microsoft.com/en-us/library/ff687007.aspx
... or the approaches provided / detailed here:
Enhanced Script Logging module (automatic console output captured to
file)
Automatically copy PowerShell console output to a log file (from
Output, Error, Warning, Verbose and Debug streams), while still
displaying the output at the console. Log file output is prepended
with date/time and an indicator of which stream originated the line
https://gallery.technet.microsoft.com/scriptcenter/Enhanced-Script-Logging-27615f85
Write-Log PowerShell Logging Function
The Write-Log PowerShell advanced function is designed to be a simple
logger function for other cmdlets, advanced functions, and scripts.
Often when running scripts one needs to keep a log of what happened
and when. The Write-Log accepts a string and a path to a log file and
ap
https://gallery.technet.microsoft.com/scriptcenter/Write-Log-PowerShell-999c32d0
* Update as per the OP comment*
See this discussion...
Powershell apply verbosity at a global level
where the -verbose flag is not supplied to the ni command. Is there a
way to set the Verbosity at a global PSSession level if I were to run
this script to force verbosity? The reason I ask is that I have a
group of about 60 scripts which are interdependent and none of these
supply -verbose to any commands they issue and I'd like to see the
entire output when I call the main entry point powershell script.
Powershell apply verbosity at a global level
Use PowerShell Default Parameter Values to Simplify Scripts
Changing default parameter values
When I was asked to write about my favorite Windows PowerShell 3.0
feature, my #1 $PSDefaultParameterValues came to mind immediately.
From my point of view, this was something I was looking for, for a
long time.
How does it work? With $PSDefaultParameterValues, you can define
(overwrite) default values of parameters for Windows PowerShell
cmdlets.
https://blogs.technet.microsoft.com/heyscriptingguy/2012/12/03/use-powershell-default-parameter-values-to-simplify-scripts/
See also:
Script Tracing and Logging
While Windows PowerShell already has the LogPipelineExecutionDetails
Group Policy setting to log the invocation of cmdlets, PowerShell’s
scripting language has plenty of features that you might want to log
and/or audit. The new Detailed Script Tracing feature lets you enable
detailed tracking and analysis of Windows PowerShell scripting use on
a system. After you enable detailed script tracing, Windows PowerShell
logs all script blocks to the ETW event log,
Microsoft-Windows-PowerShell/Operational. If a script block creates
another script block (for example, a script that calls the
Invoke-Expression cmdlet on a string), that resulting script block is
logged as well.
Logging of these events can be enabled through the Turn on PowerShell
Script Block Logging Group Policy setting (in Administrative Templates
-> Windows Components -> Windows PowerShell).
https://learn.microsoft.com/en-us/powershell/wmf/5.0/audit_script
I am running a fairly complex python script from a powershell script. I would like to both display the stdout and stderr streams of the .python script in the console in real time (ie as the .py script writes to them) and also write them to a file.
My current solution looks like this:
Do-PreliminaryStuff
log = & ".\myPyScript.py" -myArgument "\this\that\thingy.txt" 2>&1 $log
Write-Output $log
$log | Out-File "$logDir\pyScriptLog.log"
Do-RestOfScript
This has the problem that the text is only printed out after the .py script has finished, making it much harder to watch the progress of the .py script.
Is there a way to somehow ..sample.. the pipeline as object go through it?
You are probably looking for the Tee-Object cmdlet.
Use Tee-Object - it splits the pipeline into a filestream before continuing:
& ".\myPyScript.py" -myArgument "\this\that\thingy.txt" 2>&1 |Tee-Object -FilePath $log
When I run this command:
Get-Content generated\no_animate.css >> generated\all.css
It is copying the first files content into the second file. What is the official term for the >> symbol and where can I find more information about this and others?
Unsurprisingly searching for >> in Google is not terribly informative.
Thanks to EBGreen I found this information.
https://technet.microsoft.com/en-us/library/hh847746.aspx
TOPIC
about_Redirection
SHORT DESCRIPTION
Explains how to redirect output from Windows PowerShell to text files.
LONG DESCRIPTION
By default, Windows PowerShell sends its command output to the Windows
PowerShell console. However, you can direct the output to a text
file, and you can redirect error output to the regular output stream.
You can use the following methods to redirect output:
- Use the Out-File cmdlet, which sends command output to a text file.
Typically, you use the Out-File cmdlet when you need to use its
parameters, such as the Encoding, Force, Width, or NoClobber
parameters.
- Use the Tee-Object cmdlet, which sends command output to a text file
and then sends it to the pipeline.
- Use the Windows PowerShell redirection operators.
WINDOWS POWERSHELL REDIRECTION OPERATORS
The redirection operators enable you to send particular types of output
to files and to the success output stream.
The Windows PowerShell redirection operators use the following characters
to represent each output type:
* All output
1 Success output
2 Errors
3 Warning messages
4 Verbose output
5 Debug messages
NOTE: The All (*), Warning (3), Verbose (4) and Debug (5) redirection operators were introduced
in Windows PowerShell 3.0. They do not work in earlier versions of Windows PowerShell.
The Windows PowerShell redirection operators are as follows.
Operator Description Example
-------- ---------------------- ------------------------------
> Sends output to the Get-Process > Process.txt
specified file.
>> Appends the output to dir *.ps1 >> Scripts.txt
the contents of the
specified file.
2> Sends errors to the Get-Process none 2> Errors.txt
specified file.
2>> Appends errors to Get-Process none 2>> Save-Errors.txt
the contents of the
specified file.
2>&1 Sends errors (2) and Get-Process none, Powershell 2>&1
success output (1)
to the success
output stream.
3> Sends warnings to the Write-Warning "Test!" 3> Warnings.txt
specified file.
3>> Appends warnings to Write-Warning "Test!" 3>> Save-Warnings.txt
the contents of the
specified file.
3>&1 Sends warnings (3) and function Test-Warning
success output (1) { Get-Process PowerShell;
to the success Write-Warning "Test!" }
output stream. Test-Warning 3>&1
4> Sends verbose output to Import-Module * -Verbose 4> Verbose.txt
the specified file.
4>> Appends verbose output Import-Module * -Verbose 4>> Save-Verbose.txt
to the contents of the
specified file.
4>&1 Sends verbose output (4) Import-Module * -Verbose 4>&1
and success output (1)
to the success output
stream.
5> Sends debug messages to Write-Debug "Starting" 5> Debug.txt
the specified file.
5>> Appends debug messages Write-Debug "Saving" 5>> Save-Debug.txt
to the contents of the
specified file.
5>&1 Sends debug messages (5) function Test-Debug
and success output (1) { Get-Process PowerShell
to the success output Write-Debug "PS" }
stream. Test-Debug 5>&1
*> Sends all output types function Test-Output
to the specified file. { Get-Process PowerShell, none
Write-Warning "Test!"
*>> Appends all output types Write-Verbose "Test Verbose"
to the contents of the Write-Debug "Test Debug" }
specified file.
Test-Output *> Test-Output.txt
*>&1 Sends all output types Test-Output *>> Test-Output.txt
(*) to the success output Test-Output *>&1
stream.
The syntax of the redirection operators is as follows:
<input> <operator> [<path>\]<file>
If the specified file already exists, the redirection operators that do not
append data (> and n>) overwrite the current contents of the file without
warning. However, if the file is a read-only, hidden, or system file, the
redirection fails. The append redirection operators (>> and n>>) do not
write to a read-only file, but they append content to a system or hidden
file.
To force the redirection of content to a read-only, hidden, or system file,
use the Out-File cmdlet with its Force parameter. When you are writing to
files, the redirection operators use Unicode encoding. If the file has a
different encoding, the output might not be formatted correctly. To
redirect content to non-Unicode files, use the Out-File cmdlet with its
Encoding parameter.
SEE ALSO
Out-File
Tee-Object
about_Operators
about_Command_Syntax
about_Path_Syntax
I wrote a script in powershell and I would like to have it write all activities and errors to a log file. I am a powershell newbie so I need anyone's input.
I created a function
function logWrite
{
param ([string]$logstring)
add-content $logfile -value $logstring
}
Instead of using Write-host i use the logWrite but I am getting errors:
Unexpected token 'starting script' in expression or statement. at
d:\scripts\tmain.ps1
Appreciate everyone's feedback in advance.
You can also use the Start-Transcript cmdlet in your script, which will copy all of the console input and output (including Write-Host) to a file.
The easiest way is to redirect output at the point you invoke the script e.g.:
C:\PS> .\myscript.ps1 *> myscript.log
The *> will redirect all streams to the log file including output, error, warning, verbose and debug. The only output it won't capture is Write-Host output since that is written directly to the host by definition.