0 votes

I found a really nice password expire notification script on the net at http://www.ehloworld.com/318. I decided to test it inside of a scheduled tasks and it works . However it continues to loop through the script sending email's to the soon to expire users. I would use the built in version within Adaxes, but it seemed lacking and we had already been using this as a scheduled windows task on a utility server. Any help would be greatly appreciated on what it is i could do to stop it from looping.

[cmdletBinding(SupportsShouldProcess = $true)]
param(
    [parameter(ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, Mandatory = $false)] 
    [switch]$Demo,
    [parameter(ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, Mandatory = $false)] 
    [switch]$Install,
    [parameter(ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, Mandatory = $false)] 
    [switch]$Preview,
    [parameter(ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, Mandatory = $false)] 
    [string]$PreviewUser,
    [parameter(ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, Mandatory = $false)] 
    [bool]$NoImages = $true
)
Write-Verbose "Setting variables"
[string]$Company = "Company"
[string]$OwaUrl = "OWA URL"
[string]$PSEmailServer = "IP Address"
[string]$EmailFrom = "Help Desk Email"
[string]$HelpDeskPhone = "Phone Number"
[string]$HelpDeskURL = "Help Desk"
[string]$TranscriptFilename = $MyInvocation.MyCommand.Name + " " + $env:ComputerName + " {0:yyyy-MM-dd hh-mmtt}.log" -f (Get-Date)
[int]$global:UsersNotified = 0
[int]$DaysToWarn = 14
[string]$ImagePath = "http://website.com"
[string]$ScriptName = $MyInvocation.MyCommand.Name
[string]$ScriptPathAndName = $MyInvocation.MyCommand.Definition
[string]$ou
[string]$DateFormat = "d"

if ($PreviewUser){
    $Preview = $true
}

Write-Verbose "Defining functions"
function Set-ModuleStatus { 
    [cmdletBinding(SupportsShouldProcess = $true)]
    param    (
        [parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Mandatory = $true, HelpMessage = "No module name specified!")] 
        [string]$name
    )
    if(!(Get-Module -name "$name")) { 
        if(Get-Module -ListAvailable | ? {$_.name -eq "$name"}) { 
            Import-Module -Name "$name" 
            # module was imported
            return $true
        } else {
            # module was not available
            return $false
        }
    }else {
        # module was already imported
        return $true
    }
} # end function Set-ModuleStatus

function Remove-ScriptVariables {  
    [cmdletBinding(SupportsShouldProcess = $true)]
    param(
        [string]$path
    )
    $result = Get-Content $path |  
    ForEach { 
        if ( $_ -match '(\$.*?)\s*=') {      
            $matches[1]  | ? { $_ -notlike '*.*' -and $_ -notmatch 'result' -and $_ -notmatch 'env:'}  
        }  
    }  
    ForEach ($v in ($result | Sort-Object | Get-Unique)){        
        Remove-Variable ($v.replace("$","")) -EA 0
    }
} # end function Remove-ScriptVariables

