Tag Archives: Read-Host

Testing Multiplication Facts

Edit: I said I would not, but I added more to the final function at the bottom of this post.

My daughter entered the office right on time — the end of my workday yesterday — and asked me to give her math problems. That means multiplication facts. While she is all but done learning her multiplication tables these days, I guess we are still practicing. It was my job to randomly choose two numbers between 1 and 12 that she would multiply in her head and say the answer out loud. I was sitting an arm’s length away from Windows Terminal and PowerShell, so I was about to give up coming up with the two numbers myself. PowerShell was going to do this for me.

This is not the first time I have discussed multiplication this school year. Here is a related post. This post is not really a part 2.

I didn’t want to spend much of our time writing PowerShell, so I quickly wrote the below PowerShell and we started. Because she could see the problems in the console — I zoomed in like I never zoomed in before — we were able to burn through at least a hundred, maybe two before we wrapped up our  “give me math” session.

Clear-Host; "$(1..12 | Get-Random) x $(1..12 | Get-Random)"

Here is a quick video that is probably worth seeing at this point in the post.

 

As we went through these random multiplication problems, my mind kept going to how I would have written this had I had more time to prepare. Well, that is what this post is for now. I know I can add a ridiculous amount of features, sure, but I have other things to do, so I am going to keep the features to a minimum. It did dawn on me to do something like my 1 to 100 game, but again, I only want to give her enough to play it herself. I did not need to keep score or be as nearly as polished as that one.

$1st = Get-Random -InputObject (1..12)
$2nd = Get-Random -InputObject (1..12)
"$1st x $2nd = $($1st * $2nd)"

3 x 8 = 24

The above example shows some changes to what I had authored previously. Basically, I can create a multiplication problem and include the answer too. This is not very helpful, as my daughter would be able to see the answer. Either way, this was a logical step toward the next example.

In this example, we add a do-until loop, hiding the product from the user. The Read-Host prompt will stop promoting for the answer as soon as it is entered correctly.

$1st = Get-Random -InputObject (1..12)
$2nd = Get-Random -InputObject (1..12)
"$1st x $2nd = ?"
do {$Product = Read-Host -Prompt 'Enter Product'}
until ($Product -eq $1st * $2nd)

1 x 8 = ?
Enter Product: 8

6 x 8 = ?
Enter Product: 45
Enter Product: 50
Enter Product: 48

And that was it. Plenty more could have been added, however, I am not sure she would even appreciate additional features and the extra work. This PowerShell will be good enough. I bet she will think it is great.

Okay fine, I decided to add a little more, but I am done after this, I swear. I put it in a function with a couple of parameters and here it is. As you will see, not much more time was spent doing this.

Function Test-Multiplication {
    [CmdletBinding()]
    Param (
        [Parameter()]
        $FirstRange = (1..12),

        [Parameter()]
        $SecondRange = (1..12)
    )

    $1st = Get-Random -InputObject $FirstRange
    $2nd = Get-Random -InputObject $SecondRange

    "$1st x $2nd = ?"
    do {$Product = Read-Host -Prompt 'Enter Product'}
    until ($Product -eq $1st * $2nd)
}
Test-Multiplication
9 x 9 = ?
Enter Product: 81

Test-Multiplication
4 x 6 = ?
Enter Product: 21
Enter Product: 24

Last note here. Because we have parameters, we can, if we want, send in different ranges for the FirstRange and SecondRange parameters. Ony want to practice your 4’s and you can do this.

Test-Multiplication -FirstRange (4..4)
   
4 x 1 = ?
Enter Product: 4

Test-Multiplication -FirstRange (4..4)
   
4 x 6 = ?      
Enter Product: 24

Okay, I am done now — for real.

Update: Well, it was not for real. I lasted a night. My daughter played the multiplication game and it was clear it needed one more thing. Even though she, at 10, now knows to press the up arrow for the last command, I went ahead and added a little more. Here is the updated function first and then an example of it being executed.

