« Searching Active Directory for Windows 2000 and Windows NT4 Domain Controllers with PowerShell | Main | PowerShell and XML »
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?
- None Found
Topics: PowerShell | 1 Comment »
March 31st, 2009 at 03:39
Great code. Smart coding. Just a small comment. “exit” should be replaced by “break”