function Install    {
    [cmdletBinding(SupportsShouldProcess = $true)]
    param()
    $error.clear()
    Write-Host "Creating scheduled task `"$ScriptName`"..."
    $TaskCreds = Get-Credential("$env:userdnsdomain\$env:username")
    $TaskPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($TaskCreds.Password))
    schtasks /create /tn $ScriptName /tr "$env:windir\system32\windowspowershell\v1.0\powershell.exe -command $ScriptPathAndName" /sc Daily /st 06:00 /ru $TaskCreds.UserName /rp $TaskPassword | Out-Null
    if (! $error){
        Write-Host "Installation complete!" -ForegroundColor green
    }else{
        Write-Host "Installation failed!" -ForegroundColor red
    }
    remove-variable taskpassword
    exit
} # end function Install

function Get-ADUserPasswordExpirationDate {
    [cmdletBinding(SupportsShouldProcess = $true)]
    Param (
        [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, HelpMessage = "Identity of the Account")]
        [Object]$accountIdentity
    )
    PROCESS {
        Write-Verbose "Getting the user info for $accountIdentity"
        $accountObj = Get-ADUser $accountIdentity -properties PasswordExpired, PasswordNeverExpires, PasswordLastSet, name, mail
        # Make sure the password is not expired...is the account de-provisioned?
    Write-Verbose "verifying that the password is not expired, and the user is not set to PasswordNeverExpires"
    if (((!($accountObj.PasswordExpired)) -and (!($accountObj.PasswordNeverExpires))) -or ($PreviewUser)) {
        Write-Verbose "Verifying if the date the password was last set is available"
        $passwordSetDate = $accountObj.PasswordLastSet         
      if ($passwordSetDate -ne $null) {
          $maxPasswordAgeTimeSpan = $null
        Write-Verbose "Determining domain functional level"
        if ($global:dfl -ge 4) { # 2008 Domain functional level
          $accountFGPP = Get-ADUserResultantPasswordPolicy $accountObj
          if ($accountFGPP -ne $null) {
              $maxPasswordAgeTimeSpan = $accountFGPP.MaxPasswordAge
                    } else {
                        $maxPasswordAgeTimeSpan = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
                    }
                } else { # 2003 or ealier Domain Functional Level
                    $maxPasswordAgeTimeSpan = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
                }                
                if ($maxPasswordAgeTimeSpan -eq $null -or $maxPasswordAgeTimeSpan.TotalMilliseconds -ne 0) {
                    $DaysTillExpire = [math]::round(((New-TimeSpan -Start (Get-Date) -End ($passwordSetDate + $maxPasswordAgeTimeSpan)).TotalDays),0)
                    if ($preview){$DaysTillExpire = 1}
                    if ($DaysTillExpire -le $DaysToWarn){
                        Write-Verbose "User should receive email"
                        $PolicyDays = [math]::round((($maxPasswordAgeTimeSpan).TotalDays),0)
                        if ($demo)    {Write-Host ("{0,-25}{1,-8}{2,-12}" -f $accountObj.Name, $DaysTillExpire, $PolicyDays)}
            # start assembling email to user here....grab this script from technet
                        $EmailName = $accountObj.Name                        
                        $DateofExpiration = (Get-Date).AddDays($DaysTillExpire)
                        $DateofExpiration = (Get-Date($DateofExpiration) -f $DateFormat)                        

Write-Verbose "Assembling email message"                        
[string]$emailbody = @"
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <style type="text/css">

        .auto-style1 {
            color: #FF0000;
        }
        </style>
    </head>
<body>    
"@

if (!($NoImages)){
$emailbody += @"    
    <table id="email" border="0" cellspacing="0" cellpadding="0" width="655" align="center">
        <tr>
            <td align="left" valign="top"><img src="$ImagePath/spacer.gif" alt="Description: $ImagePath/spacer.gif" width="46" height="28" align="absMiddle">
            </td>
        </tr>
"@                        

if ($HelpDeskURL){        
$emailbody += @"
            <tr><td height="121" align="left" valign="bottom"><a href="$HelpDeskURL"><img src="$ImagePath/header.gif" border="0" alt="Description: $ImagePath/header.gif" width="655" height="121"></a></td></tr>
"@
}else{
$emailbody += @"    
            <tr><td height="121" align="left" valign="bottom"><img src="$ImagePath/header.gif" border="0" alt="Description: $ImagePath/header.gif" width="655" height="121"></td></tr>
"@
}

$emailbody += @"
        <tr>
            <td>
                <table id="body" border="0" cellspacing="0" cellpadding="0">
                    <tr>
                        <td width="1" align="left" valign="top" bgcolor="#a8a9ad"><img src="$ImagePath/spacer50.gif" alt="Description: $ImagePath/spacer50.gif" width="1" height="50"></td>
                        <td><img src="$ImagePath/spacer.gif" alt="Description: $ImagePath/spacer.gif" width="46" height="106"></td>
                        <td id="text" width="572" align="left" valign="top" style="font-size: 12px; color: #000000; line-height: 17px; font-family: Verdana, Arial, Helvetica, sans-serif">
"@
}
if ($DaysTillExpire -le 1){
    $emailbody += @"
        <div align='center'>
            <table border='0' cellspacing='0' cellpadding='0' style='width:510px; background-color: white; border: 0px;'>
                <tr>
"@
if (!($NoImages)){
$emailbody += @"
                    <td align='right'><img width='36' height='28' src='$ImagePath/image001b.gif' alt='Description: $ImagePath/image001b.gif'></td>    
"@
}
$emailbody += @"
                    <td style="font-family: verdana; background: #E12C10; text-align: center; padding: 0px; font-size: 9.0pt; color: white">ALERT: You must change your password today or you will be locked out!</td>        
"@
if (!($NoImages)){
$emailbody += @"
                    <td align='left'><img border='0' width='14' height='28' src='$ImagePath/image005b.gif' alt='Description: $ImagePath/image005b.gif'></td>
"@
}
$emailbody += @"
                </tr>
            </table>
        </div>
"@
}

$emailbody += @"
            <p style="font-weight: bold">Hello, $EmailName,</p>
            <p>It's password changing time again! Your $company password expires in <span style="background-color: red; color: white; font-weight: bold;">&nbsp;$DaysTillExpire&nbsp;</span> day(s), on $DateofExpiration.</p>
                        <p>&nbsp;</p>
            <p>Please use one of the methods below to update your password:</p>
            <ol>
                <li>$company office computers: You may update your password on your computer by pressing Ctrl-Alt-Delete and selecting 'Change 
                a Password...' from the available options. If you use a $company laptop in addition to a desktop PC, be sure and read #3 below.</li>
                <li>Remote Outlook Client, Mac, and/or Outlook Web App users: If you only access our email system, please use the following method to easily change your password:</li>
                <ul>
                    <li>Log into <a href="$owaurl">Outlook Web App</a> using Internet Explorer (PC) or 
                    Safari or Firefox.</li>
                    <li>Click on the Options button in the upper right corner of the page.</li>        
                    <li>Select the "Change your Password" link to change your password.</li>
                    <li>Enter your current password, then your new password twice, and click Save</li>
                </ul>
                <li>$company issued laptops/tablets: If you have been issued a $company laptop, 
                or tablet you must be in a corporate office or directly connected to the company 
                over VPN network to change your password. If you also use a desktop PC in the office, you must remember to always update your domain password on the laptop/tablet first. Your desktop will automatically use the new password.</li>
                <ul>
                    <li>Log in on laptop/tablet</li>
                    <li>Press Ctrl-Alt-Delete and select 'Change a Password...' from the available options.</li>
                    <li>Make sure your workstation (if you have one) has been logged off any previous sessions so as to not cause conflict with your new password.</li>
                </ul>
            </ol>
                        <p><span class="auto-style1">NOTE:</span> You will now 
                        need to use your new password when logging into Outlook 
                        Web App, Outlook 2010, SharePoint, Windows Mobile 
                        (ActiveSync) devices, etc. If you have been assigned an 
                        iPhone or iPad you will need to update each device with 
                        your new password. Blackberry Enterprise Users (BES) 
                        will not need to update their password.</p>
                        <ol>
                            <li>
                            <span style="font-size:11.0pt;font-family:"Calibri","sans-serif";
mso-fareast-font-family:Calibri;mso-fareast-theme-font:minor-latin;mso-ansi-language:
EN-US;mso-fareast-language:EN-US;mso-bidi-language:AR-SA">To update the password 
                            in your iPhone or iPad do the following:</span><ul>
                                <li>Go to Settings then select Mail, Contacts, 
                                Calendars, this will list all email accounts 
                                synced to your device.</li>
                                <li>Select Exchange, which is your SAM Inc email 
                                account, and then touch the Account field with 
                                your email address to edit credentials.</li>
                                <li>Clear then update the password field with 
                                your new password and select done. A checkmark 
                                to the right of each field will verify your 
                                password has been accepted and updated.</li>
                            </ul>
                            <p class="MsoNormal">&nbsp;</p>
                            </li>
            </ol>
            <p>Think you've got a complex password? Run it through the <a href="http://www.passwordmeter.com/">The Password Meter</a></p>
            <p>Think your password couldn't easily be hacked? See how long it would take: <a href="http://howsecureismypassword.net/">How Secure Is My Password</a></p>
                        <p>Remember, if you do not change your password before it expires on $DateofExpiration, you will be locked out of all $company Computer Systems until an Administrator unlocks your account.</p>
                        <p>If you are traveling or will not be able to bring your laptop into the office before your password expires, please call the number below for additional instructions.</p>
                        <p>&nbsp;You will continue to receive these emails daily until the password is changed or expires.</p>
                        <p>&nbsp;</p>

            <p>Thank you,<br />
            The $company Help Desk<br />
            $HelpDeskPhone</p>
"@            
if ($accountFGPP -eq $null){ 
    $emailbody += @"
            <table style="background-color: #dedede; border: 1px solid black">
                <tr>
                    <td style="font-size: 12px; color: #000000; line-height: 17px; font-family: Verdana, Arial, Helvetica, sans-serif"><b>$company Password Policy</b>
                        <ul>
                            <li>Your password must have a minimum of a $MinPasswordLength characters.</li>
                            <li>You may not use a previous password.</li>
                            <li>Your password must not contain parts of your first, last, or logon name.</li>
                            <li>Your password must be changed every $PolicyDays days.</li>
"@                            

if ($PasswordComplexity){
    Write-Verbose "Password complexity"
    $emailbody += @"
                            <li>Your password requires a minimum of two of the following three categories:</li>
                            <ul>
                                <li>1 upper case character (A-Z)</li>
                                <li>1 lower case character (a-z)</li>
                                <li>1 numeric character (0-9)</li>                                
                            </ul>
"@
}
$emailbody += @"
                            <li>You may not reuse any of your last $PasswordHistory passwords</li>
                        </ul>
                    </td>
                </tr>
            </table>
"@
}
if (!($NoImages)){
$emailbody += @"                                
                            </td>
                            <td width="49" align="left" valign="top"><img src="$ImagePath/spacer50.gif" alt="" width="49" height="50"></td>
                            <td width="1" align="left" valign="top" bgcolor="#a8a9ad"><img src="$ImagePath/spacer50.gif" alt="Description: $ImagePath/spacer50.gif" width="1" height="50"></td>
                        </tr>
                    </table>
                    <table id="footer" border="0" cellspacing="0" cellpadding="0" width="655">
                        <tr>
                            <td><img src="$ImagePath/footer.gif" alt="Description: $ImagePath/footer.gif" width="655" height="81"></td>
                        </tr>
                    </table>
                    <table border="0" cellspacing="0" cellpadding="0" width="655" align="center">
                        <tr>
                            <td align="left" valign="top"><img src="$ImagePath/spacer.gif" alt="Description: $ImagePath/spacer.gif" width="36" height="1"></td>
                            <td align="middle" valign="top"><font face="Verdana" size="1" color="#000000"><p>This email was sent by an automated process. 
"@
}
if ($HelpDeskURL){
$emailbody += @"                                                            
                            If you would like to comment on it, please visit <a href="$HelpDeskURL"><font color="#ff0000"><u>click here</u></font></a>
"@
}
if (!($NoImages)){
$emailbody += @"
                                </p></font>
                            </td>
                            <td align="left" valign="top"><img src="$ImagePath/spacer.gif" alt="Description: $ImagePath/spacer.gif" width="36" height="1"></td>
                        </tr>
                    </table>
                </td>
            </tr>
        </table>
"@
}
$emailbody += @"
    </body>
</html>
"@
                        if (!($demo)){
                            $emailto = $accountObj.mail
                            if ($emailto){
                                Write-Verbose "Sending demo message to $emailto"
                                Send-MailMessage -To $emailto -Subject "Your password expires in $DaysTillExpire day(s)" -Body $emailbody -From $EmailFrom -Priority High -BodyAsHtml
                                $global:UsersNotified++
                            }else{
                                Write-Verbose "Can not email this user. Email address is blank"
                            }
                        }
                    }
                }
            }
        }
    }
} # end function Get-ADUserPasswordExpirationDate

if ($install){
    Write-Verbose "Install mode"
    Install
    Exit
}

Write-Verbose "Checking for ActiveDirectory module"
if ((Set-ModuleStatus ActiveDirectory) -eq $false){
    $error.clear()
    Write-Host "Installing the Active Directory module..." -ForegroundColor yellow
    Set-ModuleStatus ServerManager
    Add-WindowsFeature RSAT-AD-PowerShell
    if ($error){
        Write-Host "Active Directory module could not be installed. Exiting..." -ForegroundColor red; 
        if ($transcript){Stop-Transcript}
        exit
    }
}
Write-Verbose "Getting Domain functional level"
$global:dfl = (Get-AdDomain).DomainMode
# Get-ADUser -filter * -properties PasswordLastSet,EmailAddress,GivenName -SearchBase "OU=Users,DC=domain,DC=test" |foreach {
if (!($PreviewUser)){
    if ($ou){
        Write-Verbose "Filtering users to $ou"
        $users = Get-AdUser -filter * -SearchScope subtree -SearchBase $ou -ResultSetSize $null
    }else{
        $users = Get-AdUser -filter * -ResultSetSize $null
    }
}else{
    Write-Verbose "Preview mode"
    $users = Get-AdUser $PreviewUser
}
if ($demo){
    Write-Verbose "Demo mode"
    # $WhatIfPreference = $true
    Write-Host "`n"
    Write-Host ("{0,-25}{1,-8}{2,-12}" -f "User", "Expires", "Policy") -ForegroundColor cyan
    Write-Host ("{0,-25}{1,-8}{2,-12}" -f "========================", "=======", "===========") -ForegroundColor cyan
}

