PoshCode Logo PowerShell Code Repository

Start-Demo 3.5.0 by Wojciech Sciesin 11 months ago (modification of post by Wojciech Sciesin view diff)
diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/6399"></script>download | new post

This is an overhaul of Jeffrey Snover’s original Start-Demo script … I’ve switched it to use ReadKey, which saves you some typing and makes the whole thing seem more natural when you’re demoing, (at least to me). I’ve also added a bunch of command-line options and a couple of features in the process (see the Revision History in the script).

  1. ## Start-Demo.ps1
  2. ##################################################################################################
  3. ## This is an overhaul of Jeffrey Snover's original Start-Demo script by Joel "Jaykul" Bennett
  4. ##
  5. ## I've switched it to using ReadKey instead of ReadLine (you don't have to hit Enter each time)
  6. ## As a result, I've changed the names and keys for a lot of the operations, so that they make
  7. ## sense with only a single letter to tell them apart (sorry if you had them memorized).
  8. ##
  9. ## I've also been adding features as I come across needs for them, and you'll contribute your
  10. ## improvements back to the PowerShell Script repository as well.
  11. ##################################################################################################
  12. ## Revision History (version 3.5.0)
  13. ## 3.5.0 Added:    StartDelay parameter added
  14. ##       Added:    SkipInstructions parameter added
  15. ##       Added:    The help section 'Improving ideas' added
  16. ##       Addde:    DelayAfterComment switch added, add wait time after write comments to screen
  17. ##       Fixed:    Some comments to code added
  18. ##       Fixed:    Restoring oryginal prompt corrected
  19. ## 3.4.1 Fixed:    Switches SkipAddTheEndLine and SkipAddDemoTime corrected
  20. ## 3.4.0 Fixed:    FullAuto mode corrected
  21. ##       Fixed:    Small corrections of code based on PSScriptAnalyzer 1.6.0 sugestions
  22. ##       Added:    Console window title will be set back after a demo end
  23. ##       Added:    Own custom prompt can be used under demo
  24. ##       Added:    SkipAddTheEndLine switch to don't display 'The end' line
  25. ##       Added:    SkipAddDemoTime switch to don't display start/end demo and demo duration in
  26. ##                 a PowerShell console window
  27. ##       Added:    backgroundColor parameter added - now PowerShell console don't need to be black
  28. ## 3.3.3 Fixed:    Script no longer says "unrecognized key" when you hit shift or ctrl, etc.
  29. ##       Fixed:    Blank lines in script were showing as errors (now printed like comments)
  30. ## 3.3.2 Fixed:    Changed the "x" to match the "a" in the help text
  31. ## 3.3.1 Fixed:    Added a missing bracket in the script
  32. ## 3.3 - Added:    Added a "Clear Screen" option
  33. ##     - Added:    Added a "Rewind" function (which I'm not using much)
  34. ## 3.2 - Fixed:    Put back the trap { continue; }
  35. ## 3.1 - Fixed:    No Output when invoking Get-Member (and other cmdlets like it???)
  36. ## 3.0 - Fixed:    Commands which set a variable, like: $files = ls
  37. ##     - Fixed:    Default action doesn't continue
  38. ##     - Changed:  Use ReadKey instead of ReadLine
  39. ##     - Changed:  Modified the option prompts (sorry if you had them memorized)
  40. ##     - Changed:  Various time and duration strings have better formatting
  41. ##     - Enhance:  Colors are settable: prompt, command, comment
  42. ##     - Added:    NoPauseAfterExecute switch removes the extra pause
  43. ##                 If you set this, the next command will be displayed immediately
  44. ##     - Added:    Auto Execute mode (FullAuto switch) runs the rest of the script
  45. ##                 at an automatic speed set by the AutoSpeed parameter (or manually)
  46. ##     - Added:    Automatically append an empty line to the end of the demo script
  47. ##                 so you have a chance to "go back" after the last line of you demo
  48. ##################################################################################################
  49. ## Improving ideas
  50. ## - convert script to function
  51. ## - add padding zero(s) to command number
  52. ## - remove char '?' from the prompt in the FullAuto mode
  53. ##################################################################################################
  54.  
  55. param (
  56.     $file = ".\demo.txt",
  57.     [int]$command = 0,
  58.     [System.ConsoleColor]$promptColor = "Yellow",
  59.     [System.ConsoleColor]$commandColor = "White",
  60.     [System.ConsoleColor]$commentColor = "Green",
  61.     [System.ConsoleColor]$backgroundColor = "black",
  62.         [int]$StartDelay,
  63.         [switch]$SkipInstructions,
  64.     [switch]$FullAuto,
  65.     [int]$AutoSpeed = 3,
  66.         [int]$DelayAfterComment = 1,
  67.         [switch]$NoPauseAfterExecute,
  68.     [switch]$UseMyPrompt, #To customize change definition in the function Prompt (below)
  69.     [switch]$SkipAddTheEndLine,
  70.     [switch]$SkipAddDemoTime    
  71. )
  72.  
  73. $RawUI = $Host.UI.RawUI
  74. $hostWidth = $RawUI.BufferSize.Width
  75. $hostTitle = $RawUI.WindowTitle
  76.  
  77. If ($UseMyPrompt.ispresent) {
  78.     $OryginalPrompt = Get-Content Function:\prompt
  79.     Prompt
  80. }
  81.  
  82. # More about constructing prompts here: https://technet.microsoft.com/en-us/library/hh847739.aspx
  83. Function prompt { "[PS] >" }
  84.  
  85. # A function for reading in a character
  86. function Read-Char() {
  87.     $_OldColor = $RawUI.ForeGroundColor
  88.     $RawUI.ForeGroundColor = "Red"
  89.     $inChar = $RawUI.ReadKey("IncludeKeyUp")
  90.     # loop until they press a character, so Shift or Ctrl, etc don't terminate us
  91.     while ($inChar.Character -eq 0) {
  92.         $inChar = $RawUI.ReadKey("IncludeKeyUp")
  93.     }
  94.     $RawUI.ForeGroundColor = $_OldColor
  95.     return $inChar.Character
  96. }
  97.  
  98.  
  99.  
  100. function Rewind($lines, $index, $steps = 1) {
  101.     $started = $index;
  102.     $index -= $steps;
  103.     while (($index -ge 0) -and ($lines[$index].Trim(" `t").StartsWith("#"))) {
  104.         $index--
  105.     }
  106.     if ($index -lt 0) { $index = $started }
  107.     return $index
  108. }
  109.  
  110. $file = Resolve-Path $file
  111. while (-not (Test-Path $file)) {
  112.     $file = Read-Host "Please enter the path of your demo script (Crtl+C to cancel)"
  113.     $file = Resolve-Path $file
  114. }
  115.  
  116. Clear-Host
  117.  
  118. If ( $StarDelay -gt 0 ) {
  119.         Start-Sleep -seconds $StartDelay
  120. }
  121.  
  122. $_lines = Get-Content $file
  123.  
  124. If (-not $SkipAddTheEndLine.IsPresent) {
  125.     # Append an extra (do nothing) line on the end so we can still go back after the last line.
  126.     $_lines += "Write-Host 'The End'"
  127. }
  128.  
  129. $_starttime = [DateTime]::now
  130.  
  131. #Overwrite original prompt (?)
  132. Write-Host -nonew -back $backgroundColor -fore $promptColor $(" " * $hostWidth)
  133.  
  134. If (-not $SkipAddDemoTime.IsPresent) {
  135.     Write-Host -nonew -back $backgroundColor -fore $promptColor @"
  136. <Demo Started :: $(split-path $file -leaf)>$(' ' * ($hostWidth - (18 + $(split-path $file -leaf).Length)))
  137. "@
  138. }
  139.  
  140. If ( -not ($SkipInstructions.IsPresent -or $FullAuto.IsPresent) ) {
  141.         Write-Host -nonew -back $backgroundColor -fore $promptColor "Press"
  142.         Write-Host -nonew -back $backgroundColor -fore Red " ? "
  143.         Write-Host -nonew -back $backgroundColor -fore $promptColor "for help.$(' ' * ($hostWidth - 17))"
  144.         Write-Host -nonew -back $backgroundColor -fore $promptColor $(" " * $hostWidth)
  145. }
  146.  
  147. # We use a FOR and an INDEX ($_i) instead of a FOREACH because
  148. # it is possible to start at a different location and/or jump
  149. # around in the order.
  150. for ($_i = $Command; $_i -lt $_lines.count; $_i++) {
  151.     # Put the current command in the Window Title along with the demo duration
  152.     $Dur = [DateTime]::Now - $_StartTime
  153.     $RawUI.WindowTitle = "$(if ($dur.Hours -gt 0) { '{0}h ' })$(if ($dur.Minutes -gt 0) { '{1}m ' }){2}s   {3}" -f
  154.     $dur.Hours, $dur.Minutes, $dur.Seconds, $($_Lines[$_i])
  155.    
  156.     # Echo out the commmand to the console with a prompt as though it were real
  157.     Write-Host -nonew -fore $promptColor "[$_i]$([char]0x2265) "
  158.        
  159.         # Comments line from file can be write to the console using $commentColor as a text (not executed)
  160.     if ($_lines[$_i].Trim(" ").StartsWith("#") -or $_lines[$_i].Trim(" ").Length -le 0) {
  161.         Write-Host -fore $commentColor "$($_Lines[$_i])  "
  162.                 Start-Sleep -Seconds $DelayAfterComment
  163.         continue
  164.     }
  165.     else {
  166.         Write-Host -nonew -fore $commandColor "$($_Lines[$_i])  "
  167.     }
  168.    
  169.     if ($FullAuto.IsPresent) { $FullAutoInt = $true; Start-Sleep $autoSpeed; $ch = [char]13 }
  170.     else { $ch = Read-Char }
  171.    
  172.     switch ($ch) {
  173.         "?" {
  174.             Write-Host -Fore $promptColor @"
  175.  
  176. Running demo: $file
  177. (n) Next       (p) Previous
  178. (q) Quit       (s) Suspend
  179. (t) Timecheck  (v) View $(split-path $file -leaf)
  180. (g) Go to line by number
  181. (f) Find lines by string
  182. (a) Auto Execute mode
  183. (c) Clear Screen
  184. "@
  185.             $_i-- # back a line, we're gonna step forward when we loop
  186.         }
  187.         "n" {
  188.             # Next (do nothing)
  189.             Write-Host -Fore $promptColor "<Skipping Line>"
  190.         }
  191.         "p" {
  192.             # Previous
  193.             Write-Host -Fore $promptColor "<Back one Line>"
  194.             while ($_lines[--$_i].Trim(" ").StartsWith("#")) { }
  195.             $_i-- # back a line, we're gonna step forward when we loop
  196.         }
  197.         "a" {
  198.             # EXECUTE (Go Faster)
  199.             $AutoSpeed = [int](Read-Host "Pause (seconds)")
  200.             $FullAutoInt = $true;
  201.             Write-Host -Fore $promptColor "<eXecute Remaining Lines>"
  202.             $_i-- # Repeat this line, and then just blow through the rest
  203.         }
  204.         "q" {
  205.             # Quit
  206.             Write-Host -Fore $promptColor "<Quiting demo>"
  207.             $_i = $_lines.count;
  208.             #Restore oryginal PowerShell host title
  209.             $RawUI.WindowTitle = $hostTitle
  210.             #Restore oryginal PowerShell prompt
  211.             If ($UseMyPrompt.IsPresent) {
  212.                                 Invoke-Expression
  213.             }
  214.             break;
  215.         }
  216.         "v" {
  217.             # View Source
  218.             $lines[0..($_i - 1)] | Write-Host -Fore Yellow
  219.             $lines[$_i] | Write-Host -Fore Green
  220.             $lines[($_i + 1)..$lines.Count] | Write-Host -Fore Yellow
  221.             $_i-- # back a line, we're gonna step forward when we loop
  222.         }
  223.         "t" {
  224.             # Time Check
  225.             $dur = [DateTime]::Now - $_StartTime
  226.             Write-Host -Fore $promptColor $(
  227.                 "{3} -- $(if ($dur.Hours -gt 0) { '{0}h ' })$(if ($dur.Minutes -gt 0) { '{1}m ' }){2}s" -f
  228.                 $dur.Hours, $dur.Minutes, $dur.Seconds, ([DateTime]::Now.ToShortTimeString()))
  229.             $_i-- # back a line, we're gonna step forward when we loop
  230.         }
  231.         "s" {
  232.             # Suspend (Enter Nested Prompt)
  233.             Write-Host -Fore $promptColor "<Suspending demo - type 'Exit' to resume>"
  234.             $Host.EnterNestedPrompt()
  235.             $_i-- # back a line, we're gonna step forward when we loop
  236.         }
  237.         "g" {
  238.             # GoTo Line Number
  239.             $i = [int](Read-Host "line number")
  240.             if ($i -le $_lines.Count) {
  241.                 if ($i -gt 0) {
  242.                     # extra line back because we're gonna step forward when we loop
  243.                     $_i = Rewind $_lines $_i (($_i - $i) + 1)
  244.                 }
  245.                 else {
  246.                     $_i = -1 # Start negative, because we step forward when we loop
  247.                 }
  248.             }
  249.         }
  250.         "f" {
  251.             # Find by pattern
  252.             $match = $_lines | Select-String (Read-Host "search string")
  253.             if ([String]::IsNullOrEmpty($match)) {
  254.                 Write-Host -Fore Red "Can't find a matching line"
  255.             }
  256.             else {
  257.                 $match | ForEach-Object -Process { Write-Host -Fore $promptColor $("[{0,2}] {1}" -f ($_.LineNumber - 1), $_.Line) }
  258.                 if ($match.Count -lt 1) {
  259.                     $_i = $match.lineNumber - 2 # back a line, we're gonna step forward when we loop
  260.                 }
  261.                 else {
  262.                     $_i-- # back a line, we're gonna step forward when we loop
  263.                 }
  264.             }
  265.         }
  266.         "c" {
  267.             Clear-Host
  268.             $_i-- # back a line, we're gonna step forward when we loop
  269.         }
  270.         "$([char]13)" {
  271.             # on enter
  272.             Write-Host
  273.             trap [System.Exception] { Write-Error $_; continue; }
  274.             Invoke-Expression ($_lines[$_i]) | out-default
  275.             if (-not $NoPauseAfterExecute -and -not $FullAutoInt) {
  276.                 $null = $RawUI.ReadKey("NoEcho,IncludeKeyUp") # Pause after output for no apparent reason... ;)
  277.             }
  278.         }
  279.         default {
  280.             Write-Host -Fore Green "`nKey not recognized.  Press ? for help, or ENTER to execute the command."
  281.             $_i-- # back a line, we're gonna step forward when we loop
  282.         }
  283.     }
  284. }
  285. $dur = [DateTime]::Now - $_StartTime
  286. If (-not $SkipAddDemoTime.IsPresent) {
  287.     Write-Host -Fore $promptColor $(
  288.         "<Demo Complete -- $(if ($dur.Hours -gt 0) { '{0}h ' })$(if ($dur.Minutes -gt 0) { '{1}m ' }){2}s>" -f
  289.         $dur.Hours, $dur.Minutes, $dur.Seconds, [DateTime]::Now.ToLongTimeString())
  290.     Write-Host -Fore $promptColor $([DateTime]::now)
  291. }
  292. Write-Host
  293. #Restore oryginal PowerShell host title
  294. $RawUI.WindowTitle = $hostTitle
  295. #Restore oryginal PowerShell prompt
  296. If ($UseMyPrompt.IsPresent) {
  297.     Invoke-Expression -Command "Function Prompt { $OryginalPrompt }" -ErrorAction SilentlyContinue
  298. }

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me