{"id":71982,"date":"2015-07-23T00:01:00","date_gmt":"2015-07-23T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2015\/07\/23\/sorting-powershell-transcript-files\/"},"modified":"2019-02-18T09:46:53","modified_gmt":"2019-02-18T16:46:53","slug":"sorting-powershell-transcript-files","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/sorting-powershell-transcript-files\/","title":{"rendered":"Sorting PowerShell Transcript Files"},"content":{"rendered":"<p><b style=\"font-size:12px\">Summary<\/b><span style=\"font-size:12px\">: Ed Wilson, Microsoft Scripting Guy, talks about creating a sortable transcript name.<\/span><\/p>\n<p>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&rsquo;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&mdash;I have never been typical in my life.<\/p>\n<p>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&mdash;and all of these settings are exactly the opposite.<\/p>\n<p>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.<\/p>\n<p>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?<\/p>\n<p>Well, I am talking about the Windows PowerShell transcript feature. I love the Windows PowerShell transcript feature, but what I don&rsquo;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.<\/p>\n<p>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&rsquo;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.<\/p>\n<h2>The problem with the default name<\/h2>\n<p>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:<\/p>\n<p style=\"margin-left:30px\">PowerShell_transcript.EDLT.Dz6sxz6B.20150720151906.txt<\/p>\n<p>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&rsquo;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.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/Hsg-7-23-1501.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/Hsg-7-23-1501.png\" alt=\"Image of menu\" title=\"Image of menu\" \/><\/a><\/p>\n<h2>A better file name<\/h2>\n<p>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 <b>Get-Date<\/b> by using <b>Format s<\/b> from the .NET <b>DateTime<\/b> object. This is shown here:<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt; Get-Date -format s<\/p>\n<p style=\"margin-left:30px\">2015-07-21T12:35:37<\/p>\n<p>The problem with this is that I cannot use a colon in a file name&mdash;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:<\/p>\n<p style=\"margin-left:30px\">[io.path]::GetInvalidFileNamechars()<\/p>\n<p>So once I know all of the invalid file name characters, I can easily replace them by using the <b>&ndash;Replace<\/b> 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 <b>&ndash;Replace<\/b> operator to fix the sortable time into something I can use.<\/p>\n<p>Because I need something I can replace and I cannot do a replacement operation on a <b>DateTime<\/b> object, I convert my date to string by calling the <b>ToString<\/b> method. I then use the <b>&ndash;f<\/b> format specifier, and do a substitution to create my new file name. The entire function is shown here:<\/p>\n<p style=\"margin-left:30px\">Function Get-TranscriptName<\/p>\n<p style=\"margin-left:30px\">{<\/p>\n<p style=\"margin-left:30px\">&nbsp;$invalidChars = [io.path]::GetInvalidFileNamechars()<\/p>\n<p style=\"margin-left:30px\">&nbsp;$date = Get-Date -format s<\/p>\n<p style=\"margin-left:30px\">&nbsp; &quot;{0}.{1}.{2}.txt&quot; -f &quot;PowerShell_Transcript&quot;, $env:COMPUTERNAME,<\/p>\n<p style=\"margin-left:30px\">&nbsp; ($date.ToString() -replace &quot;[$invalidChars]&quot;,&quot;-&quot;) }<\/p>\n<p>Now, I simply add it to my Windows PowerShell profile.<\/p>\n<p>But I still need to fix my call to <b>Start-Transcript<\/b>. <b>Start-Transcript<\/b> has a <b>&ndash;path<\/b> 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 <b>$doc<\/b> variable that I previously defined as pointing to the document folder in my profile:<\/p>\n<p style=\"margin-left:30px\">New-Variable -Name doc -Value &quot;$home\\documents&quot;<\/p>\n<p>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:<\/p>\n<p style=\"margin-left:30px\">Start-Transcript -Path (Join-Path &ndash;Path $doc -ChildPath $(Get-TranscriptName))<\/p>\n<p>In my profile, I use the function to determine if I am running in a Windows PowerShell console:<\/p>\n<p style=\"margin-left:30px\">Function Test-ConsoleHost<\/p>\n<p style=\"margin-left:30px\">{<\/p>\n<p style=\"margin-left:30px\">&nbsp;if(($host.Name -match &#039;consolehost&#039;)) {$true}<\/p>\n<p style=\"margin-left:30px\">&nbsp;Else {$false}&nbsp;&nbsp;<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p>I also created an alias to the function:<\/p>\n<p style=\"margin-left:30px\">Set-Alias -Name tch -Value Test-ConsoleHost | out-null<\/p>\n<p>When I call the command to start the transcript, I first check to see if I am running in the Windows PowerShell console:<\/p>\n<p style=\"margin-left:30px\">If(tch) {Start-Transcript -Path (Join-Path -Path `<\/p>\n<p style=\"margin-left:30px\">&nbsp;$doc -ChildPath $(Get-TranscriptName))}<\/p>\n<p>When I check for Windows PowerShell transcripts, the files appear in order:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/Hsg-7-23-1502.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/Hsg-7-23-1502.png\" alt=\"Image of menu\" title=\"Image of menu\" \/><\/a><\/p>\n<p>Here is the complete Windows PowerShell profile:<\/p>\n<p style=\"margin-left:30px\">#&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<\/p>\n<p style=\"margin-left:30px\">#<\/p>\n<p style=\"margin-left:30px\"># PowerShell console profile<\/p>\n<p style=\"margin-left:30px\"># ed wilson, msft<\/p>\n<p style=\"margin-left:30px\">#<\/p>\n<p style=\"margin-left:30px\"># NOTES: contains five types of things: aliases, functions, psdrives,<\/p>\n<p style=\"margin-left:30px\"># variables and commands.<\/p>\n<p style=\"margin-left:30px\"># version 1.1<\/p>\n<p style=\"margin-left:30px\"># 7\/20\/2015<\/p>\n<p style=\"margin-left:30px\"># HSG 7-23-2015<\/p>\n<p style=\"margin-left:30px\">#&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<\/p>\n<p style=\"margin-left:30px\">#Aliases<\/p>\n<p style=\"margin-left:30px\">Set-Alias -Name ep -Value edit-profile | out-null<\/p>\n<p style=\"margin-left:30px\">Set-Alias -Name tch -Value Test-ConsoleHost | out-null<\/p>\n<p style=\"margin-left:30px\">#Functions<\/p>\n<p style=\"margin-left:30px\">Function Edit-Profile<\/p>\n<p style=\"margin-left:30px\">{ ISE $profile }<\/p>\n<p style=\"margin-left:30px\">Function Test-ConsoleHost<\/p>\n<p style=\"margin-left:30px\">{<\/p>\n<p style=\"margin-left:30px\">&nbsp;if(($host.Name -match &#039;consolehost&#039;)) {$true}<\/p>\n<p style=\"margin-left:30px\">&nbsp;Else {$false}&nbsp;&nbsp;<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p style=\"margin-left:30px\">Function Get-TranscriptName<\/p>\n<p style=\"margin-left:30px\">{<\/p>\n<p style=\"margin-left:30px\">&nbsp;$invalidChars = [io.path]::GetInvalidFileNamechars()<\/p>\n<p style=\"margin-left:30px\">&nbsp;$date = Get-Date -format s<\/p>\n<p style=\"margin-left:30px\">&nbsp; &quot;{0}.{1}.{2}.txt&quot; -f &quot;PowerShell_Transcript&quot;, $env:COMPUTERNAME,<\/p>\n<p style=\"margin-left:30px\">&nbsp; ($date.ToString() -replace &quot;[$invalidChars]&quot;,&quot;-&quot;) }<\/p>\n<p style=\"margin-left:30px\">#Variables<\/p>\n<p style=\"margin-left:30px\">New-Variable -Name doc -Value &quot;$home\\documents&quot;<\/p>\n<p style=\"margin-left:30px\">#PS_Drives<\/p>\n<p style=\"margin-left:30px\">New-PSDrive -Name Mod -Root ($env:PSModulePath -split &#039;;&#039;)[0] `<\/p>\n<p style=\"margin-left:30px\">&nbsp;-PSProvider FileSystem | out-null<\/p>\n<p style=\"margin-left:30px\">#Commands<\/p>\n<p style=\"margin-left:30px\">Set-Location c:\\<\/p>\n<p style=\"margin-left:30px\">If(tch) {Start-Transcript -Path (Join-Path -Path `<\/p>\n<p style=\"margin-left:30px\">&nbsp;$doc -ChildPath $(Get-TranscriptName))}<\/p>\n<p>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.<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b><\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>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&rsquo;t get me wrong, Windows PowerShell is great, but like any program, there [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[51,144,3,4,45],"class_list":["post-71982","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-getting-started","tag-profiles","tag-scripting-guy","tag-scripting-techniques","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>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&rsquo;t get me wrong, Windows PowerShell is great, but like any program, there [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/71982","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=71982"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/71982\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=71982"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=71982"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=71982"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}