Write-Verbose "Setting event log configuration"
[object]$evt = new-object System.Diagnostics.EventLog("Application")
[string]$evt.Source = $ScriptName
$infoevent = [System.Diagnostics.EventLogEntryType]::Information
[string]$EventLogText = "Beginning processing"
$evt.WriteEntry($EventLogText,$infoevent,70)

Write-Verbose "Getting password policy configuration"
$DefaultDomainPasswordPolicy = Get-ADDefaultDomainPasswordPolicy
[int]$MinPasswordLength = $DefaultDomainPasswordPolicy.MinPasswordLength
# this needs to look for FGPP, and then default to this if it doesn't exist
[bool]$PasswordComplexity = $DefaultDomainPasswordPolicy.ComplexityEnabled
[int]$PasswordHistory = $DefaultDomainPasswordPolicy.PasswordHistoryCount

ForEach ($user in $users){
    Get-ADUserPasswordExpirationDate $user.samaccountname
}

# $WhatIfPreference = $false

Remove-ScriptVariables -path $ScriptPathAndName
by (70 points)
0

Hello,

What actually do you need in the Adaxes built-in Password Expiration Notifier Scheduled Task that you use this script? Maybe we could advise you on modifying the built-in Task to your requirements?

Also, how of is the script scheduled to run?

