Cool PowerShell Game Teaches Cmdlet Names

Cool PowerShell Game Teaches Cmdlet Names

  • Comments 4
  • Likes

Summary: Learn Windows PowerShell cmdlet names by taking the Dr. Scripto Challenge.
 
Microsoft Scripting Guy Ed Wilson here. The Scripting Wife and I are on a road trip in Canada. We had a wonderful time in Toronto with Windows PowerShell MVP Sean Kearney. Now we are heading to Ottawa where we plan to meet with Windows PowerShell MVP Kirk Munro. In addition to getting to talk to customers about Windows PowerShell and meeting with way cool Windows PowerShell MVPs, it also means we have access to the television. At home in Charlotte, North Carolina, we do not watch television, so in some ways it is sort of a treat. For example, the Scripting Wife has a couple of shows she likes to watch. As she was watching one particular show in which contestants receive letters and blank spaces and try to match a clue, it dawned on me that I could write that in Windows PowerShell.


So here it is; the Dr. Scripto Windows PowerShell Challenge. The script is interesting, but it is also illustrative of an interesting way to manipulate strings. The techniques could possibly be applicable in a wide variety of situations.


DrScriptoChallenge.ps1
$array = @()
$array = Get-Command -CommandType cmdlet |
ForEach-Object { $_.name.tostring() }
Foreach($cmdlet in $array)
{
 $rndChar = get-random -InputObject ($cmdlet.tochararray()) -count ($cmdlet.length/4)
 foreach($l in $rndchar)
 {
  $cmdlet = $cmdlet.Replace($l,"_")
 }# end foreach $l
 $cmdlet
} #end foreach $cmdlet

The first thing I do in the DrScriptoChallenge.ps1 script is create an empty array and store it in the $array variable. Next, I use the Get-Command cmdlet to retrieve all of the cmdlets, and I pipe the cmdletinfo objects to the Foreach-Object cmdlet where I obtain the name of each cmdlet as a string. I then store the resultant cmdlet names in the $array variable. All of this provides me with an array of Windows PowerShell cmdlet names. This portion of the code is shown here:


$array = @()
$array = Get-Command -CommandType cmdlet |
ForEach-Object { $_.name.tostring() }

The next thing I want to do is to choose a random grouping of letters from each Windows PowerShell cmdlet. To do this, I turn the Windows PowerShell cmdlet names that are stored in the $array variable into an array of characters. This allows me to choose individual letters from the Windows PowerShell cmdlet names. I pass the cmdlet names to the Get-Random cmdlet to choose the random letters. One thing I do is look at the length of the Windows PowerShell cmdlet name, and if a cmdlet name is longer, I select additional random letters. To make the challenge harder, use a 2 or a 3 instead of a 4. To make it easier, use a 5 or a 6 instead of a 4. I store the resulting random letters in an array called $rndChar. This section of the Windows PowerShell script is shown here:


$rndChar = get-random -InputObject ($cmdlet.tochararray()) -count ($cmdlet.length/4)

Now I want to replace each of these random letters in the Windows PowerShell cmdlet names with an underscore character. I use a Foreach loop to walk through the array of letters, and the replace method to replace each letter with the underscore character. A key point here is to write the replacement string back to the original string, or else when the script completes, only the last letter will be replaced. This portion of the script is shown here:


foreach($l in $rndchar)
 {
  $cmdlet = $cmdlet.Replace($l,"_")
 }# end foreach $l

The last thing to do is to display the modified string and close out the loop:


$cmdlet
} #end foreach $cmdlet

Because there are several Foreach type of loops, I add a comment at the closing brace (curly bracket) to let me know the purpose of the brace. This makes troubleshooting easier. As the script currently stands, it simply displays the modified cmdlet names on the screen; to create a test simply redirect it to a text file as seen here:


$cmdlet >>c:\fso\DrScriptoChallenge.txt

The script and associated output displayed on the screen are shown in the following figure.

Image of script and associated output

 

Well that is all there is to creating the DrScriptoChallenge. You might think the script is easier than the challenge—it is a great way to test your knowledge of the default Windows PowerShell cmdlets. Until tomorrow, keep on scripting.


I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.


Ed Wilson, Microsoft Scripting Guy

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • <p>Hi Ed,</p> <p>a very good and extremely short implementation of the game!</p> <p>I just want to add another idea to this, that I came across, looking at the few lines of code. </p> <p>I thought it might be possible to avoid the replacement loop over each character with a regular expression containing all the characters I want to replace and doing a one in all replacement.</p> <p>We can build a regular expression from the array of random characters if we join them together in the end like this:</p> <p>$rndString = get-random -InputObject $_.Name.ToCharArray() -count ($_.Name.length/4)) -join &#39;&#39;</p> <p>This can be used to form a range of characters in a regular expression like</p> <p>$cmdlet = cmdlöet -replace &quot;[$rndString]&quot;, &#39;_&#39;</p> <p>which does all replacements without the loop.</p> <p>In fact this worked with the exception of the dash that brole my regular expression string :-(</p> <p>But OK, we can even get around the dash, if we escape it which is a bit of ugly additional work, but .... why not ... So we finally have </p> <p>$rndString = ((get-random -InputObject $_.Name.ToCharArray() -count ($_.Name.length/4)) -join &#39;&#39;).replace(&#39;-&#39;,&#39;\-&#39;)</p> <p>Putting all together it results in a very short ... but maybe less readable ... &quot;one-liner&quot; ( I split it into five lines anyway :-)</p> <p>Get-Command -CommandType cmdlet | </p> <p>Foreach-Object { </p> <p> &nbsp; &nbsp;$rndString = ((get-random -InputObject $_.Name.ToCharArray() -count ($_.Name.length/4)) -join &#39;&#39;).replace(&#39;-&#39;,&#39;\-&#39;); </p> <p> &nbsp; &nbsp;$_.name -replace &quot;[$rndString]&quot;, &#39;_&#39; &nbsp;</p> <p>}</p> <p>Klaus.</p>

  • <p>@Klaus You are absolutely correct, it would be possible to use a regular expression to make the repalcements. In fact, the first version of the script I wrote I used regular expressions. But they are complicated, and a loop using the Get-Random and -replace is easier to understand. My emphasis this week is going to be on Hash Tables and on developing functions. I will build on this script all week. I even have a couple of articles for the weekend that will clear up a few points that arise during the week. I am pretty excited about this series. </p>

  • <p>Any suggestions on creating my own cheap game of Jeopardy using a text file? &nbsp;Example, all the rows output as shown from this script, but the next column, the &quot;Synopsis&quot; information that is displayed when using Get-Help.</p> <p>W_it_-_utput Adds content to the specified items, such as adding words to a file.</p> <p>_rit_-Host Writes customized output to a host.</p> <p>Or similar. &nbsp;Any suggestions out there?</p>

  • <p>@Charlie Hawkins stay tuned. I am modifying this all week, and by the end of the week you will be able to create your own input text file, and you can easily have the answers, and require the &quot;answer&quot; typed to meet &quot;what is the capital of Canada&quot; in response to the prompt &quot;Ottawa&quot;</p>