RSS All Posts

RSS PowerShell Posts

Tags

2142 Active Directory Administrativia Announcements Battlefield Blogging Cricket Deployment Deployment4 Get-PSUGUK Group Policy HowTo Linux MDT MDT 2010 Microsoft Deployment Toolkit MSDN Music Permissions Personal PowerGui Power Lines PowerShell PowerShell Groups PowerShell Support PowerShell Tools PowerShell V2 Presentations PSUGAU Quick Tips Scripting SDDL Security Tech Talk Ubuntu User Groups Virtualisation VMware Infrastructure Client WAIK Weekly Poll Windows 7 Windows Automation Installation Kit Windows Server 2003 Windows Server 2008 XML

Archives

Meta


« | Main | »

PowerShell – less code, same result

By Adam Bell | February 28, 2007

One thing I have seen a lot of since I’ve been using PowerShell is that you can get the same tasks completed with less code.

Now with a bunch of the ADSI scripts we’ve gone through lately this isn’t blatantly obvious. These have been conversions of existing VBScripts that I have in my toolkit. However, this reduction in code has been highlighted really well in a recent script I converted.

When I create a new user account in Active Directory, I prefer to use a random password generator. Not particularly practical for creating one new account, but when you create say a hundred it becomes quite useful.

Ok, so here’s our first function:
Random.vbs


---------------------------------------
' Function        fnRandomPassword
' Abstract        Function to randomly generate a complex password
' Requirements    None
' Parameters      Integer Length of the password required.
' Return values   random complex password to specified length
' Revision        1.2
'---------------------------------------
Public Function fnRandomPassword(imLength)
  
  Dim smPassword,imRandValue, x
  Dim imSecPoint(2), imMark
  imMark = CInt(imLength/3)
'  To meet complex password requirements we need at least 1 lower, 1 numb and 1 upper.
  imSecPoint(0) = imMark
  imSecPoint(1) = imSecPoint(0) + imMark
  imSecPoint(2) = (imSecPoint(1) + imMark) -1
  If imSecPoint(2) > imLength Then imSecPoint(2) = imSecPoint(2) -1
  smPassword = ""
  Randomize
  Do while len(smPassword) < imLength
    If Len(smPassword) = imSecPoint(0) Then
'      Make sure this character is number
      imRandValue = Int((128 * Rnd) + 1)
      if imRandValue >= 48 and imRandValue <= 57 Then
        smPassword = smPassword & Chr(imRandValue)
      end if
    ElseIf Len(smPassword) = imSecPoint(1) Then
'      Make sure this character is an Lower case Alpha
      imRandValue = Int((128 * Rnd) + 1)
      if imRandValue >= 97 and imRandValue <= 122 Then
        smPassword = smPassword & Chr(imRandValue)
      end if
    ElseIf Len(smPassword) = imSecPoint(2) Then
'      Make sure this character is an Upper case Alpha
      imRandValue = Int((128 * Rnd) + 1)
      if imRandValue >= 65 and imRandValue <= 90 Then
        smPassword = smPassword & Chr(imRandValue)
      end if
    Else
'      Make the bugger complex :-)
      imRandValue = Int((128 * Rnd) + 1)
'      Due to using DCPromo.exe and HTML, we have to avoid: &<"\
      if ((imRandValue => 35) And (imRandValue =< 37)) Or _
      ((imRandValue => 39)  And (imRandValue <= 59)) Or _
      ((imRandValue >= 61) and (imRandValue <= 91)) Or _
      ((imRandValue >= 93) and (imRandValue <= 123)) then
        smPassword = smPassword & Chr(imRandValue)
      end if
    End If
  Loop
  fnRandomPassword = smPassword
  
End Function

If you’ve played with the Randomize() Statement before then there’s nothing particularly difficult here.

We define three markers in our password where we’ll ensure that we meet complex password requirements. This falls over if the password is less then five characters, but as I usually use a minimum of eight it’s not a show stopper!

Most of the hard work in this function is testing that our random number falls within acceptable values. Then we use the Char function to produce the relevant character. If you haven’t played with Char before then Microsoft have a useful table here.

This is performed for each character up until the password length and then our resulting password is returned.

So now let’s compare our PowerShell equivalent:
Random.ps1


function create-complexpassword
{
#  *** Unable to generate complex password less then 5 chars ***
#  ASCII data taken from http://msdn2.microsoft.com/en-us/library/60ecse8t(VS.80).aspx
 
Param (
  [int]$PassLength
  )
 
#  Let's work out where our 3 complex characters will be inserted in the password...
  [int]$mark = ($PassLength/3)
  $ComplexChar = @("marker")
  $ComplexChar[0] = $mark
  $ComplexChar = $ComplexChar+($ComplexChar[0] + $mark)
  $ComplexChar = $ComplexChar+(($ComplexChar[1] + $mark) -1)
 
  $Password = $null
  $rnd = new-object random
 
#  "i" is our counter while we make the password, one char at a time.
  $i = $Password.length
  do
    {
      switch ($Password.length)
        {
          $ComplexChar[0]
            {
              # Make this character a Numeric
              $password = $password+([char]($rnd.next(48,57)))
            
            }
          
          $ComplexChar[1]
            {
              # Make this character a LowerAlpha
              $password = $password+([char]($rnd.next(65,90)))
            }
          
          $ComplexChar[2]
            {
              # Make this character a Upper Alpha
              $password = $password+([char]($rnd.next(97,122)))
            }
            
          default
            {
              # In case this is used in a DCPromo answer files, theres a few chars to
              # avoid: Ampersand, Less than, double quote and back slash
              $NextChar = $rnd.next(33,123)
              
              switch ($nextChar)
                {
                  34 {exit}
                  38 {exit}
                  60 {exit}
                  92 {exit}
                  default
                    {
                      $Password = $Password+([char]$nextChar)
                  
                    }                
                }
            }
        }
      $i++
      
    }
  Until ($Password.length -eq $PassLength)
  return $Password

Apart from the code spacing within this function you can see that this is dramatically shorter than the VBScript counterpart. Now I guess this isn’t really a true PowerShell code reduction because we haven’t used a Cmdlet to reduce the code, this has been done using the .Net class Random and the Next method which allows us to specify some boundaries on our random number.

Personally, I think this still counts. What do you think? Do you have any good examples you’d like to share?

Topics: PowerShell | 1 Comment »

One Response to “PowerShell – less code, same result”

  1. MAK Says:
    March 31st, 2009 at 03:39

    Great code. Smart coding. Just a small comment. “exit” should be replaced by “break”

Comments