Summary: Ed Wilson, Microsoft Scripting Guy, talks about creating a sortable transcript name.
Microsoft Scripting Guy, Ed Wilson, is here. One of the great things about Windows PowerShell is that if there is something that annoys you, you can generally fix it. Don’t get me wrong, Windows PowerShell is great, but like any program, there are things that annoy me. It is partly because I have different needs than a typical user—I have never been typical in my life.
For example, I think that all of the defaults in Windows Explorer are wrong for me. For example, I want to see file extensions, I want to see hidden and system files, and I really want to know by looking at the name, if the file is encrypted or compressed—and all of these settings are exactly the opposite.
But with a billion users worldwide, I can imagine that we have done extensive research, and that the settings are exactly right for the vast majority of those billion users. And I know that by using Windows PowerShell, I can fix my Windows issues pretty easily.
If it is easy to fix many of my Windows issues, it is really easy to fix my Windows PowerShell issues. What am I talking about today?
Well, I am talking about the Windows PowerShell transcript feature. I love the Windows PowerShell transcript feature, but what I don’t like is the name generates automatically by the Windows PowerShell transcript feature. Oh, it is great, and the fact that we throw in a random number means I can start the transcript many times per second, and never get a file name conflict.
But dude, that is just it. At least on my laptop, I can barely start the Windows PowerShell transcript tool every two or three seconds, so I don’t need that level of precision in the file name. In fact, with the name as it stands, I cannot sort by file name. It comes out, well, rather random. So I decided to change that with my own function that I will place in my Windows PowerShell profile.
The problem with the default name
The default Windows PowerShell transcript name includes the words PowerShell_Transcript (which is cool), the name of the computer (which is also cool), then a random number, and finally the date string. It is the random number that is a bit of a problem. In addition, the date string is all one number, and it is a bit cumbersome to read. Here is a typical default transcript name:
PowerShell_transcript.EDLT.Dz6sxz6B.20150720151906.txt
When I look at the transcripts in the Windows Explorer, the files are somewhat jumbled. Of course, I can click and sort by date, but that is an extra click that I don’t want to do. Also, if I am sorting in Windows PowerShell, it is also another step to sort by date. Here is a screenshot of the default transcripts.
A better file name
I like having PowerShell_Transcript in the file name, and I prefer the capital T in the name. I also like the idea of having the computer name in the file so it is easy to find related transcripts if I happen to copy them to a file share. The random number needs to go, and then I want a sortable date-time string. I can easily get a sortable date-time string from Get-Date by using Format s from the .NET DateTime object. This is shown here:
PS C:\> Get-Date -format s
2015-07-21T12:35:37
The problem with this is that I cannot use a colon in a file name—it is invalid. How do I remember this? Well, as shown here, there is a static method from the System.Io.Path .NET framework class:
[io.path]::GetInvalidFileNamechars()
So once I know all of the invalid file name characters, I can easily replace them by using the –Replace operator and supplying a replacement value, such as an underscore. And that is what I do. I store my sortable date in a variable, I store my disallowed file name characters in a variable, and I then call the –Replace operator to fix the sortable time into something I can use.
Because I need something I can replace and I cannot do a replacement operation on a DateTime object, I convert my date to string by calling the ToString method. I then use the –f format specifier, and do a substitution to create my new file name. The entire function is shown here:
Function Get-TranscriptName
{
$invalidChars = [io.path]::GetInvalidFileNamechars()
$date = Get-Date -format s
"{0}.{1}.{2}.txt" -f "PowerShell_Transcript", $env:COMPUTERNAME,
($date.ToString() -replace "[$invalidChars]","-") }
Now, I simply add it to my Windows PowerShell profile.
But I still need to fix my call to Start-Transcript. Start-Transcript has a –path parameter, which is the path to the folder and the file name. So I need to create a path. I do this by using the $doc variable that I previously defined as pointing to the document folder in my profile:
New-Variable -Name doc -Value "$home\documents"
I call my function to create the file name. To do this, I need a subexpression (which means to run the function), get the output, and THEN use it in my path. The command is shown here:
Start-Transcript -Path (Join-Path –Path $doc -ChildPath $(Get-TranscriptName))
In my profile, I use the function to determine if I am running in a Windows PowerShell console:
Function Test-ConsoleHost
{
if(($host.Name -match 'consolehost')) {$true}
Else {$false}
}
I also created an alias to the function:
Set-Alias -Name tch -Value Test-ConsoleHost | out-null
When I call the command to start the transcript, I first check to see if I am running in the Windows PowerShell console:
If(tch) {Start-Transcript -Path (Join-Path -Path `
$doc -ChildPath $(Get-TranscriptName))}
When I check for Windows PowerShell transcripts, the files appear in order:
Here is the complete Windows PowerShell profile:
#------------------------------------------------------------------------------
#
# PowerShell console profile
# ed wilson, msft
#
# NOTES: contains five types of things: aliases, functions, psdrives,
# variables and commands.
# version 1.1
# 7/20/2015
# HSG 7-23-2015
#------------------------------------------------------------------------------
#Aliases
Set-Alias -Name ep -Value edit-profile | out-null
Set-Alias -Name tch -Value Test-ConsoleHost | out-null
#Functions
Function Edit-Profile
{ ISE $profile }
Function Test-ConsoleHost
{
if(($host.Name -match 'consolehost')) {$true}
Else {$false}
}
Function Get-TranscriptName
{
$invalidChars = [io.path]::GetInvalidFileNamechars()
$date = Get-Date -format s
"{0}.{1}.{2}.txt" -f "PowerShell_Transcript", $env:COMPUTERNAME,
($date.ToString() -replace "[$invalidChars]","-") }
#Variables
New-Variable -Name doc -Value "$home\documents"
#PS_Drives
New-PSDrive -Name Mod -Root ($env:PSModulePath -split ';')[0] `
-PSProvider FileSystem | out-null
#Commands
Set-Location c:\
If(tch) {Start-Transcript -Path (Join-Path -Path `
$doc -ChildPath $(Get-TranscriptName))}
That is all there is to using Windows PowerShell to create a sortable file name. Profile Week will continue tomorrow when I will talk about more cool stuff.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy