Start-TypedDemo.ps1
Function Start-TypedDemo { [cmdletBinding(DefaultParameterSetName = "Random")] [Alias("std")] Param( [Parameter(Position = 0, Mandatory = $True, HelpMessage = "Enter the name of a text file with your demo commands")] [ValidateScript( {Test-Path $_})] [string]$File, [ValidateScript( {$_ -gt 0})] [Parameter(ParameterSetName = "Static")] [int]$Pause = 80, [Parameter(ParameterSetName = "Random")] [ValidateScript( {$_ -gt 0})] [int]$RandomMinimum = 50, [Parameter(ParameterSetName = "Random")] [ValidateScript( {$_ -gt 0})] [int]$RandomMaximum = 140, [Parameter(ParameterSetName = "Random")] [string]$Transcript, [switch]$NoExecute, [switch]$NewSession ) #this is an internal function so I'm not worried about the name Function PauseIt { [cmdletbinding()] Param() Write-Verbose "PauseIt" #wait for a key press $Running = $true #keep looping until a key is pressed While ($Running) { if ($host.ui.RawUi.KeyAvailable) { $key = $host.ui.RawUI.ReadKey("NoEcho,IncludeKeyDown") if ($key) { $Running = $False #check the value and if it is q or ESC, then bail out if ($key -match "q|27") { Write-Host "`r" Return "quit" } #if match q|27 } #if $key } #if key available Start-Sleep -millisecond 100 } #end While } #PauseIt function #abort if running in the ISE if ($host.name -match "PowerShell ISE") { Write-Warning "This will not work in the ISE. Use the PowerShell console host." Return } Clear-Host if ($NewSession) { #simulate a new PowerShell session #define a set of coordinates $z = new-object System.Management.Automation.Host.Coordinates 0, 0 #year is no longer part of the output #$year = '2016' $header = @" Windows PowerShell Copyright (C) Microsoft Corporation. All rights reserved. `r "@ Write-Host $header } #if new session #Start a transcript if requested $RunningTranscript = $False if ($Transcript) { Try { Start-Transcript -Path $Transcript -ErrorAction Stop | Out-Null $RunningTranscript = $True } Catch { Write-Warning "Could not start a transcript. One may already be running." } } #strip out all comments and blank lines Write-Verbose "Getting commands from $file" $commands = Get-Content -Path $file | Where {$_ -notmatch "#" -AND $_ -match "\w|::|{|}|\(|\)"} $count = 0 #write a prompt using your current prompt function Write-Verbose "prompt" Write-Host $(prompt) -NoNewline $NoMultiLine = $True $StartMulti = $False #define a scriptblock to get typing interval Write-Verbose "Defining interval scriptblock" $interval = { if ($pscmdlet.ParameterSetName -eq "Random") { #get a random pause interval Get-Random -Minimum $RandomMinimum -Maximum $RandomMaximum } else { #use the static pause value $Pause } } #end Interval scriptblock Write-Verbose "Defining PipeCheck Scriptblock" #define a scriptblock to pause at a | character in case an explanation is needed $PipeCheck = { if ($command[$i] -eq "|") { If ((PauseIt) -eq "quit") {Return} } } #end PipeCheck scriptblock Write-Verbose "Processing commands" foreach ($command in $commands) { #trim off any spaces $command = $command.Trim() $count++ #pause until a key is pressed which will then process the next command if ($NoMultiLine) { If ((PauseIt) -eq "quit") {Return} } #SINGLE LINE COMMAND if ($command -ne "::" -AND $NoMultiLine) { Write-Verbose "single line command" for ($i = 0; $i -lt $command.length; $i++) { #write the character Write-Verbose "Writing character $($command[$i])" Write-Host $command[$i] -NoNewline #insert a pause to simulate typing Start-sleep -Milliseconds $(&$Interval) &$PipeCheck } #remove the backtick line continuation character if found if ($command.contains('`')) { $command = $command.Replace('`', "") } #Pause until ready to run the command If ((PauseIt) -eq "quit") {Return} Write-host "`r" #execute the command unless -NoExecute was specified if (-NOT $NoExecute) { Invoke-Expression $command | Out-Default } else { Write-Host $command -ForegroundColor Cyan } } #IF SINGLE COMMAND #START MULTILINE #skip the :: elseif ($command -eq "::" -AND $NoMultiLine) { $NoMultiLine = $False $StartMulti = $True #define a variable to hold the multiline expression [string]$multi = "" } #elseif #FIRST LINE OF MULTILINE elseif ($StartMulti) { for ($i = 0; $i -lt $command.length; $i++) { if ($IncludeTypo -AND ($(&$Interval) -ge ($RandomMaximum - 5))) { &$Typo } else { write-host $command[$i] -NoNewline} #else start-sleep -Milliseconds $(&$Interval) #only check for a pipe if we're not at the last character #because we're going to pause anyway if ($i -lt $command.length - 1) { &$PipeCheck } } #for $StartMulti = $False #remove the backtick line continuation character if found if ($command.contains('`')) { $command = $command.Replace('`', "") } #add the command to the multiline variable $multi += " $command" # if (!$command.Endswith('{')) { $multi += ";" } if ($command -notmatch ",$|{$|}$|\|$|\($") { $multi += " ; " } If ((PauseIt) -eq "quit") {Return} } #elseif #END OF MULTILINE elseif ($command -eq "::" -AND !$NoMultiLine) { Write-host "`r" Write-Host ">> " -NoNewline $NoMultiLine = $True If ((PauseIt) -eq "quit") {Return} #execute the command unless -NoExecute was specified Write-Host "`r" if (-NOT $NoExecute) { Invoke-Expression $multi | Out-Default } else { Write-Host $multi -ForegroundColor Cyan } } #elseif end of multiline #NESTED PROMPTS else { Write-Host "`r" Write-Host ">> " -NoNewLine If ((PauseIt) -eq "quit") {Return} for ($i = 0; $i -lt $command.length; $i++) { if ($IncludeTypo -AND ($(&$Interval) -ge ($RandomMaximum - 5))) { &$Typo } else { Write-Host $command[$i] -NoNewline } Start-Sleep -Milliseconds $(&$Interval) &$PipeCheck } #for #remove the backtick line continuation character if found if ($command.contains('`')) { $command = $command.Replace('`', "") } #add the command to the multiline variable and include the line break #character $multi += " $command" # if (!$command.Endswith('{')) { $multi += ";" } if ($command -notmatch ",$|{$|\|$|\($") { $multi += " ; " #$command } } #else nested prompts #reset the prompt unless we've just done the last command if (($count -lt $commands.count) -AND ($NoMultiLine)) { Write-Host $(prompt) -NoNewline } } #foreach #stop a transcript if it is running if ($RunningTranscript) { #stop this transcript if it is running Stop-Transcript | Out-Null } } #function |