Thursday, September 23, 2010

Resetting Consultant Passwords

We have an issues with certain consultants that only logon once every few months and therefore their password has expired. They can’t change it because they never logged on during the grace period so now the account is locked out. Normally they could call the helpdesk during regular working hours and have the password reset and it wouldn’t be a big deal, however some of these accounts are for offshore remote monitoring services that only logon when there is a problem. When there is a problem they need to logon and they need to logon NOW!
I solved this issue for our organization by creating a script that will query AD and return the users from the ‘Consultants’ group and if the password is about to expire (7 days) it will reset it and email it to the address stored in the ‘emailaddress’ attribute of AD. I know the idea of emailing passwords plaintext over the internet is a horrid security practice, however it was deemed acceptable by people of a higher rank than I…
Import-Module ActiveDirectory

Function CreatePassword {
    param ( $Characters )
    
    [System.Security.SecureString]$password = New-Object System.Security.SecureString
    #Set up random number generator
    $rand = New-Object System.Random
    #Generate a new 10 character password
    [int]$int = $Characters/4
    1..$int | ForEach { $NewPassword = $NewPassword + [char]$rand.next(65,90) }
    ($int+1)..($int*2) | ForEach { $NewPassword = $NewPassword + [char]$rand.next(33,64) }
    (($int*2)+1)..($int*3) | ForEach { $NewPassword = $NewPassword + [char]$rand.next(97,122) }
    (($int*3)+1)..$Characters | ForEach { $NewPassword = $NewPassword + [char]$rand.next(48,57) }
    
    $secureString = new-object Security.SecureString
    $NewPassword.ToCharArray() | % { $secureString.AppendChar($_) }
    @{'SecurePassword'=$secureString;'PlainPassword'=$NewPassword}
}

function SendEmail {
    param(
        $array
    )

    $SMTPServer = "smtp.domain.com"
    # Create from/to addresses  
    $FromObject = New-Object System.Net.Mail.MailAddress $array[0]  
    $ToObject =   New-Object System.Net.Mail.MailAddress $array[1]
  
    # Create Message  
    $message = new-object  System.Net.Mail.MailMessage $FromObject, $ToObject  
    $message.Subject = $array[2]
    $message.Body = $array[3]
  
    $client = new-object system.net.mail.smtpclient $SMTPServer  
  
    # Send the message  
#    "Sending an e-mail message to {0} by using SMTP host {1} port {2}." -f $to.ToString(), $client.Host, $client.Port  
    try {  
           $client.Send($message)  
#          "Message to: {0}, from: {1} has beens successfully sent" -f $from, $to  
    }  
    catch {  
          "Exception caught in CreateTestMessage: {0}" -f $Error.ToString()  
    } 
}

function ResetPassword() {
    # function taken from MSDN and modified for my needs
    # http://blogs.msdn.com/b/adpowershell/archive/2010/02/26/find-out-when-your-password-expires.aspx
    Param ([Parameter(Mandatory=$true,  Position=0,  ValueFromPipeline=$true, HelpMessage="Identity of the Account")]
    [Object] $accountIdentity)
    PROCESS {
        $accountObj = Get-ADUser $accountIdentity -properties PasswordExpired, PasswordNeverExpires, PasswordLastSet
        if ($accountObj.PasswordExpired) {
            #echo ("Password of account: " + $accountObj.Name + " already expired!")
            $true
        } else { 
            if ($accountObj.PasswordNeverExpires) {
                #echo ("Password of account: " + $accountObj.Name + " is set to never expires!")
                $false
            } else {
                $passwordSetDate = $accountObj.PasswordLastSet
                if ($passwordSetDate -eq $null) {
                    #echo ("Password of account: " + $accountObj.Name + " has never been set!")
                    $true
                }  else {
                    $maxPasswordAgeTimeSpan = $null
                    $dfl = (get-addomain).DomainMode
                    if ($dfl -ge 3) { 
                        ## Greater than Windows2008 domain functional level
                        $accountFGPP = Get-ADUserResultantPasswordPolicy $accountObj
                        if ($accountFGPP -ne $null) {
                            $maxPasswordAgeTimeSpan = $accountFGPP.MaxPasswordAge
                        } else {
                            $maxPasswordAgeTimeSpan = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
                        }
                    } else {
                        $maxPasswordAgeTimeSpan = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
                    }
                    if ($maxPasswordAgeTimeSpan -eq $null -or $maxPasswordAgeTimeSpan.TotalMilliseconds -eq 0) {
                        #echo ("MaxPasswordAge is not set for the domain or is set to zero!")
                    } else {
                        #echo ("Password of account: " + $accountObj.Name + " expires on: " + ($passwordSetDate + $maxPasswordAgeTimeSpan))
                        $ResetDate = Get-Date
                        if (($passwordSetDate + $maxPasswordAgeTimeSpan) -lt $ResetDate.AddDays(7)){
                            $true
                        } else {
                            $false
                        }
                    }
                }
            }
        }
    }
}

if ($Consultants.Length -gt 0) {
    Remove-Variable Consultants
}
$Consultants = Get-ADGroupMember "Role_Consultants" -Recursive

if ($NewPassword.Length -gt 0) {
    Remove-Variable NewPassword
}

foreach ($user in $Consultants) {
    
    if (ResetPassword($user)) {
        $UserAccount = Get-ADUser -Identity $user -Properties EmailAddress
        $NewPassword = CreatePassword(12)
        $PlainPassword = $NewPassword.PlainPassword
        Set-ADAccountPassword -Identity $user -NewPassword $NewPassword.SecurePassword
        SendEmail("NetAdmins@domain.com",$UserAccount.EmailAddress,"Domain User Account Update","Your network password has been changed to $PlainPassword")
        
        Write-Host $user.Name $NewPassword.PlainPassword
    
        Remove-Variable NewPassword
    } else {
        Write-Host "$User.Name password does not need to be reset"
    }
}



No comments:

Post a Comment