Function Test-Multiplication {
    [CmdletBinding()]
    Param (
        [Parameter()]
        $FirstRange = (1..12),

        [Parameter()]
        $SecondRange = (1..12)
    )

	
	do {
		$1st = Get-Random -InputObject $FirstRange
		$2nd = Get-Random -InputObject $SecondRange

		"$1st x $2nd = ?"
		do {$Product = Read-Host -Prompt 'Enter Product'}
		until ($Product -eq $1st * $2nd)

		do {
			$Replay = Read-Host -Prompt 'Enter = More (Q = quit)' 
		} until ($Replay -eq '' -or $Replay -eq 'Q')
	}
	until ($Replay-eq 'Q')
}
[PS7.2.1][C:\] Test-Multiplication 
4 x 3 = ?      
Enter Product: 12
Enter = More (Q = quit): 
5 x 10 = ?     
Enter Product: 50
Enter = More (Q = quit): 
4 x 5 = ?      
Enter Product: 20
Enter = More (Q = quit): 
9 x 4 = ?      
Enter Product: 35
Enter Product: 39
Enter Product: 36
Enter = More (Q = quit): q
[PS7.2.1][C:\] 

Okay, I am done again, for now. Ugh.

Forum Problem to Posted Solution and Article Post

I was reading the Stack Overflow (PowerShell) forum when I happened on a question that I decided I would take on. It reminded me of an old post I had written. In that post, Countdown Options, I wrote a countdown that overwrote itself as it counted down. Here’s s GIF from that post.

In the question on Stack Overflow, someone wanted to get away from the way Do-Until works. Here’s their, modified-by-me question:

I have this simple bit of code in a PS script where I want to get a simple yes or no answer…The problem is that when user inputs something other than y or n it reprompts on new line…How can I avoid the new line and make the code as simple and easy to understand as possible?

I didn’t bother taking my time to explain that this is how it works and that they should expect more from their users. Instead, I set out to use what I learned from my countdown article. Before we get to that solution, let’s look at how this works before the changes I implemented.

Do {
    $Answer = Read-Host -Prompt 'Found missing roles. Install them now? (y/n)'
}
Until ($Answer -eq 'y' -or $Answer -eq 'n')

According to the OP, the problem with the above option and below results is that it’s re-prompting on the next line if the answer doesn’t match “y” or “n.” That needed to be avoided, if possible.

Found missing roles. Install them now? (y/n): 1
Found missing roles. Install them now? (y/n): 2
Found missing roles. Install them now? (y/n): 3
Found missing roles. Install them now? (y/n): 4
Found missing roles. Install them now? (y/n): 
Found missing roles. Install them now? (y/n): 
Found missing roles. Install them now? (y/n): a
Found missing roles. Install them now? (y/n): b
Found missing roles. Install them now? (y/n): c
Found missing roles. Install them now? (y/n): n

In my example, we overwrite the previously entered value. Take a look at the slight modifications I’ve made to the code. Then, take a look at the GIF made for this article.

$Cursor = [System.Console]::CursorTop
Do {
    [System.Console]::CursorTop = $Cursor
    Clear-Host
    $Answer = Read-Host -Prompt 'Found missing roles. Install them now? (y/n)'
}
Until ($Answer -eq 'y' -or $Answer -eq 'n')

And with that, my work is done here, and over there on Stack Overflow. Well, until the next question, where I can hopefully make a positive impact.

Read-Host Prompt inside Hash Table

I’m working with Plaster and in doing so, have a few hash tables in my workspace. Suddenly, and out of nowhere, I had a thought: Can I put a Read-Host command, as the value of a key-value pair inside of a hash table? Yes, but before we get too far into this, here’s a simple hash table example without any Read-Host commands.

$Params = @{
    meal = 'lunch'
    food = 'Ramen'
    drink = 'Tea'
}
$Params

Name                           Value
----                           -----
drink                          Tea
food                           Ramen
meal                           lunch

Okay, that was simple: Choose a variable name, prefix it with a dollar sign, create the hash table structure as @{}, and then add key-value pairs as <key> = <value>.

Now, on to a Read-Host example. Read-Host is a cmdlet that can be used to interactively prompt a user for a value. It’s not always preferred, or the right to do, but there are times when it can be useful, and where its use is acceptable. In the next example, we’ll create a single key-value pair ourselves, then we’ll prompt the user for a value to assign to the Number key. As you will also determine, when prompted, the word “five” is entered, and sure enough, the entry ends up as the value for the Number key in our hash table.

