Prof. Powershell

Command History Lesson Part 2: PowerShell 3.

Here's how to capture PowerShell commands and history in PowerShell 3.

In our last lesson we explored some different techniques for capturing PowerShell commands and history. In PowerShell v3 and later we have another option, although it is limited to commands stored in modules. You can enable logging on a per module basis.

One way is manually through the shell. I'm going to enable it for the CIM cmdlets so I'll need to run a CIM cmdlet or import the module.

PS C:\> Import-Module CIMCmdlets

By default, logging is disabled.

PS C:\> get-module cimcmdlets | select LogPipelineExecutionDetails

                                             LogPipelineExecutionDetails
---------------------------
False

But I can turn it on.

PS C:\> (get-module cimcmdlets).LogPipelineExecutionDetails = $true

Now, whenever I execute a CIM cmdlet, an event is recorded in the Windows PowerShell event log.

PS C:\> get-ciminstance win32_operatingsystem -computer chi-hvr2

There's no indication in the console that anything happened. But if I look in the Windows PowerShell log I will see an Information entry for ID 800.

You can see my result in Figure 1.

[Click on image for larger view.]  Figure 1.

This will continue for any cmdlet for as long as my PowerShell session is open. Logging will only capture commands created in this host. If I run a CIM command in the PowerShell ISE it will not be logged. Although I'll show you how later.

I can look at events in the event viewer or use PowerShell.

PS C:\> get-eventlog "Windows PowerShell" -InstanceId 800 | Select TimeGenerated,Message | Format-Table –wrap

In figure 2 I've highlighted what command was run and how.

[Click on image for larger view.]  Figure 2.

One thing you could do with this output is to use regular expressions to pull out information like the user name and command line.

[regex]$cmd="CommandLine=.*"
[regex]$user="UserId=.*\\.*"
[regex]$script="ScriptName=.*"

Get-Eventlog "Windows PowerShell" -InstanceId 800 |
Select MachineName,TimeGenerated,
@{Name="UserID";Expression={$user.Matches($_.Message).Value.Split("=")[1].Trim()}},
@{Name="Command";Expression={$cmd.Matches($_.Message).Value.Split("=")[1].Trim()}},
@{Name="Script";Expression={$script.Matches($_.Message).Value.Split("=")[1].Trim()}} | Out-Gridview -title "CIM Command Log"

My result can be seen in Figure 3.

[Click on image for larger view.]  Figure 3.

This type of l006Fgging won't help for any command that doesn't ship in a module. Commands in a PSSnapin will not be logged either. Also, this assumes the command completed successfully. If a command fails you won't see the command. Error information can be found, but not easily surfaced. But if this is of interest, you can continue to enable on a per module basis as needed. Or next time I'll show you a better way.

About the Author

Jeffery Hicks is an IT veteran with over 25 years of experience, much of it spent as an IT infrastructure consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He is a multi-year recipient of the Microsoft MVP Award in Windows PowerShell. He works today as an independent author, trainer and consultant. Jeff has written for numerous online sites and print publications, is a contributing editor at Petri.com, and a frequent speaker at technology conferences and user groups.

comments powered by Disqus
Most   Popular