- Configure attack surface reduction in Microsoft Defender using Group Policy or PowerShell - Mon, Aug 15 2022
- Run Windows Terminal as admin - Thu, Aug 11 2022
- End of support for Office (2013, 2016, 2019):No Microsoft 365 access, and outdated OS versions - Thu, Aug 4 2022
A common task when working with the command prompt is to write the output of commands to a file. As with cmd.exe, PowerShell supports the redirection of output but has more options. PowerShell also comes with a couple of cmdlets that support further features.
Whether you want to permanently save the output of complex calculations or log details of a script, you usually need a procedure to redirect the console output to a file. You can accomplish this job using redirect operators that work in a way that is similar to the conventional command prompt (at least as long as the task is relatively simple). If you just want to redirect the regular and successful output of a command to a file, the redirect operators “>” and “>>” are all you need:
Get-Process > process.out
If process.out already exists, PowerShell would overwrite the file’s previous contents, in contrast to the next example where the redirected output will be appended to the file:
Get-Process >> process.out
Redirecting five output streams ^
In addition to the actual results, most cmdlets and scripts return further information such as errors, warnings, and status messages. If a script is supposed to return data through the appropriate streams, its programmer has to follow a few rules. In particular, this means that he has to use the suitable cmdlets to write the information to the right stream. For instance, Write-Debug, Write-Verbose, and Write-Warning are cmdlets that are typically used to deliver information about the command processing.
Whereas cmd.exe is only able to redirect error messages to an alternative device, PowerShell supports five different output types (streams):
- Success output
- Warning messages
- Verbose output
- Debug messages
To redirect only a particular output type, you have to add the stream number to the redirect operator:
Get-Process 5> debug.out
Like usual, this command would display a list of the running processes, whereas all debug information would be written to debug.out. If you want to append the file with debug data, you would use 5>> instead.
Redirecting to different streams ^
If you want to redirect to another stream instead of to a file, the redirect operator expects the following syntax:
“m” stands for the stream that you want to redirect, and “n” represents the target stream. For example, the following command redirects debug information to the regular output stream of Get-Process:
If you want to redirect not only a single stream but all streams, PowerShell allows you to work with wildcards:
Get-Process *> process.out
This command redirects the contents of all five streams to process.out. The same command can be used with “>>” in order to append the data to the file. Redirecting all streams to a single stream is just as admissible:
Splitting output with tee ^
If you redirect the output of a command to a file, the data is no longer available in the pipeline to process it with another cmdlet. Sticking with the above example, if you want to write the entire output of Get-Process to a file and only display the attributes ID, Name, and CPU, the following command wouldn’t work:
Get-Process > process.out | Select ID, Name, CPU
In this case, nothing would arrive at Select and, accordingly, its output would be empty. The remedy for this is the Tee-Object cmdlet, which splits the output like its UNIX counterpart. This enables you to store the output in a file and process it on the console, where you can pass it through the pipeline to another cmdlet:
Get-Process | Tee process.out | Select ID, Name, CPU
Splitting output with Tee-Object
Using additional options with Out-File ^
In most cases, redirecting via “>” and “>>” proves to be sufficient to write the desired information to a file. However, these operators only allow you to overwrite or append files, and they don’t offer any options. In contrast, the Out-File cmdlet comes with a variety of additional features such as the ability to use another character set, work with an alternative line length, or store data in write-protected files. It accepts input through the pipeline or the -InputObject parameter:
Out-File -FilePath .\temp.out -Width 256 -InputObject $(Get-Process) -Encoding ascii -Force
This command writes the output of Get-Process to the file temp.out, uses the ASCII character set, and sets the line length to 256 characters to ensure that no information is lost in the table.
Because of the -Force parameter, Out-File would overwrite an existing file without warning even if the read-only attribute is set. If you want to append the output to a file, you have to use the -NoClobber parameter.
Alternatively, you can pass the output of Get-Process to Out-File through the pipeline:
Get-Process | Out-File temp.out -Width 256 -Encoding ascii -Force
Writing to multiple files ^
Because the redirect operators and Out-File don’t accept wildcards for file names, you can only use them to write to one file. This is usually sufficient when you only want to save the output of a command.
However, if you want to update the contents of multiple files, the cmdlets Set-Content and Add-Content are suitable for the task. The first one replaces the contents of the specified file, whereas the latter appends the data to the file.
Set-Content cannot modify existing text in the file; it creates new files with the contents that you pass through the -Value parameter. If you only want to replace distinct strings, you have to first read all files with Get-Content, process the contents with simple substitution patterns or regular expressions, and then write back the result with Set-Content.
However, it is easier if you only want to append information to existing files. In this case, you can pass one or more file names, separated by commas, through the parameter -Path. It is also possible to target several files with the help of wildcards. The parameter -Value takes the output of the corresponding cmdlet as input:
Add-Content *.out, *.xml -Value $(Get-Date)