Over the years I've posted variations on this technique and discuss it often in my training classes. The idea is to take your PowerShell transcript and transform it into a PowerShell script. Remember that there is very little difference between running commands in the shell and in a script. Thus, any commands that have been captured by a transcript should be able to be executed in a script.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
First you'll need a transcript. At your PowerShell prompt run Start-Transcript. Actually, first look at cmdlet help. I prefer giving my transcript a name.
Start-Transcript c:\work\fridayfun.txt
Now run all the commands that you think you'd like to use in your script. Don't worry if you get errors. Keep working until you get the commands you want. You're going to clean up your script file anyway. If you are done, you can run Stop-Transcript. Or if you close your PowerShell session the transcript will automatically be closed.
Now you're going to need my Export-Transcript function.
Function Export-Transcript { [cmdletbinding(SupportsShouldProcess=$True)] Param ( [Parameter(Position=0,Mandatory=$True,HelpMessage="Enter the path and filename to a PowerShell transcript.")] [ValidateNotNullOrEmpty()] [string]$Transcript, [Parameter(Position=1,Mandatory=$True,HelpMessage="Enter the path and filename for the script.")] [ValidateNotNullOrEmpty()] [string]$Script, [switch]$NoClobber ) #verify transcript file can be found if (! (test-path $Transcript)) { Write-Error "$Transcript can't be found!" Return } #define an array for the script content $content=@() #define a script header $header=@" #Requires -version 2.0 <# $("#"*100) Name : $(Split-Path -Path $Script -Leaf) Created: $(Get-Date) Source : $Transcript Author : $env:username Company: $env:userdomain PSVersionTable $(($PSVersionTable | Out-String).Trim()) Current Host $(($host | format-list Name,Version,*Culture | out-String).Trim()) $("#"*100) #> Set-StrictMode -Version Latest "@ #add the header to content $content+=$header Write-Verbose "Filtering content from $Transcript" $filteredLog=Get-Content $Transcript | Select-String "> " Write-Verbose "Processing $($filteredLog.count) command lines" # drop the last line which is likely a stop-transcript command for ($i=0;$i -lt $filteredLog.length-1;$i++) { #each item in $filteredlog is actually a MatchInfo object which #we need to treat as a string $line=$filteredLog[$i].ToString() Write-Verbose $line #find the first > in the line $idx=$line.IndexOf(">") #get everything after the first > $cmd=$line.Substring($idx+1) #add the line to the new content, trimming off any spaces $content+=$cmd.Trim() } Write-Verbose "Creating script file" If ( (Test-Path -Path $Script) -AND ($NoClobber)) { Write-Verbose "NoClobber specified and file exists." Write-Warning "NoClobber specified and $script exists." } else { $content | Out-File -FilePath $Script Write-Verbose ("Finished exporting {0}. See {1} for your script." -f $Transcript,$script) Get-Item -Path $Script } } #end function
Once the function is loaded into your PowerShell session, run it specifying the transcript and the name of your new script file.
PS C:\> Export-Transcript c:\work\fridayfun.txt c:\scripts\MyNewScript.ps1
The function creates a new script file, overwriting any previous versions unless you use -NoClobber.
Write-Verbose "Creating script file" If ( (Test-Path -Path $Script) -AND ($NoClobber)) { Write-Verbose "NoClobber specified and file exists." Write-Warning "NoClobber specified and $script exists." } else { $content | Out-File -FilePath $Script Write-Verbose ("Finished exporting {0}. See {1} for your script." -f $Transcript,$script) Get-Item -Path $Script } [
The contents of the script consist of a header that includes a variety of metadata I thought you most likely would want.
#define a script header $header=@" #Requires -version 2.0 <# $("#"*100) Name : $(Split-Path -Path $Script -Leaf) Created: $(Get-Date) Source : $Transcript Author : $env:username Company: $env:userdomain PSVersionTable $(($PSVersionTable | Out-String).Trim()) Current Host $(($host | format-list Name,Version,*Culture | out-String).Trim()) $("#"*100) #> Set-StrictMode -Version Latest "@ #add the header to content $content+=$header
The main part of the function gets the transcript content where the line contains the ">" character.
Write-Verbose "Filtering content from $Transcript" $filteredLog=Get-Content $Transcript | Select-String "> "
The assumption is that your Powershell prompt, which is captured int he transcript is something like PS C:\somewhere\>. The end result is that $FilteredLog contains only the command lines. Don't worry if it captures non-command lines that just might have a ? character since you always need to edit the resulting script file. Think of my function as a rapid prototyping tool; you still need to refine and validate the script.
Moving on. Each line is then parsed using the Substring method so that it starts at the location of the first > +1 character.
# drop the last line which is likely a stop-transcript command for ($i=0;$i -lt $filteredLog.length-1;$i++) { #each item in $filteredlog is actually a MatchInfo object which #we need to treat as a string $line=$filteredLog[$i].ToString() Write-Verbose $line #find the first > in the line $idx=$line.IndexOf(">") #get everything after the first > $cmd=$line.Substring($idx+1) #add the line to the new content, trimming off any spaces $content+=$cmd.Trim() }
Each "command" is added to the $content array. After everything has been processed $content is written to the new file and presto, chango you have a script! Open the script file in your editor of choice and take it from there. Clean up commands you don't want. Add additional comments. Add help. Fortunately, you've already worked out the majority of code in your PowerShell session so creating a script shouldn't take that much time.
I hope this helps speed up your script development.
Download Export-Transcript.
Deja Vu – We have a feature in PowerSE that records the command history for the embedded PowerShell console and lets you use that command history to create a script. The funny thing is, we were talking about how cool this feature is and that we need to mention it more, and then I see you writing an article about the same functionality directly from the normal PS prompt.
The challenge, regardless, is that I don’t think a lot of people use transcripts.
Agreed – I had pretty much forgotten about them until I saw your post, and even before that only heard them mentioned a few times. One of those cool features people forget about.
Great Article. This is perfect for the IT Admin who is fighting PowerShell, but has no choice as it’s quickly becoming THE management interface for all Windows Products. By poking around, following the examples (ex. PowerShell generated by the GUI tools from Exchange or VMM); they would find it’s not so bad. They don’t have to professional scripts to benefit.
I posted a quick video showing how to use this feature.