Generate Random Passwords with Powershell

by alexpav 14. May 2009 10:31

Recently, I ran across the need to generate a random password, and decided to write a quick PowerShell script to accomplish this task. I wanted to make sure that I can supply the desired password length and that there are two different levels of complexity: letters (uppercase and lowercase) and numbers, and letters (uppercase and lowercase), numbers, and special characters.

Since I have Powershell v2 on my Windows Server 2008 R2 laptop, that’s what I will use. Powershell v2 contains a nifty random generator cmdlet (get-random), and it will be very useful. If you don’t yet have Powershell V2 installed, grab the latest version listed here: http://blogs.msdn.com/powershell/pages/download-windows-powershell.aspx . As of the time of the writing, CTP3 was the latest released version – download it from the Microsoft Download Center: http://go.microsoft.com/fwlink/?LinkID=131969 .

If you are impatient like me, just grab the script file here:  

pwgen.zip (1.47 kb)

But to truly understand how it works, read on... 

When I started thinking about the problem at hand, I already knew that there would be two different parameters that I need to pass to the script: password length, and password complexity. Getting these values into the script can be achieved with param statement in Powershell:

 param (

[string]$pwcomplexity = $(Read-Host "Please select password complexity. 1 for alphanumeric, or 2 for alphanumeric plus special characters"),

[string]$pwlength = $(Read-Host "Please enter the desired password length")

) 

 

The use of the param statement allows us to pass the values to the script using the –pwcomplexity and –pwlength arguments. The use of the Read-Host statement will allow us to simply run the script – we will be prompted to enter these values as the script executes. Additionally, note the use of the [string] cast. We want to make sure that the input values are strings, not integers, hence the cast .

Before we move on, let’s pre-define the character strings to be used in our passwords. I wanted to have a set with letters (uppercase and lowercase) and numbers, and another set with letters, numbers, and special characters. Note that this is two lines of code (broken up for ease of viewing).

 $strComplex =

"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T",

"U","V","W","X","Y","Z","1","2","3","4","5","6","7","8","9","0","a","b","c","d",

"e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z”,

"!","@","#","$","%","^","&","*","(",")","_","=","~","?","<",">"

$strSimple =

"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T",

"U","V","W","X","Y","Z","1","2","3","4","5","6","7","8","9","0","a","b","c","d","e","f",

"g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z”

 

 Because we assign values separated by commas, the $strComplex and $strSimple become character arrays. In an array, we can query array’s value by supplying its position within the array. For example, $strSimple[3] will return capital letter D, since the first character in the array has a position of zero. So $strSimple[0] is letter A. You get the idea – we will use a random number to peek inside the array and get characters for our password.

Now we need to process the arguments – make sure that they are valid, and configure options for password generation based on input.

  if ($pwcomplexity -eq "1")#simple password

{

    $strCharacters =  $strSimple

}

elseif ($pwcomplexity -eq "2")#complex password

{

   $strCharacters =  $strComplex

}else

#not sure what was entered, let's assume complex password

{

     write-warning "Invalid passwod complexity supplied, generating a complex password (equivalent to option 2)"

     $strCharacters =  $strComplex

}

if ($pwlength -notmatch "\d+")

#validate that what was entered is a digit using regular expressions.

{

   #not a digit, assume that desired length is 8 characters

   write-warning "Invalid password length supplied, generating an 8 character password instead"

$pwlength = 8

} 

 

Note the use of the regular expression matching with the –notmatch parameter. “\d+” means “any number of digits only”. So if someone types in a letter or any other non-digit during the password length input, the script will trigger the contents of the if block, write a warning to the screen, and assume the default length of 8 characters.

At this point in the script, we have our desired password generator options all taken care of. Let’s write a function to generate the random password. By making it a function, we have a better ability to call it multiple times. Hint: making this a function will come handy as we write the rest of our script.

function generate-password

{

   $pw = $null

   for ($i=0;$i -lt $pwlength; $i++)

   {

     $pw += get-random -InputObject $strCharacters

    }

    return $pw

} 

 

