PoshCode Logo PowerShell Code Repository

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

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