Remove-Variable -Name Params
$Params = @{
    Color = 'red'
    Number = Read-Host -Prompt 'Enter spelled out number'
}
$Params
Enter spelled out number: five

Name                           Value
----                           -----
Number                         five
Color                          red

This example was one of those “can I do this moments?” Sure, I was able to return the $Params hash table with the correct value in the Number key after having been prompted for that value. This occurred, as the hash table was being defined and built. I didn’t even know if that would work, but now we both know that it does.

In the next example, we try something even more obscure, but as suspected, it doesn’t work. We first assign the Random key the value of a Read-Host prompt. As we’ve seen, that does work. Next, while still creating keys and values, we take the value assigned to the Random key in the $Params hash table and attempt to assign it to the Number key, as well. Again, this doesn’t work. As suspected, we can’t use the $Params hash table until it’s done being created. It’s not a shock, but it was worth a try, of course.

Remove-Variable -Name Params
$Params = @{
    DayOfWeek = 'Friday'
    Random = Read-Host -Prompt 'Enter spelled out number'
    Number = $Params.Random
}
$Params
Enter spelled out number: three

Name                           Value                                                                                                                             
----                           -----                                                                                                                             
Random                         three
Number
DayOfWeek                      Friday

Even if this did work, I’m not sure how this would ever really serve a purpose, but it’s always worth trying something even if doesn’t seem plausible. And if it did work, I don’t expect that we’d even need duplicate values in different keys anyway, and that’s all we’d be doing. But all that said, we absolutely can use Read-Host to assign a value to a key in a hash table, as it’s being created.

Alright, that was it. Enjoy the week!

Read-Host with a Previous Value Part II

It’s simply not everyday that Rob Sewell (@sqldbawithbeard) places a link on Twitter to your blog. Yours, as in mine, but here we are. That was yesterday.

Today, knowing this is out there, I decided to add a bit more to this short post with a second installment. In this post, I’ve written a few changes to the single If statement from Part I. While it was a simple statement to see if I could reuse a previously stored value in the first installment, it’s a bit more full featured now.

We’re getting away from statically setting the default user. We’ll actually let the user assign that value. This determination — whether there’s a default user or not — defines our prompt message, which is most of what’s been added.

If ($User) {
    $Prompt = "Press Enter for the last user [$User], or enter a new user"
} Else {
    $Prompt = "Please enter a new user"
}

If (($Result = Read-Host -Prompt $Prompt) -eq '' -or $Result -eq $User) {
    "You're using the previously used ""$User"" user."
} Else {
    "You're using the previously unused ""$Result"" user."
    $User = $Result
}

I won’t bother including any examples of the running code, but do run the example yourself if you’re interested. Remember to clear or remove the $User, $Prompt, and $Result variables if you want to start fresh. The following command will remove those variables, if you find you need it before a new run.

Remove-Variable -Name User,Prompt,Result -ErrorAction SilentlyContinue

And that’s it. Thanks for the link to the blog, Rob!

Read-Host with a Previous Value

Update: There’s a Part II, read it next.

Here’s a quick one. For an upcoming project, I decided I may need a way to use Read-Host in combination with a previously set, default value. Here’s the working code I threw together in case it’s needed.

$User = 'tommymaynard'

If (($Result = Read-Host -Prompt "Press Enter for the last user [$User], or enter a new user") -eq '' -or $Result -eq $User) {
    "You're using the previously used ""$User"" user."
} Else {
    "You're using the previously unused ""$Result"" user."
}

I set my user to “tommymaynard,” and then the If statement executes. The execution pauses while the Read-Host cmdlet waits for my input. If I press Enter, the If portion runs indicating that I’m using the previously set value of “tommymaynard.” It’ll do that if I enter tommymaynard again, too. If I enter a new value, it indicates I’m using the new value.

While we’re here, let’s run the code with three possible values: nothing entered, tommymaynard entered, and a different user entered.

