One of the keys to keeping a system secure is to be able to keep a log of all of the activities being performed on the system. If you suspect nefarious activity, you can go back through the security logs to determine who has been using the system, and what they have been doing. When it comes to PowerShell, this type of logging has always been challenging. PowerShell has its own transcription feature, but historically this feature has suffered from a couple of major limitations. Thankfully, there is now a better way to leverage PowerShell transcription logs to check on activity.
Native PowerShell transcription logs
For most of PowerShell’s history, the primary tool for logging PowerShell activity has been the Start-Transcript cmdlet. Simply enter this cmdlet followed by a path and filename for the log file that you want to create. PowerShell will populate the log file with every subsequent command that is entered. The figure below shows an example of the Start-Transcript cmdlet being used. Incidentally, you can disable the transcription by using the Stop-Transcript cmdlet.
The transcripts that PowerShell generates are actually quite impressive. As you can see in the screenshot below, the Start-Transcript cmdlet writes a header to the log file. This header lists things like the username, machine name, and the date and time when the transcript was started (among other things). As you enter commands into PowerShell, the transcription engine not only logs the commands, but also the command output. In the figure below for example, you can see that I had used the Get-VM cmdlet to display a list of the Hyper-V virtual machines that exist on the PC. The transcript not only shows that this cmdlet was used, it also shows me the output that appeared within the PowerShell console when the command was run.
As nice as this transcript may be, it does have some significant limitations. For starters, you will notice that the transcript does not log the date and time when the individual commands were entered. Being able to tell when a command was used can be important if you ever have to perform a forensic analysis of the system.
A second major limitation is that transcription, at least as I have talked about it so far, has to be manually enabled. Remember that PowerShell did not start transcribing my activities until after I used the Start-Transcript command.
A third major limitation to PowerShell’s transcription capabilities is that transcription is tied to an individual session. If I were to open another PowerShell window, or even switch to another PowerShell window that was already open, the commands that I enter within that window would not be written to the transcript. The same can also be said for PowerShell ISE. PowerShell treats each individual PowerShell window as a separate session. When you use the Start-Transcript cmdlet, PowerShell only transcribes commands from the session within which the cmdlet was entered.
Now this brings up an important point. Even though the Start-Transcript cmdlet does not provide system wide transcription capabilities, it does not mean that there is no record of the activities that are being performed on the system. The Windows event logs capture user and system activities regardless of whether those activities were performed through the GUI or through PowerShell.
Why use PowerShell transcription logs?
Being that PowerShell’s native transcription capabilities have to be manually enabled and cannot cross session boundaries, I suspect that PowerShell transcription probably was not designed to be a security feature but rather a development tool. I have on occasion used transcription as a tool when I am developing a script. I enable transcription, and then begin typing the commands that I intend to use in the script. When I am done, I open the transcript and delete the header, the outputs, and any commands that did not work quite the way that I intended. I then take what is left, and save it as a PS1 file.
There is a better way
If you like the idea of using PowerShell transcription as a security feature, but are concerned about the limitations of conventional transcripts, then you will be happy to know that a better option exists. Rather than relying on the Start-Transcript cmdlet, you can instead enable transcription at the group policy level.
To do so, open the Group Policy Object Editor and then navigate through the console tree to Computer Configuration | Administrative Templates | Windows Components | Windows PowerShell. As you can see in the figure below, there is a group policy setting called Turn on PowerShell Transcription. Enabling this setting results in the system wide transcription of PowerShell cmdlets. It also keeps you from having to manually start the transcription process.
You can enable PowerShell transcription at the group policy level by using the Turn on PowerShell Transcription setting. Once enabled, the system wide transcription feature logs PowerShell use on a per user basis. If a user enters a PowerShell command, a record of that command is written to a document within that user’s My Documents folder.
If you would rather log PowerShell usage in a more centralized way, then you can use the group policy setting to specify an output folder, as shown in the figure below. Just be sure to apply the appropriate permissions to the folder.
In case you are wondering, the system wide transcription functionality works the same way as using the Start-Transcript cmdlet. The only difference is that you do not have to manually enter the cmdlet, and transcriptions work across multiple sessions and even support PowerShell ISE.
More on PowerShell transcription capabilities
PowerShell’s transcription capabilities can be useful both as a security tool and as an engineering tool (for the development of scripts). If you are intending to use transcription for security purposes, then make sure to configure the Group Policy setting to write the transcript data to a location that isn’t obvious to the end users. Otherwise, someone wishing to cover their tracks could easily erase the transcript. You can read more about enhanced transcription for PowerShell here.