November 5th, 2015

Generate Random Letters with PowerShell

Doctor Scripto
Scripter

Summary: Ed Wilson, Microsoft Scripting Guy, talks about generating random letters with Windows PowerShell.

Hey, Scripting Guy! Question Hey, Scripting Guy! I need to generate a string of random letters. These letters need to be five characters long, and they should be either upper case or lower case. I do not need any numbers or special characters. In fact, my strings should not contain any special characters—only upper case and lower case letters. I have spent several days on this, and it is not working. I am not looking for a random password generator; I have a rather special application for this. Can you help me?

—BG

Hey, Scripting Guy! Answer Hello BG,

Microsoft Scripting Guy, Ed Wilson, is here. One of the things that I love (and some people seem to really hate) about Windows PowerShell is the “one-liner." I mean, I can do a lot of good work in a single line of code. But the amount of work that goes into creating a one-liner can be considerable. Then again, sometimes a one-liner seems to spring from nothingness into full-blown, one-liner mode. It is like the way kudzu grows in the deep southern portion of the United States. It starts small, and then keeps growing and growing and growing. That is the way that most of my one-liners develop—organically, where I keep piling things on top as required.

Five random letters in one line

I can create a five random letter word with a single line of Windows PowerShell. But it takes advantage of several very interesting things. Let's take a look at the parts of my one-liner, and I will show the completed one-liner at the end of the post.

First of all, I am going to assume that I can use the ASCII table, and that I do not need UNICODE characters. I can use the same technique with UNICODE if required. In the ASCII table, the numbers 65-90 represent the upper case letters of the alphabet. The numbers 97–122 represent the lower case alphabet.

I can use the range operator to create a range of numbers, but it does not seem to like gaps in the range. So I am going to create two arrays of numbers, and then simply add them together. To add together arrays, I use the + operator. Here is my range of numbers that go 65–90 and 97-122.

(65..90) + (97..122)

Because I now have a single array of numbers with my range, I can pipe the output from that range to the Get-Random cmdlet and tell it to select five numbers for me. The command uses the Count parameter:

Get-Random -Count 5

Because the Get-Random cmdlet loves pipelined input, all I need to do is add a pipe character after my array of numbers and before Get-Random:

(65..90) + (97..122) | Get-Random -Count 5

I can test that the command works by highlighting the code in the ISE and running only the selected code. This is shown in the following image:

Image of command output

Create a letter from a number

To create a letter from a number, all I need to do is to cast the number as a [CHAR]. When I do that, it will return the letter associated with the ASCII coded numeric value:

PS C:\> [char]65

A

Now all I need to do is to accept the pipelined input from the Get-Random portion of the code. But I cannot simply place [CHAR]$_ following the pipeline character because [CHAR]$_ will not accept pipelined input.

The $_ works because it represents the current number in the pipeline. It is the [CHAR] part that has the issue. Luckily, Windows PowerShell can handle that by using the Foreach-Object cmdlet. It will now take each object that comes across the pipeline and do whatever I put into my script block. The {} delineates the script block. Because I am writing a one-liner, I do not want to go to the trouble of spelling out Foreach-Object, so I can use the % alias instead.

Note  Using the % alias is a bit difficult for some people to grasp because it seems to have no basis in reality. I mean, gps can be related to Get-Process, but %? What is up with that? Well, if you think of the "o" portion of % as the object in the pipeline, the "/" portion of % as the pipeline character, and then back to "o" as the object, you can sort of see the object going across the pipeline…maybe…if you hold your head tilted to the right. Anyway, that is how I remembered it when I was learning Windows PowerShell.

Now I have the following portion of the code:

(65..90) + (97..122) | Get-Random -Count 5 | % {[char]$_}

Here is the associated output when I run only that selected portion of the one-liner:

Image of command output

Put it together

I need to put the five letters back together. How do I do that? Well, I need to join them, so I use the –Join operator and put the rest of the code in a pair of parentheses:

-join ((65..90) + (97..122) | Get-Random -Count 5 | % {[char]$_})

Now when I run the code, I get a single line of five random letters that is made up of upper and lower case letters of the alphabet:

Image of command output

BG, that is all there is to creating a random string of letters. Join me tomorrow when I will talk about more way cool stuff.

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 

Author

The "Scripting Guys" is a historical title passed from scripter to scripter. The current revision has morphed into our good friend Doctor Scripto who has been with us since the very beginning.

2 comments

Discussion is closed. Login to edit/delete existing comments.

  • Micah Lindström

    I noticed this is not actually random, as the 12 generated characters will not contain repeats, e.g. getting aaaaaaaaaaaa is impossible. To remedy this, I made this code instead: 
    -join(1..12 | ForEach {((65..90)+(97..122) | % {[char]$_})+(0..9) | Get-Random})

  • Gilles LE GUILLOU

    Hi from the crypt,
    Great, taste good with:
    -join(((65..90)+(35..38)+(97..122) | % {[char]$_})+(0..9) | Get-Random -Count 12)
    Thanks
    Gilles