Press Enter for the last user [tommymaynard], or enter a new user:
You’re using the previously used “tommymaynard” user.

Press Enter for the last user [tommymaynard], or enter a new user: tommymaynard
You’re using the previously used “tommymaynard” user.

Press Enter for the last user [tommymaynard], or enter a new user: lsmith
You’re using the previously unused “lsmith” user.

And there it is, a super short post about using a previously set value for Read-Host.

Creating Multiple Credential Objects Part II

Download the updated function here: https://gist.github.com/tommymaynard/98031ccd5de67005bf3063db06a33851

Back in January 2015, I wrote a post and uploaded an advanced function to the TechNet Gallery that allows a user to create multiple credential objects. Edit: The TechNet Gallery no longer hosts scripts/modules, so use the GitHub Gist at the top and bottom of this page. The multiple part is up to the user, such as they might enter a command as in the below example. Due to the -Set 2 parameter and parameter value, they would get prompted twice, to enter a username and password combination. When the function was completed, they would have two credential objects, with the first stored in $CredSet1 and the second stored in $CredSet2.

New-TMMultiCred -Set 2

I had always wanted to make a couple of changes to the advanced function, and so I have. Now the function includes a -NoGui parameter, that will not require the username and password be entered into the Get-Credential GUI, and can instead be entered directly into the console. I should mention that if this was run in the ISE, the password would actually invoke a small GUI for the password, as is standard when using Read-Host‘s -AsSecureString parameter in that host.

The other addition I wanted to add is that the advanced function produces objects, instead of using the Write-Output cmdlet to display information. Now, instead of the function writing this:

SUCCESS: Credential Set 1 stored in $CredSet1
SUCCESS: Credential Set 2 stored in $CredSet2

the function writes this:

CredSet             Variable            UserName                                 Password
-------             --------            --------                                 --------
1                   $Credset1           mydomain\admin       System.Security.SecureString
2                   $Credset2           user1                System.Security.SecureString

Neat, right? So download it and try it out. I think it was a decent addition to an already helpful advanced function.

Download the updated function here: https://gist.github.com/tommymaynard/98031ccd5de67005bf3063db06a33851

Multi-Level Menu System with a Back Option

It’s been said several times now, but while this site was designed to help people learn some Windows PowerShell, it’s also about posting things I’m going to want to find one day. Take for instance this menu system I started for someone on TechNet: https://social.technet.microsoft.com/Forums/en-US/30663446-4091-4a1c-9de0-407046ccc39f/powershell-script-with-submenus-how-to-go-back?forum=winserverpowershell.

It allows the user the ability to enter into menus and submenus with the option of backing out of them. You know, choose a number from the menu, or hit B to go back to the previous menu. Hopefully it’s helpful for the TechNet thread creator, and maybe it’s helpful for others someday, too. I’ve included both the code and an image of the code in action. Until next time.

Do {
@'

----------Software/Driver Installation----------
1. Toshiba 1
2. Acer 1
------------------------------------------------

'@

    $MainMenu = Read-Host -Prompt 'Enter 1 - 2 or Q to quit'
    Switch ($MainMenu) {
        1 {
            Do {
@'

---------Software/Driver Installation----------
1. Software
2. Drivers
------------------------------------------------

'@
                $1MainMenu = Read-Host -Prompt 'Enter 1 - 2 or B for Back'
                Switch ($1MainMenu) {
                    '1' {
                            Do {
@'

--------------Software Installation-------------
1. Package 1
2. Package 2
3. Package 3
------------------------------------------------

'@
                                $1InnerMenu = Read-Host -Prompt 'Enter 1 - 3 or B for Back'
                                Switch ($1InnerMenu) {
                                 '1' {Write-Output -InputObject '--> You chose to install package 1'; break}
                                 '2' {Write-Output -InputObject '--> You chose to install package 2'; break}
                                 '3' {Write-Output -InputObject '--> You chose to install package 3'}
                                }
                            } Until ($1InnerMenu -eq 'B')
                        }
                }
            } Until ($1MainMenu -eq 'B')
        }
    } # End Switch.
} Until (
    $MainMenu -eq 'Q'
)

multi-level-nested-menu-system-with-a-back-option01