Instead of explicitly writing each log line to a file, you may want to use a different approach that references the log file only at one location in the code.
Advantages:
- Easy to change log path and customize the log output (e. g. prepending a timestamp), without having to modify all code locations that log something.
- Captures any kind of messages, e. g. also error, verbose and debug messages (if enabled).
- Captures messages of 3rd party code aswell, without having to tell them the name of the log file.
Function SomeFunction {
Write-Host "Hello from SomeFunction" # a log message
"SomeFunctionOutput" # Implicit output (return value) of the function.
# This is short for Write-Output "SomeFunctionOutput".
}
Function Main {
Write-Host "Hello from Main" # a log message
# Call SomeFunction and store its result (aka output) in $x
$x = SomeFunction
# To demonstrate that "normal" function output is not affected by log messages
$x -eq "SomeFunctionOutput"
}
# Call Main and redirect all of its output streams, including those of any
# called functions.
Main *>&1 | Tee-Object -FilePath $PSScriptRoot\Log.txt -Append
Output:
Hello from Main
Hello from SomeFunction
True
In this sample all code is wrapped in function Main. This allows us to easily redirect all output streams using the *>&1 syntax, which employs the redirection operator to "merge" the streams. This means that all commands further down the pipeline (in this example Tee-Object) receive any script messages that would normally end up in the console (except when written directly to the console, which circumvents PowerShells streams).
Possible further improvements
You may want to use try/catch in function Main, so you also capture script-terminating errors:
try {
SomeFunction # May also cause a script-terminating error, which will be catched.
# Example code that causes a script-terminating error
Write-Error "Fatal error" -ErrorAction Stop
}
catch {
# Make sure script-terminating errors are logged
Write-Error -ErrorRecord $_ -ErrorAction Continue
}