Wednesday, January 17, 2007

Transcript & search

While experimenting your way in PS> you have probably tested some new commands, browsed some websites, copied and pasted some code into the console and tested their output, closing and re-opening PS> and all over again. Along the way, when you wanted to reproduce the commands, you typed them With some mistakes, the console returns error messages and you are pulling your hair out trying to figure out what is wrong, while wishing you could travel back in time, but this is not possible.

PS> comes to your help with a cmdlet called Start-Transcript (there is also Stop-Transcript) . You can tell PS> to record your sessions by typing Start-Transcript (you can also include it in your profile to automate the action each time you launch PS>).

Finding your command history is instantaneous. PS> records all the commands and command output as you typed them into the console, and at the same time writes them to a text file (similar to the Tee-object).

Running Start-Transcript with no parameters will write a text file to the default file location (My Documents) with a file name similar to PowerShell_transcript.20070114225720.txt So, Here is the relevant portion of my PS> profile file:

New-PSDrive -name PSS -Psprovider FileSystem -root "E:\PowerShell\Scripts"

function Record-Session{
   param(
     
[string]$logname,
      [string]$path
   )

   $path="$path\PSLOG_$logname.log"
   if(Test-Path $path) {Start-Transcript $path -append} else{Start-Transcript $path -force}
}

Set-Alias recse Record-Session recse -path pss:"\history" -logname (Get-Date).ToString("dd-MM-yyyy")

 

The first line defines a new PSdrive for my PS> scripts folder. So, instead of writing the whole path, I can use pss: to access its content (this can also be achieved by creating a new environment variable). Inside the new PSDrive I created a folder named "History" that will contain all the PS> session recordings.

If you choose to include Start-Transcript in your profile file, each time you open PS> the console will show that the Transcript has started (see below for more details regarding this), the output file is:

C:\Documents and Settings\Administrator\MyDocuments\PowerShell_transcript.20070114225720.txt

As this cmdlet delivers the goods, if you open and close PS> 50 times a day or more (I recommend leaving it open all day long), at list 50 transcript files will be created (one for each session) and the folder that contains the files will contain multiple files, dramatically increasing the used space when working with PS> on a daily basis.

To overcome this, the Record-Session was written in a way that the default location for saving the files can be changed, a new file name pattern will be applied and only one transcript file will be generated per day.

The Record-Session function takes two parameters. One for the path to the History folder, and another to the log file name in a format of "PSLOG_dd-MM-yyyy.log". In the last lines, a new alias is made and called for the Record-Session:

Set-Alias recse Record-Session recse -path pss:"\history" -logname (Get-Date).ToString("dd-MM-yyyy")

Note that parameter names can be used when invoking the alias "recse". To quickly search the transcript files (or any other files) just type:

Get-ChildItem pss:"\history" -filter *.log | Select-String -pattern "administrator"

This command will pipe each transcript file it finds under the History folder to the Select-String cmdlet in order to find "administrator". You can supply a regex pattern to the -pattern parameter. Now, when running it on my computer I got an error message.

Select-String : The file can not be read: E:\PowerShell\Scripts\history\PSLOG_14-01-2007.log At line:1 char:66+ Get-ChildItem pss:"\history" -filter *.log -force | Select-String <<<< -pattern "administrator".

I suspect the error caused by trying to open the current (locked) transcript file that is in use by PS>, so searching inside the current transcript file cannot take place. I added the -force parameter to avoid such errors.

Get-ChildItem pss:"\history" -filter *.log -force | Select-String -pattern "administrator"

It didn't help so I tried another variation with -ErrorAction (shorter version -ea), one that will "Resume Next" and wont stop the process:

Get-ChildItem pss:"\history" -filter *.log | Select-String -pattern "administrator" -ErrorAction SilentlyContinue

This time I got a ton of output. Piping it to "more" gave me the option to page the results: Get-ChildItem pss:"\history" -filter *.log | Select-String -pattern "administrator" -ErrorAction SilentlyContinue | more

The matched output is in the format of: FullPathToTheFile:LineNumber:MatchedLineText or
E:\PowerShell\Scripts\history\PSLOG_13-01-2007.log:4:Username : SHAY\Administrator

If a case-sensitive search is required, consider adding the -casesensitive parameter to the Select-String cmdlet. Finally, to display a summary of matches per file you can use:

Get-ChildItem pss:"\history" -filter *.log | Select-String -pattern "administrator" -ea silentlycontinue | group-object Filename | sort-object count -desc | ft count,name -autosize

Count Name
-----    ----
1156    PSLOG_11-01-2007.log 55 PSLOG_12-01-2007.log 15 PSLOG_13-01-2007.log

 

$hay

No comments: