Automatically Keep Log of PowerShell ISE Commands


Summary: Ed Wilson, Microsoft Scripting Guy, talks about using the new transcript command in the Windows PowerShell ISE.

Hey, Scripting Guy! Question Hey, Scripting Guy! I might be alone in this, but I love using the transcript tool in the Windows PowerShell console. I really wish I could have a transcript in the Windows PowerShell ISE because that is what I use to write scripts. But every time I try to use it, I get a bogus error message that says basically, "Go jump in a lake." How rude. I am just complaining, and I really don’t expect that there is anything you can actually do about this sad state of affairs. Oh, yeah, for what it is worth, I love reading your blog. It is the bomb. Respectfully yours,

—DH

Hey, Scripting Guy! Answer Hello DH,

Microsoft Scripting Guy, Ed Wilson, is here. DH, I love getting email like yours sent to my scripter@microsoft.com email address. "Why?" you may ask. Well for one thing, I love to hear from people who read the Hey, Scripting Guy! Blog. But there is an even better reason...

In Windows PowerShell 5.0, we introduced the Start-Transcript cmdlet to the Windows PowerShell ISE. Yes, that is right. You were not the only one who complained about not having a transcript tool in the Windows PowerShell ISE. As a matter of fact, I even wrote one myself that I used for many years. But that is no longer necessary because WooHoo, Start-Transcript now works in the ISE.

The transcript tool in the PowerShell ISE

Like in the Windows PowerShell console, I can use the Start-Transcript cmdlet to start a transcript of what happens in the Windows PowerShell ISE. All I need to do is to type Start-Transcript. However, I like to capture the output of the command. This is because the transcript gets basically hidden. Well, not actually hidden, it goes into the Documents folder in my profile location. It also has a long random—a very long random—file name. Actually, it is a random number and letter combination, and then the date, time, and seconds. Still, it is rather painful to navigate. The command and its output are shown here:

PS C:\> Start-Transcript

Transcript started, output file is C:\Users\mredw\Documents\PowerShell_transcript.ED

LT.EW1t8ikl.20151106110936.txt

When I am done, I can type Stop-Transcript. If I do, it will nicely display the location of the transcript:

PS C:\> Stop-Transcript

Transcript stopped, output file is C:\Users\mredw\Documents\PowerShell_transcript.ED

LT.EW1t8ikl.20151106110936.txt

If I close the Windows PowerShell ISE while the transcript is running, it automatically stops the transcription and I need to use Start-Transcript to start it again.

Unfortunately, as you can see here, the Start-Transcript and Stop-Transcript cmdlets return a string:

PS C:\> Start-Transcript | gm

   TypeName: System.String

Name             MemberType            Definition                                  

----                    ----------                 ----------                                  

Clone            Method                System.Object Clone(), System.Object IClon...

CompareTo        Method                int CompareTo(System.Object value), int Co...

Contains         Method                bool Contains(string value)                 

