Powershell

I needed some source text to test a regular expression pattern, so my goal tonight was to generate some. The regex pattern in question finds email addresses, so I needed to be sure to embed real-looking email addresses inside of gibberish. Step number one: I need some random letters. PowerShell v2’s Get-Random cmdlet comes to the rescue!

Get-Random has two modes. The first mode allows you to return random numbers, and you can specify a min and max range. The second mode will return random items from a list, and as an added bonus, you can specify the number of items to return. I plan on using both modes in this exercise.

In order to build gibberish words or email addresses, I need to start with a list of allowable characters. Let’s keep it simple and restrict things to lowercase letters, although adding in numbers would be simple.

You all remember ASCII, right? This is a conversion table that has been used to represent numeric values for letters (and every other character on you keyboard, plus others) for a long, LONG time. You are slowly seeing ASCII encoding supplanted by Unicode as that table has a much larger address space and can handle non-Latin alphabets, but ASCII suits me just fine. We are going to use ASCII values and PowerShell’s range operator (..) to generate the list of allowable characters.

If you have worked with Vbscript, then you might know how to to ASCII conversions with the Chr() function. You give that function a number, and it spits out the ASCII value. The reverse is done with the Asc() function. In PowerShell, it’s not done the same way at all, so just forget that. Instead, what we are going to do is to convert back and forth between a “char” (character) .NET type. Chars are really sort of an in-between data type. They look like strings (i.e., it’s a letter), but they are very easily converted into integers.

So let’s take that knowledge and combine it with a technique called “casting”. To cast in PowerShell means to state that you want a particular value to be a certain data type. For example, if I have a number, and I want to make sure it is treated like a string in my script, I can cast it as a string like so:

[string]12

If you pipe that to Get-Member, you’ll see that the result is a string object, with all of the properties and methods which that type has, as opposed to the much more basic [int] type.

Moving on, let’s take the letter “a”, and the letter “z”, and turn it into a range containing all of the letters in between. PowerShell’s range operator can be used here, but it only works with integers. I could ask a search engine for an ASCII chart to get the numbers I need, but there’s no need, I’ll just convert from the letters directly.

Here’s how to convert a single letter into its ASCII number representation:

PS > [int][char]'a'
97

What I am doing here is casting twice. Anything surrounded by single or double quotes is a string. I can convert any single letter (or symbol, or whatever) to a char data type by casting it as you can see. Then I take that char and cast it immediately to an integer, and as I said before, that’s an easy conversion for PowerShell to do because that’s the way chars types are wired.

Now we have our first integer. Just replace the ‘a’ with a ‘z’ and we have the second.

PS > [int][char]'z'
122

These integers are going to be perfect as input to the Get-Random cmdlet. Here’s how to return random letters using Get-Random’s first mode:

PS > $min = [int][char]'a'
PS > $max = [int][char]'z'
PS > Get-Random -Minimum $min -Maximum $max
104
PS > [char](Get-Random -Minimum $min -Maximum $max)
l
PS > [char](Get-Random -Minimum $min -Maximum $max)
q
PS > [char](Get-Random -Minimum $min -Maximum $max)
r

As you can see, turning an integer back into a letter is pretty simple, you just cast it to a [char]. (The parentheses are necessary.) And you can also see a new random letter popping up at each execution of Get-Random. Great! So how do we make random words? Well, in the context of this blog post, a word consists of an array of characters. That makes sense, right? There are a few ways to go from here to create the requisite [char] array. I could create a for loop, and run the above command inside the loop.

However, there is an easier way. Let’s go back a step and have a look at Get-Random’s second mode. Here is a table showing the two parameter sets (output created with my Get-Parameter script):

   ParameterSet: RandomNumberParameterSet

Name    Type       IsMandatory Pipeline
----    ----       ----------- --------
SetSeed Nullable`1       False    False
Maximum Object           False    False
Minimum Object           False    False

   ParameterSet: RandomListItemParameterSet

Name        Type       IsMandatory Pipeline
----        ----       ----------- --------
SetSeed     Nullable`1       False    False
InputObject Object[]          True     True
Count       Int32            False    False

We used Minimum and Maximum in the first mode. Now we are going to use InputObject and Count. This mode is really handy because you can supply an array of items (letters in this case) as input, and tell it how many random items to return as output! That means no loop, so the code is going to be much simpler.

First, let’s build an array of all lowercase letters. We already know the numeric values to use in the range, so let’s use those. I’m going to use a little trick to take the integer range and cast it in one step to an array of characters, which is exactly what we want:

PS > $alpha = [char[]]($min..$max)
PS > $alpha | Select-Object -First 3
a
b
c

We build the range with “$min..$max” and put that in parentheses. Then we cast it, but not as a single [char], but as an array of [char]’s by adding an empty set of brackets []. Now, the variable $alpha contains our input to Get-Random. The next step is easy, just pass this variable to the cmdlet and give it a count:

PS > $alpha | Get-Random -Count 5
t
f
a
b
c

Presto! A five-letter word! Well…sorta. What we have is a series of characters, one per line. To turn this into adjacent characters we can cast the whole thing as a string.

PS > [string]( $alpha | Get-Random -Count 5 )
i h s p z

Almost there, we just have to get rid of those extra spaces. The spaces are generated because of something called the “output format separator”, otherwise known as $OFS. This is a variable predefined by PowerShell to be a single space, but you can change it to whatever you want. Here’s that final step:

PS > $ofs = ''
PS > [string]( $alpha | Get-Random -Count 5 )
qfzwg
PS > [string]( $alpha | Get-Random -Count 5 )
dnhbq

Now I am just a hop, skip, and a jump from generating random email addresses, but that’s enough for tonight.

: http://halr9000.com/article/859

2010-02-18 08:10:13

I love the why you outline the steps you took and your thought process. Very nice to read
I am catching up on your powerscripting podcasts (episode 27 right now).

Keep up the great work

Andy
2010-03-25 21:42:14

Thanx !

Jon
2011-11-03 15:21:49

I was trying to figure out how to generate 8 random characters that could potentially include uppercase/lowercase alpha and numbers 0-9. I was having trouble until I discovered this blog post. Very helpful! Thanks!

Here’s what I came up with as sample code (I decided to work around the $OTS issue another way):

$a += [Char[]]([Int][Char]‘a’..[Int][Char]‘z’)
$a += [Char[]]([Int][Char]‘A’..[Int][Char]‘Z’)
$a += [Int[]](0..9)
1..8 | % { [String]$RandomString += (Get-Random -InputObject $a) }

  • Microblog

  • Recent Posts

  • Recent Comments

  • meta

  • PowerShell Blogroll