PoshCode Logo PowerShell Code Repository

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

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