PowerShell – less code, same result

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:

—————————————
‘ 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:

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?

3 thoughts on “PowerShell – less code, same result

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

  2. Any chance of seeing a line with the script being use? I’m guessing it would be something like $p=password.ps1 8 is that right?

  3. Pingback: Powershell – Rename Local Admin Account OR Ecuritysay Oughthray Obscurityway | BlackOps

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>