0

In a nutshell we wanted to be able to utilize HTML is why we choose this script and not have to write something completely new within Adaxes. The schedule is set for all objects and to be ran everyday at 10am.

0

Hello,

OK, I'll ask our script guy to have a closer look at it.

1 Answer

0 votes
by (1.2k points)

Your script is going through AD and getting all the users that will expire. Are you also telling Adaxes to run for each user that will expire? If so, you will run this script for repeatedly for each user that meets the criteria you have set in the adaxes scheduled task. You need to either run by itself or it needs to be modified to take the output from Adaxes.

0

I'm only telling Adaxes to run the script in a scheduled task.

0

Hello,

Can you post here a screenshot of your Scheduled Task that launches the script with the actions and conditions section and the Activity Scope section visible?

0

0

Hello,

As previously mentioned by jiambor, your script is searching the whole of the AD and getting all the users, whose passwords are soon to expire. You created a Scheduled Task that is available for the User object type and included All Objects in the Assignment Scope. This means that the Task runs the script for every user in your Active Directory. So, the script will be run by the Task as many times as many users you have in your AD.

To avoid the task recurring many times, you need to create another Scheduled Task that will be run the script only once. To create such a Scheduled Task:

  1. Create a new Scheduled Task.
  2. On the 3rd step of the Create Scheduled Task wizard, select the Show all object types checkbox and select the Domain-DNS object type.
  3. On the 4th step, click Add Action.
  4. In the dialog box that appears, select the Run a program of PowerShell script action.
  5. Paste your script that you use to notify users about password expiration in the Script field.
  6. Enter a short description for the script and click OK.
  7. On the Activity Scope step of the wizard, add any of your domains to the activity scope of the task.