CopyTo           Method                void CopyTo(int sourceIndex, char[] destin...

EndsWith         Method                bool EndsWith(string value), bool EndsWith...

Equals           Method                bool Equals(System.Object obj), bool Equal...

GetEnumerator    Method                System.CharEnumerator GetEnumerator(), Sys...

GetHashCode      Method                int GetHashCode()                           

GetType          Method                type GetType()                              

GetTypeCode      Method                System.TypeCode GetTypeCode(), System.Type...

IndexOf          Method                int IndexOf(char value), int IndexOf(char ...

IndexOfAny       Method                int IndexOfAny(char[] anyOf), int IndexOfA...

Insert           Method                string Insert(int startIndex, string value) 

IsNormalized     Method                bool IsNormalized(), bool IsNormalized(Sys...

LastIndexOf      Method                int LastIndexOf(char value), int LastIndex...

LastIndexOfAny   Method                int LastIndexOfAny(char[] anyOf), int Last...

Normalize        Method                string Normalize(), string Normalize(Syste...

PadLeft          Method                string PadLeft(int totalWidth), string Pad...

PadRight         Method                string PadRight(int totalWidth), string Pa...

Remove           Method                string Remove(int startIndex, int count), ...

Replace          Method                string Replace(char oldChar, char newChar)...

Split            Method                string[] Split(Params char[] separator), s...

StartsWith       Method                bool StartsWith(string value), bool Starts...

Substring        Method                string Substring(int startIndex), string S...

ToBoolean        Method                bool IConvertible.ToBoolean(System.IFormat...

ToByte           Method                byte IConvertible.ToByte(System.IFormatPro...

ToChar           Method                char IConvertible.ToChar(System.IFormatPro...

ToCharArray      Method                char[] ToCharArray(), char[] ToCharArray(i...

ToDateTime       Method                datetime IConvertible.ToDateTime(System.IF...

ToDecimal        Method                decimal IConvertible.ToDecimal(System.IFor...

ToDouble         Method                double IConvertible.ToDouble(System.IForma...

ToInt16          Method                int16 IConvertible.ToInt16(System.IFormatP...

ToInt32          Method                int IConvertible.ToInt32(System.IFormatPro...

ToInt64          Method                long IConvertible.ToInt64(System.IFormatPr...

ToLower          Method                string ToLower(), string ToLower(culturein...

ToLowerInvariant Method                string ToLowerInvariant()                   

ToSByte          Method                sbyte IConvertible.ToSByte(System.IFormatP...

ToSingle         Method                float IConvertible.ToSingle(System.IFormat...

ToString         Method                string ToString(), string ToString(System....

ToType           Method                System.Object IConvertible.ToType(type con...

ToUInt16         Method                uint16 IConvertible.ToUInt16(System.IForma...

ToUInt32         Method                uint32 IConvertible.ToUInt32(System.IForma...

ToUInt64         Method                uint64 IConvertible.ToUInt64(System.IForma...

ToUpper          Method                string ToUpper(), string ToUpper(culturein...

ToUpperInvariant Method                string ToUpperInvariant()                   

Trim             Method                string Trim(Params char[] trimChars), stri...

TrimEnd          Method                string TrimEnd(Params char[] trimChars)     

TrimStart        Method                string TrimStart(Params char[] trimChars)   

Path             NoteProperty          string Path=C:\Users\mredw\Documents\Power...

Chars            ParameterizedProperty char Chars(int index) {get;}                

Length           Property              int Length {get;}                           

This means that I cannot pipe Stop-Transcript to Notepad to automatically display the transcript log. In the past, I wrote a function that would parse the string and return the path to the transcript log. I could then use that with Notepad to display the transcript. Now, however, I do not need to do that. I can instead use the ConvertFrom-String cmdlet.

Here is an example...

First I capture the returned string from Start-Transcript into a variable. I then use ConvertFrom-String to parse the string. The data I want is the path to the transcript log, and it appears in property P6. This is shown here:

PS C:\> $a = Start-Transcript

PS C:\> $a | ConvertFrom-String

P1 : Transcript

P2 : started,

P3 : output

P4 : file

P5 : is

P6 : C:\Users\mredw\Documents\PowerShell_transcript.EDLT.6tTqSZcx.20151106111543.txt

After I do some work, and then stop the transcript, I can examine the log. In the following code, I stop the transcript, and then access the transcript log to display it in Notepad.

PS C:\> Stop-Transcript

Transcript stopped, output file is C:\Users\mredw\Documents\PowerShell_transcript.ED

LT.6tTqSZcx.20151106111543.txt

PS C:\> ($a | ConvertFrom-String).p6

C:\Users\mredw\Documents\PowerShell_transcript.EDLT.6tTqSZcx.20151106111543.txt

PS C:\> notepad ($a | ConvertFrom-String).p6

The log is shown in the following image:

Image of log

As you can see, the log contains a lot of default information that could be useful in troubleshooting. It shows the user name, the computer name, and version of the operating system. It lists the host application and the process ID and the versions of WSMan, Windows PowerShell, the CLR, and other pertinent information. It also shows the command I typed and the command to stop the transcript. In addition, it shows when the transcript was started. It does not, however, show when each command ran or when the transcript stopped. One solution to this issue is to modify the prompt with a time stamp.

Other than that, the transcript works well. So, DH, there is good news after all. All you need is Windows PowerShell 5.0.

Now you understand a bit about using the Windows PowerShell ISE transcript tool.  Join me 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 

Comments (5)

  1. Jos Lieben says:

    This is indeed quite an improvement. One thing I did notice is that Start-Transcript does not work when the script runs under the SYSTEM (NT AuthoritySYSTEM) account.

  2. PetSerAl says:

    Not very good solution for finding transcript file name. First, it is language dependent. Other languages can have different number of words in translation of "Transcript started, output file is". For example, in Russian it take four words, not five. Second,
    full file name of transcript file can have spaces in it.

    If you carefully look at Get-Member output, then you can notice "Path NoteProperty", the property that normal string does not have. Why does not use it instead?

    notepad $a.Path

  3. PetSerAl says:

    You could also use -IncludeInvocationHeader parameter to Start-Transcript, so that invocation time of each command preserved in transcript file. And transcript stop time is always added in transcript file, you just need to scroll your notepad’s window
    a bit.

  4. Gary Smith says:

    I have been using this command for several years to capture the ISE Console output (PS version 2):
    $psise.CurrentPowerShellTab.Output.text > $outputfile where $outputfile can contain any path and file name. I embed date/time stamps in the file name for uniqueness.
    The original; reference for this idea was:
    http://powershell.com/cs/forums/p/13964/26600.aspx

  5. postanote says:

    Why struggle with it that way, when you can directly tell Start-Transcript what to call the log and where to put it.

    Start-Transcript -Path $env:USERPROFILEDocumentsSessionTranscript.log

    Then just use Get-Content to bring it into the console or notepad to get it there

    You are in the ISE, why op notepad. Just use the ISE (its a better notepad that notepad.exe IMHO)
    psedit PathToYourFile

    Write a script in ISE, test the script in ISE, output the file result to ISE
    Heck, even give it a customer name each time vs. the default ugly one.

    Here is one of my old version on how I tackled this.
    (I pulled together a function that I put in my profile and all my scripts for this nowadays.)

    # Set the tab title
    $host.ui.rawui.WindowTitle = $env:USERNAME + ‘_’ + $(get-date).Tostring(‘ddMMMyyyy_HHmmss’)

    # use that to dynamically set the file name
    $SessionLog = Start-Transcript ($host.ui.rawui.WindowTitle + ".txt")

    # do some stuff you want recorded.
    Get-Service
    # or whatever

    # Stop the session
    $SessionLog = Stop-Transcript

    # Dynamically determine whether you are in ISE or Console Host
    $MsgResults = Read-Host ‘Do you want view ‘ $SessionLog.Path
    If ($MsgResults -eq ‘Y’)
    {
    If ($Host.Name -eq ‘Windows PowerShell ISE Host’)
    {psedit $SessionLog.Path }
    else {notepad $SessionLog.Path }
    }
    else {Write-Host "8^) you don’t wnat to see the contents’"}

    # Remove the log if no longer needed
    $MsgResults = Read-Host ‘Do you want to remove / delete ‘ $SessionLog.Path

    If ($MsgResults -eq ‘Y’) {Remove-Item $SessionLog.Path}
    else {Write-Host ‘So, you want to keep this file around. Good for you. It just might come in handy later.’}

    As for
    Jos’s comment
    Start-Transcript does not work when the script runs under the SYSTEM (NT AuthoritySYSTEM) account.

    That it default to writing to your $Userprofile and SYSTEM (NT AuthoritySYSTEM) does not have one.

    again, the script above, just change the path to where you want the file to go.

    # use that to dynamically set the file name
    $SessionLog = Start-Transcript ("C:Temp" + ($host.ui.rawui.WindowTitle + ".txt"))

    # Results from running the same sample above as NT AuthoritySYSTEM, with a direct point to a storage location works as well. I have done this on many occasions as needed

    Just…
    C:UsersAdministrator>C:ToolsSysinternalsSuitePsExec.exe -accepteula -i -s %SystemRoot%system32cmd.exe
    C:Windowssystem32>whoami
    nt authoritysystem

    C:Windowssystem32>powershell

    PS C:Windowssystem32> C:temptest1.ps1
    Running wudfsvc Windows Driver Foundation – User-mo…
    Running ZeroConfigService Intel(R) PROSet/Wireless Zero Confi…
    Do you want view C:TempLW530$_11Nov2015_222951.txt: y
    Do you want to remove / delete C:TempLW530$_11Nov2015_222951.txt: y

    PS C:Windowssystem32> whoami
    nt authoritysystem
    PS C:Windowssystem32> exit

    C:Windowssystem32>

Skip to main content