{"id":1473,"date":"2011-05-27T09:28:59","date_gmt":"2011-05-27T13:28:59","guid":{"rendered":"http:\/\/jdhitsolutions.com\/blog\/?p=1473"},"modified":"2015-07-13T10:07:08","modified_gmt":"2015-07-13T14:07:08","slug":"friday-fun-start-typeddemo-v2","status":"publish","type":"post","link":"https:\/\/jdhitsolutions.com\/blog\/scripting\/1473\/friday-fun-start-typeddemo-v2\/","title":{"rendered":"Friday Fun: Start-TypedDemo v2"},"content":{"rendered":"<p>Not too long ago I <a href=\"http:\/\/jdhitsolutions.com\/blog\/2011\/05\/start-typeddemo\/\" target=\"_blank\">posted a function<\/a> I wrote for doing PowerShell demonstrations. My goal was to simulate a live interactive demo but without the typing so I could focus on explaining and not typing. The first version was a good start but I always had plans for a more feature complete function including typos, support for multiline expressions and transcription. That's what I have for today's Friday Fun.<!--more--><\/p>\n<p>As always, the download file includes comment based help.<\/p>\n<pre class=\"lang:ps decode:true \" >Function Start-TypedDemo {\r\n\r\n[cmdletBinding(DefaultParameterSetName=\"Random\")]\r\n\r\nParam(\r\n[Parameter(Position=0,Mandatory=$True,HelpMessage=\"Enter the name of a text file with your demo commands\")]\r\n[ValidateScript({Test-Path $_})]\r\n[string]$File,\r\n[ValidateScript({$_ -gt 0})]\r\n[Parameter(ParameterSetName=\"Static\")]\r\n[int]$Pause=100,\r\n[Parameter(ParameterSetName=\"Random\")]\r\n[ValidateScript({$_ -gt 0})]\r\n[int]$RandomMinimum=50,\r\n[Parameter(ParameterSetName=\"Random\")]\r\n[ValidateScript({$_ -gt 0})]\r\n[int]$RandomMaximum=200,\r\n[Parameter(ParameterSetName=\"Random\")]\r\n[switch]$IncludeTypo,\r\n[string]$Transcript,\r\n[switch]$NoExecute,\r\n[switch]$NewSession\r\n)\r\n\r\n#this is an internal function so I'm not worried about the name\r\nFunction PauseIt {\r\n\r\nParam()\r\n    #wait for a key press\r\n    $Running=$true\r\n    #keep looping until a key is pressed\r\n    While ($Running)\r\n    {\r\n     if ($host.ui.RawUi.KeyAvailable) {\r\n     $key = $host.ui.RawUI.ReadKey(\"NoEcho,IncludeKeyDown\")\r\n        if ($key) {\r\n         $Running=$False  \r\n         #check the value and if it is q or ESC, then bail out\r\n         if ($key -match \"q|27\") {\r\n           Write-Host `r\r\n           Return \"quit\"\r\n           }        \r\n        }\r\n      }\r\n      start-sleep -millisecond 100\r\n    } #end While\r\n} #PauseIt function\r\n\r\n#abort if running in the ISE\r\nif ($host.name -match \"PowerShell ISE\") {\r\n    Write-Warning \"This will not work in the ISE. Use the PowerShell console host.\"\r\n    Return\r\n}\r\n\r\nClear-Host\r\n\r\nif ($NewSession)\r\n{\r\n    #simulate a new session\r\n    #define a set of coordinates\r\n    $z= new-object System.Management.Automation.Host.Coordinates 0,0\r\n$header=@\"\r\nWindows PowerShell\r\nCopyright (C) 2009 Microsoft Corporation. All rights reserved.\r\n`r\r\n\"@\r\n    Write-Host $header\r\n}\r\n\r\n#Start a transcript if requested\r\n$RunningTranscript=$False\r\n\r\nif ($Transcript)\r\n{\r\n    Try \r\n    {\r\n        Start-Transcript -Path $Transcript -ErrorAction Stop | Out-Null\r\n        $RunningTranscript=$True\r\n    }\r\n    Catch\r\n    {\r\n        Write-Warning \"Could not start a transcript. One may already be running.\"\r\n    }\r\n}\r\n#strip out all comments and blank lines\r\n#$commands=Get-Content -Path $file | Where {-NOT $_.StartsWith(\"#\") -AND $_ -match \"\\w\"}\r\n$commands=Get-Content -Path $file | Where {-NOT $_.StartsWith(\"#\") -AND $_ -match \"\\w|::|{|}|\\(|\\)\"}\r\n\r\n$count=0\r\n\r\n#write a prompt using your current prompt function\r\nWrite-Host $(prompt) -NoNewline\r\n\r\n$NoMultiLine=$True \r\n$StartMulti=$False\r\n\r\n#define a scriptblock to get typing interval\r\n$interval={\r\n if ($pscmdlet.ParameterSetName -eq \"Random\")\r\n     {\r\n        #get a random pause interval\r\n        Get-Random -Minimum $RandomMinimum -Maximum $RandomMaximum\r\n     }\r\n     else \r\n     {\r\n        #use the static pause value\r\n        $Pause\r\n     }\r\n} #end Interval scriptblock \r\n\r\n#typo scriptblock\r\n$Typo={\r\n   #an array of characters to use for typos\r\n        $matrix=\"a\",\"s\",\"d\",\"f\",\"x\",\"q\",\"w\",\"e\",\"r\",\"z\",\"j\",\"t\",\"x\",\"c\",\"v\",\"b\"\r\n        #Insert a random bad character\r\n        Write-host \"$($matrix | get-random) \" -nonewline\r\n        Start-Sleep -Milliseconds 500\r\n        #simulate backspace \r\n        Write-host `b -NoNewline\r\n        start-sleep -Milliseconds 300       \r\n        Write-host `b -NoNewline\r\n        start-sleep -Milliseconds 200       \r\n        Write-Host $command[$i] -NoNewline \r\n } #end Typo Scriptblock\r\n\r\n#define a scriptblock to pause at a | character in case an explanation is needed\r\n$PipeCheck={\r\n     if ($command[$i] -eq \"|\") {\r\n        If (PauseIt -eq \"quit\") {Return}\r\n     }\r\n} #end PipeCheck scriptblock\r\n\r\nforeach ($command in $commands) {\r\n   #trim off any spaces\r\n   $command=$command.Trim()\r\n   $count++\r\n   #pause until a key is pressed which will then process the next command\r\n   if ($NoMultiLine) {\r\n    If (PauseIt -eq \"quit\") {Return}\r\n   }\r\n   \r\n#SINGLE LINE COMMAND\r\n    if ($command -ne \"::\" -AND $NoMultiLine) {            \r\n      for ($i=0;$i -lt $command.length;$i++) {\r\n     \r\n     #simulate errors if -IncludeTypo\r\n     if ($IncludeTypo -AND ($(&amp;$Interval) -ge ($RandomMaximum-5)))\r\n     {  &amp;$Typo  } #if includetypo\r\n     else\r\n     { #write the character\r\n        write-host $command[$i] -NoNewline\r\n     }\r\n     #insert a pause to simulate typing\r\n     Start-sleep -Milliseconds $(&amp;$Interval)\r\n     \r\n     &amp;$PipeCheck\r\n     \r\n    }\r\n    #Pause until ready to run the command \r\n    If (PauseIt -eq \"quit\") {Return}\r\n    Write-host `r\r\n    #execute the command unless -NoExecute was specified\r\n    if (-NOT $NoExecute) {\r\n        Invoke-Expression $command | Out-Default\r\n    }\r\n   } #IF SINGLE COMMAND\r\n#START MULTILINE  \r\n    #skip the ::     \r\n    elseif ($command -eq \"::\" -AND $NoMultiLine) {\r\n     $NoMultiLine=$False\r\n     $StartMulti=$True\r\n     #define a variable to hold the multiline expression\r\n     [string]$multi=\"\"\r\n  } #elseif\r\n#FIRST LINE OF MULTILINE\r\n    elseif ($StartMulti) {\r\n       for ($i=0;$i -lt $command.length;$i++) {\r\n        if ($IncludeTypo -AND ($(&amp;$Interval) -ge ($RandomMaximum-5)))\r\n        { &amp;$Typo  } \r\n        else   { write-host $command[$i] -NoNewline} #else\r\n        start-sleep -Milliseconds $(&amp;$Interval)\r\n        #only check for a pipe if we're not at the last character\r\n        #because we're going to pause anyway\r\n        if ($i -lt $command.length-1) {\r\n            &amp;$PipeCheck\r\n        }\r\n        } #for\r\n    \r\n        $StartMulti=$False\r\n       \r\n        #add the command to the multiline variable\r\n        $multi+=$command\r\n        \r\n        If (PauseIt -eq \"quit\") {Return}\r\n        \r\n    } #elseif\r\n#END OF MULTILINE\r\n  elseif ($command -eq \"::\" -AND !$NoMultiLine) {\r\n     Write-host `r\r\n     Write-Host \"&gt;&gt; \" -NoNewline\r\n     $NoMultiLine=$True\r\n      If (PauseIt -eq \"quit\") {Return}\r\n     #execute the command unless -NoExecute was specified\r\n    Write-Host `r\r\n    if (-NOT $NoExecute) {\r\n     Invoke-Expression $multi | Out-Default\r\n    }\r\n  }  #elseif end of multiline\r\n#NESTED PROMPTS\r\n else {\r\n    Write-Host `r\r\n    Write-Host \"&gt;&gt; \" -NoNewLine\r\n    If (PauseIt -eq \"quit\") {Return}\r\n    for ($i=0;$i -lt $command.length;$i++) {\r\n      if ($IncludeTypo -AND ($(&amp;$Interval) -ge ($RandomMaximum-5)))\r\n      { &amp;$Typo  } \r\n      else { write-host $command[$i] -NoNewline }\r\n      start-sleep -Milliseconds $(&amp;$Interval)\r\n      &amp;$PipeCheck\r\n    }\r\n    #add the command to the multiline variable\r\n    $multi+=$command\r\n      \r\n   } #else nested prompts  \r\n   \r\n   #reset the prompt unless we've just done the last command\r\n   if (($count -lt $commands.count) -AND ($NoMultiLine)) {\r\n    Write-Host $(prompt) -NoNewline \r\n   } \r\n    \r\n  } #foreach  \r\n  \r\n  #stop a transcript if it is running\r\n  if ($RunningTranscript)\r\n  {\r\n    #stop this transcript if it is running\r\n    Stop-Transcript | out-Null\r\n  }\r\n  \r\n} #function\r\n<\/pre>\n<p>This version lets you use a static interval between characters or you can use a random interval. This interval is a random number of milliseconds between a minimum and maximum value. The function defaults to a random interval and the defaults, at least for me, seem short enough to keep the demo moving yet still give the illusion of typing. If you use the -IncludeTypo parameter, then every once in a while an errant character will be introduced, backspaced, and replaced. As such, I don't recommend using this parameter with the -Transcription parameter as you end up with control characters in the text file which makes it kind of ugly. Personally, I probably won't use the typo feature often but wanted to include it just in case.<\/p>\n<p>This version also includes a parameter so that you can simulate a new PowerShell session. I use this when recording PowerShell content since I can cut out the command that starts the demo and have the video start at what looks like a new PowerShell session complete with the copyright notice.<\/p>\n<pre class=\"lang:ps decode:true \" >if ($NewSession)\r\n{\r\n    #simulate a new session\r\n    #define a set of coordinates\r\n    $z= new-object System.Management.Automation.Host.Coordinates 0,0\r\n$header=@\"\r\nWindows PowerShell\r\nCopyright (C) 2009 Microsoft Corporation. All rights reserved.\r\n`r\r\n\"@\r\n    Write-Host $header\r\n}\r\n<\/pre>\n<p>The last major improvement is support for multiline commands. This was more involved than I expected. My solution is to include a marker (::) that indicates the beginning and end of a multiline command. Thus in your demo file, you would have something like this:<\/p>\n<p><code lang=\"DOS\"><br \/>\ncd c:\\<br \/>\n::<br \/>\nget-wmiobject win32_logicaldisk -filter \"Drivetype=3\" |<br \/>\nSelect Caption,VolumeName,Size,Freespace |<br \/>\nformat-table -autosize<br \/>\n::<br \/>\ngsv spooler<br \/>\n<\/code><\/p>\n<p>The function will parse the script and when it hits a ::, it knows the next line will be the first line of a multiline command.  The lines after that are nested and the function inserts the necessary >> prompt. When it hits the next ::, it knows the end of the multiline has been reached and inserts the last >>. Pressing any key or Enter will execute it just like any other command. <\/p>\n<p>The function takes advantage of parameter sets and uses scriptblocks as a modularization technique. I knew there would be places where I needed to repeat a section of code such as checking if the current character is a | so I can pause the script. So I defined this:<\/p>\n<pre class=\"lang:ps decode:true \" >#define a scriptblock to pause at a | character in case an explanation is needed\r\n$PipeCheck={\r\n     if ($command[$i] -eq \"|\") {\r\n        If (PauseIt -eq \"quit\") {Return}\r\n     }\r\n} #end PipeCheck scriptblock\r\n<\/pre>\n<p>Now, instead of having all that code repeated, I can invoke the scriptblock.<\/p>\n<pre class=\"lang:ps decode:true \" > for ($i=0;$i -lt $command.length;$i++) {\r\n      if ($IncludeTypo -AND ($(&amp;$Interval) -ge ($RandomMaximum-5)))\r\n      { &amp;$Typo  } \r\n      else { write-host $command[$i] -NoNewline }\r\n      start-sleep -Milliseconds $(&amp;$Interval)\r\n      &amp;$PipeCheck\r\n    }\r\n<\/pre>\n<p>I did the same thing to handle the typo code ($Typo) and getting the sleep interval between characters ($Interval). Using the scriptblocks kept these sections shorter and if I found a bug say the typo code, I only had to change it one place.<\/p>\n<p>So download it and try it out, especially if you do any sort of PowerShell presentations. Hopefully I've added enough comments so you can understand what is happening. If you have any comments, questions or suggestions, please let me know. In fact, if your organization is looking for some PowerShell related training of any sort, let me know via <a href=\"mailto:jhicks@jdhitsolutions.com?Subject=Training Request\">email <\/a>and you'll most likely get to see this function in action first hand!<\/p>\n<p>Download <a href='http:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2011\/05\/Start-TypedDemo-v2.txt'  target='_blank'>Start-TypedDemo-v2<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Not too long ago I posted a function I wrote for doing PowerShell demonstrations. My goal was to simulate a live interactive demo but without the typing so I could focus on explaining and not typing. The first version was a good start but I always had plans for a more feature complete function including&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[271,75,114,8,9],"tags":[224,534,82,540,101],"class_list":["post-1473","post","type-post","status-publish","format-standard","hentry","category-friday-fun","category-powershell-v2-0","category-professional","category-scripting","category-training","tag-function","tag-powershell","tag-scriptblock","tag-scripting","tag-write-host"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Friday Fun: Start-TypedDemo v2 &#8226; The Lonely Administrator<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/jdhitsolutions.com\/blog\/scripting\/1473\/friday-fun-start-typeddemo-v2\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Friday Fun: Start-TypedDemo v2 &#8226; The Lonely Administrator\" \/>\n<meta property=\"og:description\" content=\"Not too long ago I posted a function I wrote for doing PowerShell demonstrations. My goal was to simulate a live interactive demo but without the typing so I could focus on explaining and not typing. The first version was a good start but I always had plans for a more feature complete function including...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/jdhitsolutions.com\/blog\/scripting\/1473\/friday-fun-start-typeddemo-v2\/\" \/>\n<meta property=\"og:site_name\" content=\"The Lonely Administrator\" \/>\n<meta property=\"article:published_time\" content=\"2011-05-27T13:28:59+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2015-07-13T14:07:08+00:00\" \/>\n<meta name=\"author\" content=\"Jeffery Hicks\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@JeffHicks\" \/>\n<meta name=\"twitter:site\" content=\"@JeffHicks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jeffery Hicks\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/1473\\\/friday-fun-start-typeddemo-v2\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/1473\\\/friday-fun-start-typeddemo-v2\\\/\"},\"author\":{\"name\":\"Jeffery Hicks\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"headline\":\"Friday Fun: Start-TypedDemo v2\",\"datePublished\":\"2011-05-27T13:28:59+00:00\",\"dateModified\":\"2015-07-13T14:07:08+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/1473\\\/friday-fun-start-typeddemo-v2\\\/\"},\"wordCount\":561,\"commentCount\":5,\"publisher\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"keywords\":[\"Function\",\"PowerShell\",\"ScriptBlock\",\"Scripting\",\"Write-Host\"],\"articleSection\":[\"Friday Fun\",\"PowerShell v2.0\",\"Professional\",\"Scripting\",\"Training\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/1473\\\/friday-fun-start-typeddemo-v2\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/1473\\\/friday-fun-start-typeddemo-v2\\\/\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/1473\\\/friday-fun-start-typeddemo-v2\\\/\",\"name\":\"Friday Fun: Start-TypedDemo v2 &#8226; The Lonely Administrator\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#website\"},\"datePublished\":\"2011-05-27T13:28:59+00:00\",\"dateModified\":\"2015-07-13T14:07:08+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/1473\\\/friday-fun-start-typeddemo-v2\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/1473\\\/friday-fun-start-typeddemo-v2\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/scripting\\\/1473\\\/friday-fun-start-typeddemo-v2\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Friday Fun\",\"item\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/category\\\/friday-fun\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Friday Fun: Start-TypedDemo v2\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/\",\"name\":\"The Lonely Administrator\",\"description\":\"Practical Advice for the Automating IT Pro\",\"publisher\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\",\"name\":\"Jeffery Hicks\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"caption\":\"Jeffery Hicks\"},\"logo\":{\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Friday Fun: Start-TypedDemo v2 &#8226; The Lonely Administrator","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/jdhitsolutions.com\/blog\/scripting\/1473\/friday-fun-start-typeddemo-v2\/","og_locale":"en_US","og_type":"article","og_title":"Friday Fun: Start-TypedDemo v2 &#8226; The Lonely Administrator","og_description":"Not too long ago I posted a function I wrote for doing PowerShell demonstrations. My goal was to simulate a live interactive demo but without the typing so I could focus on explaining and not typing. The first version was a good start but I always had plans for a more feature complete function including...","og_url":"https:\/\/jdhitsolutions.com\/blog\/scripting\/1473\/friday-fun-start-typeddemo-v2\/","og_site_name":"The Lonely Administrator","article_published_time":"2011-05-27T13:28:59+00:00","article_modified_time":"2015-07-13T14:07:08+00:00","author":"Jeffery Hicks","twitter_card":"summary_large_image","twitter_creator":"@JeffHicks","twitter_site":"@JeffHicks","twitter_misc":{"Written by":"Jeffery Hicks","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/jdhitsolutions.com\/blog\/scripting\/1473\/friday-fun-start-typeddemo-v2\/#article","isPartOf":{"@id":"https:\/\/jdhitsolutions.com\/blog\/scripting\/1473\/friday-fun-start-typeddemo-v2\/"},"author":{"name":"Jeffery Hicks","@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"headline":"Friday Fun: Start-TypedDemo v2","datePublished":"2011-05-27T13:28:59+00:00","dateModified":"2015-07-13T14:07:08+00:00","mainEntityOfPage":{"@id":"https:\/\/jdhitsolutions.com\/blog\/scripting\/1473\/friday-fun-start-typeddemo-v2\/"},"wordCount":561,"commentCount":5,"publisher":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"keywords":["Function","PowerShell","ScriptBlock","Scripting","Write-Host"],"articleSection":["Friday Fun","PowerShell v2.0","Professional","Scripting","Training"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/jdhitsolutions.com\/blog\/scripting\/1473\/friday-fun-start-typeddemo-v2\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/jdhitsolutions.com\/blog\/scripting\/1473\/friday-fun-start-typeddemo-v2\/","url":"https:\/\/jdhitsolutions.com\/blog\/scripting\/1473\/friday-fun-start-typeddemo-v2\/","name":"Friday Fun: Start-TypedDemo v2 &#8226; The Lonely Administrator","isPartOf":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#website"},"datePublished":"2011-05-27T13:28:59+00:00","dateModified":"2015-07-13T14:07:08+00:00","breadcrumb":{"@id":"https:\/\/jdhitsolutions.com\/blog\/scripting\/1473\/friday-fun-start-typeddemo-v2\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/jdhitsolutions.com\/blog\/scripting\/1473\/friday-fun-start-typeddemo-v2\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/jdhitsolutions.com\/blog\/scripting\/1473\/friday-fun-start-typeddemo-v2\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Friday Fun","item":"https:\/\/jdhitsolutions.com\/blog\/category\/friday-fun\/"},{"@type":"ListItem","position":2,"name":"Friday Fun: Start-TypedDemo v2"}]},{"@type":"WebSite","@id":"https:\/\/jdhitsolutions.com\/blog\/#website","url":"https:\/\/jdhitsolutions.com\/blog\/","name":"The Lonely Administrator","description":"Practical Advice for the Automating IT Pro","publisher":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/jdhitsolutions.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9","name":"Jeffery Hicks","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","url":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","caption":"Jeffery Hicks"},"logo":{"@id":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg"}}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":4445,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/4445\/simulating-a-powershell-demo\/","url_meta":{"origin":1473,"position":0},"title":"Simulating a PowerShell Demo","author":"Jeffery Hicks","date":"July 13, 2015","format":false,"excerpt":"A number of years ago I published my version of a Start-Demo script. In my version, I can create a text file with all of the commands I want to run. It might look like this: Get-Date get-ciminstance win32_logicaldisk | select DeviceID,Size,Freespace :: get-service | where {$_.status -eq 'running'} |\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":4420,"url":"https:\/\/jdhitsolutions.com\/blog\/scripting\/4420\/friday-fun-a-better-psedit\/","url_meta":{"origin":1473,"position":1},"title":"Friday Fun: A Better PSEdit","author":"Jeffery Hicks","date":"May 29, 2015","format":false,"excerpt":"In the PowerShell ISE, there is a built-in function called PSEdit. You can use this function to easily load a file in to the ISE directly from the ISE command prompt. Psedit c:\\scripts\\myscript.ps1 You can also load multiple files, but not as easily as you might like. I find myself\u2026","rel":"","context":"In &quot;Friday Fun&quot;","block_context":{"text":"Friday Fun","link":"https:\/\/jdhitsolutions.com\/blog\/category\/friday-fun\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1404,"url":"https:\/\/jdhitsolutions.com\/blog\/scripting\/1404\/start-typeddemo\/","url_meta":{"origin":1473,"position":2},"title":"Start-TypedDemo","author":"Jeffery Hicks","date":"May 3, 2011","format":false,"excerpt":"As you know, I do a lot of presenting and training. Normally I use the ubiquitous Start-Demo function to run through a demo list of commands. Most of this time this works just fine. But when I'm doing videos, especially for a video project, I want the viewer to focus\u2026","rel":"","context":"In &quot;PowerShell v2.0&quot;","block_context":{"text":"PowerShell v2.0","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell-v2-0\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2330,"url":"https:\/\/jdhitsolutions.com\/blog\/scripting\/2330\/friday-fun-get-latest-powershell-scripts\/","url_meta":{"origin":1473,"position":3},"title":"Friday Fun: Get Latest PowerShell Scripts","author":"Jeffery Hicks","date":"May 18, 2012","format":false,"excerpt":"Probably like many of you I keep almost all of my scripts in a single location. I'm also usually working on multiple items at the same time. Some times I have difficult remembering the name of a script I might have been working on a few days ago that I\u2026","rel":"","context":"In &quot;Friday Fun&quot;","block_context":{"text":"Friday Fun","link":"https:\/\/jdhitsolutions.com\/blog\/category\/friday-fun\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2012\/05\/get-latestscript-300x133.png?resize=350%2C200","width":350,"height":200},"classes":[]},{"id":2193,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/2193\/powershell-scripting-with-validatescript\/","url_meta":{"origin":1473,"position":4},"title":"PowerShell Scripting with [ValidateScript]","author":"Jeffery Hicks","date":"April 12, 2012","format":false,"excerpt":"The last few days we've been looking at parameter validation attributes you might use in a script of function. Yesterday I wrote about [ValidateRange] and demonstrated how you might use it. That attribute works fine for any values that can be evaluated as numbers. But dates are a different story.\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1185,"url":"https:\/\/jdhitsolutions.com\/blog\/scripting\/1185\/friday-fun-get-messagebox\/","url_meta":{"origin":1473,"position":5},"title":"Friday Fun Get MessageBox","author":"Jeffery Hicks","date":"March 4, 2011","format":false,"excerpt":"Today's Friday Fun offers a way for you to graphically interact with your PowerShell scripts and functions without resorting to a lot of complex Winform scripting. I have a function that you can use to display an interactive message box complete with buttons like Yes, No or Cancel. You can\u2026","rel":"","context":"In &quot;Friday Fun&quot;","block_context":{"text":"Friday Fun","link":"https:\/\/jdhitsolutions.com\/blog\/category\/friday-fun\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2011\/03\/msgbox.png?resize=350%2C200","width":350,"height":200},"classes":[]}],"_links":{"self":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/1473","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/comments?post=1473"}],"version-history":[{"count":0,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/1473\/revisions"}],"wp:attachment":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/media?parent=1473"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/categories?post=1473"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/tags?post=1473"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}