Related questions

0 votes
1 answer

We are evaluating the product and would like to let users of AD to change password in self service page. We would like to set a 90 days change password policy, ... self service page? Is it achievable (with customization and batch program)? Thanks in advance.

asked Apr 27, 2020 by eric (20 points)
0 votes
1 answer

We are using the Builtin scheduled task to let our domain users know when their password will expire in the next 2 weeks. As in ... If password will expire in less than ... problem (like wjpatterson, above) the Password section has a N/A in it. Regards, Jim

asked May 13, 2014 by jfarley (20 points)
0 votes
1 answer

Right now I have a scheduled task that runs on all user accounts and sends and HTML email to users when their password will expire. The problem with this method is that ... to look for users with expiring passwords. I could use some help sorting that out.

asked Jul 10, 2020 by dtb147 (290 points)
0 votes
0 answers

I am trying to enable the email notification for user password expiration. We use O365 and I have setup the Mail Settings but I get the following error: The SMTP server ... .7.57 SMTP; Client was not authenticated to send anonymous mail What am I missing?

asked Dec 1, 2017 by bbuck (140 points)
0 votes
1 answer

We are looking to implement an email going to the manager of end user and end user that a password request was performed. We will use this a security measure similar to ... this to be a great stop gap measure for security. Please advise if this is possible.

asked Dec 9, 2016 by willy-wally (3.2k points)
3,553 questions
3,244 answers
8,247 comments
547,833 users