In the function, we will store our generated password in a $pw variable. It is a good idea to reset it so that any previous data that could possibly be stored in that variable is erased before we proceed. So we will set it to $null to begin with. Then, we run a FOR block, which will iterate while the $i variable is between 0 and one less than the desired password length, incrementing $i by one each time the block loops. For example, if our desired password length is 8 characters, we will run it 8 times, with $i being 0,1,2,3,4,5,6, and 7. Within the FOR block, we will use a PowerShell v2 function called get-random (you can find out about get-random in a very cool Microsoft TechNet article here: http://www.microsoft.com/technet/scriptcenter/topics/winpsh/getrandom.mspx)

In a nutshell, get-random will generate a random number or pick a random object from an array. Remember the arrays we setup in the beginning? Well, we will now feed one of the arrays (depending on password complexity requirements) into the get-random cmdlet using the –InputObject parameter. We will get back a random character from that array. Then, we will add this character to the $pw string by using the += operator, which means “take whatever $pw had before, and add the result of the get-random command to it”. Basically, we will continue to increment $pw with random characters. Pretty cool! At the end, we return the password when the function is done.

A function itself does not run as part of script processing. You have to explicitly call it. Let’s do that by assigning the return value of the function to the $genPassword variable:

 $genPassword = generate-password 

 

Great, now the $genPassword variable contains our password. But is it a good password? What if the random generator did not randomly pick any numbers? Or there are no lower case letters? Or no special characters? To make sure that the password meets our requirements, let’s check it.

First, let’s check that the password has the desired length:

if ($genPassword.length -ne $pwlength)

{

   write-warning "Failed to generate the password due to length mismatch"

   $genPassword = $null

   break

}

 

Ok, something went wrong if we ran the loop 8 times but did not get an 8 character password. Let’s exit the whole script with a break statement, and try again. We’ll inform the operator with the write-warning message. Assuming that this part works, let’s check the complexity. And if we don’t meet the complexity requirements, let’s try to re-generate our password by calling the function over and over again, until the complexity requirements are met. We will use a while block, which basically loops over and over again until a pre-defined condition is met. Let’s use the $checkpasswordcomplexity boolen variable (true or false) to control it.

 while ($checkcomplexity -eq $true)

{

   if (($pwcomplexity -eq "1") -and ($genPassword -match "^.*(?=.{$pwlength,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).*$"))

  {

     write-host "Complexity level 1 validated - at least one lower case, one upper case, and one digit"

     write-host "The password is: $genPassword"

     $checkcomplexity = $false

  }

  elseif (($pwcomplexity -eq "2") -and ($genPassword -match "^.*(?=.{$pwlength,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()_=~?<>]).*$"))

  {

     write-host "Complexity level 2 validated - at least one lower case, one upper case, and one digit"

     write-host "The password is: $genPassword"

     $checkcomplexity = $false

  }

  else

  {

     write-warning "$genPassword : Complexity validation failed, regenerating..."

     $genpassword=$null$genPassword = generate-password

  }

}

 

So, if the desired complexity is “1” (simple password), and if we can match a regular expression that validates for lowercase, uppercase, and digits, we are good to go and can write the password to console. If the desired complexity is “2” (complex password), and if we can match a regular expression that validates lowercase, uppercase, numbers, and special characters, then we are also good to go and can write the password to console. Otherwise, something went wrong and we randomly picked a too simple of a password, so let’s re-run the generate-password function.

If you are confused or scared of regular expressions, don’t be. Just read this cool MSDN article on .Net regular expressions and you will feel better. Maybe. We will try to talk more about regular expressions in later articles.

As you can see, with the power of PowerShell v2, you can do really cool things, such as generate random passwords. Script on, infradevs!

-alexpav

Currently rated 5.0 by 3 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Powershell | Scripting | Security

Where are the Exchange 2007 Unified Messaging Voicemail Greetings???

by alexpav 17. March 2009 13:01
 

Have you ever wondered where the Exchange 2007 Unified Messaging greetings are stored? Recently, a fellow colleague had an interesting dilemma. His customer asked him if there was a way to upload WAV files as user’s personal greetings. Such functionality exists for Auto Attendant prompts, but not for individual user mailboxes. But before we dive in to uploading WAV files as personal greetings, we need to better understand how these greetings are stored in Exchange 2007 Unified Messaging.

First, let’s review the different greeting types which exist in Exchange 2007 Unified Messaging:

·         Recorded Name (stored in Active Directory)

·         Personal Greeting (stored in the mailbox)

·         Out of the Office Greeting (stored in the mailbox)

Recorded Name

The personal greeting is stored as a binary value in Active Directory, in an attribute called ms-Exch-UM-Spoken-Name.  In order for this attribute to be populated, several things have to take place. First, the user must have an enabled mailbox on an Exchange 2007 mailbox server. Second, the mailbox must be enabled for Exchange 2007 Unified Messaging. Finally, the user must dial the UM Outlook Voice Access number and use Personal Options to record the name. If the user does not perform the last step, Exchange 2007 Unified Messaging will auto-generate the recorded name based on the Display Name in Active Directory, however the auto-generated recorded name itself is not stored in AD. Instead, it is stored in memory of the Exchange 2007 Unified Messaging server.

Personal Greeting

Much like the custom recorded name, the personal greeting is a binary format value. However, instead of being stored in Active Directory, it is stored in the mailbox of the user. Similar three pre-requisites apply – Exchange 2007 mailbox, enabled for Unified Messaging, and user action to record the personal greeting via Outlook Voice Access.

So how does Exchange UM store the personal greeting? We already know that it is a binary value (in fact, it is a binary representation of a WAV file), and that it sits in the user mailbox. But where exactly is it?

Each user mailbox contains a hidden message area. This message area is not exposed in Outlook or Outlook Web Access, however it can be viewed using MAPI tools such as MFCMAPI, which is can be obtained from the Microsoft Download Center here. To use MFCMAPI, it is necessary to configure the Outlook profile in online mode (cached mode won’t work correctly), and also add the following registry key to view large binary values (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Messaging Subsystem\MSMapiApps\SharedMemMaxSize= 0x00800000 (DWORD).

Let’s use MFCMAPI to explore the hidden message area of a mailbox. First, launch MFCMAPI, select the Session menu item, and click on Log On and Display Store Table. Then, select the online mode Outlook profile if prompted. You will see the configured MAPI instances in the top pane of the MFCMAPI window.

 

Figure 1 – Outlook Profile, Unrated Version

Right-click the actual Exchange mailbox, and click Open Store. A new window will open, displaying the Root Container on the left side. As you can see, this is the raw view of the mailbox as you can navigate familiar folders and see raw contents of messages.

Figure 2 – Raw Mailbox View, a.k.a. Too Much Info

Right-click the Root Container in the left pane, then click on Open Associated Contents Table. You will see one more window pop-up, displaying hidden messages which are contained in the mailbox. Scroll the top pane to the right and expand the Message Class column. You will see different message classes that exist. Of interest to us is the IPM.Configuration.Um.CustomGreetings.External message. If it is not visible, you may have to record the greeting by calling in to Outlook Voice Access. If no items are visible, it is likely that the Outlook profile is configured in Cached Mode. Click on the message with the IPM.Configuration.Um.CustomGreetings.External type. You will see the list of properties in the bottom pane. We are looking for the 0x7C09000A property (see Figure 3). Note that MFCMAPI cannot fully load it because it is quite large, but no worries, with our registry modification from earlier we will be just fine!

Figure 3 – Hidden Messages

Right-click it and select Edit Property as Binary Stream. As you will see, the Stream text (top window) displays the WAVEfmt in the top row – that’s the binary file format. The bottom window displays the actual hex string of the wav file (Figure 4)

 

Figure 4 – Binary Stream View

Out of the Office Greeting

The OOF greeting is very similar to personal greeting. It is also stored in the mailbox and can be accessed and dare I say it – modified - by mortals (non-Exchange UM server types) by using MAPI tools.

Conclusion

Now that you know where the Exchange 2007 Unified Messaging greetings are stored, you can better troubleshoot issues with greetings, and also do cool things such as write applications which allow users to upload a wav file as their greeting, enabling them to easily switch between multiple greetings without having to re-record them. We’ll plan to cover this for you in our future blog posts.

Currently rated 3.7 by 3 people

  • Currently 3.666667/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Exchange | MAPI | Unified Messaging

Welcome to the Infrastructure Development Blog

by alexpav 6. October 2008 14:32

Hello and welcome to the Infrastructure Development blog. Stay tuned in the next few days for great content about architecting, customizing, and deploying various complex infrastructure solutions in enterprise environments.

Currently rated 5.0 by 3 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen