0 votes

I need to create a scheduled task that disables AD accounts if inactive for 30 days and then send me an email that it has run. I've got the account disable part working but i can't get it to send me 1 email for every account that was disabled but i need it to work once if it disabled any accounts or not.

by (60 points)

1 Answer

0 votes
by (289k points)

Hello,

Unfortunately, it is not possible to check whether a user is inactive for a specific number of days. It can only be done for a number of weeks. As we understand, you need the scheduled task to disable inactive users and then send an email notification for each of them. In this case, the scheduled task should look like the following: image.png If this is not what you need, please, describe the desired behavior in all the possible details with live examples.

0

Thanks for the help. This is close to what i am needing except this will send a seperate email for every account that it disables. I need it to send me one email once the task is complete (It would be nice if it could list the users disabled in the task, but it's not required). I also need it to send one email once it completes even if it doesn't disable anyone. This is what i have so far 2021-03-23_9-08-15.png

0

Hello,

Thank you for the provided details. Unfortunately, it is not possible to send such an email if the scheduled task is executed for each user separately. It can only be done using a PowerShell script. If this approach meets your needs, please, specify how the search for users should be performed. Should it be done in all the managed domains?

Also, please, provide us with a template of the email notification to be sent in both cases, when users were/were not disabled. In case of a script it will be quite easy to include names of users into the email.

0

The search for users should be performed in an OU such as "OU=Company Users,DC=Company,DC=local"

As far as the email template goes if the task disables users: Monthly Inactive Users task ran successfully on datetime Inactive Users: User1,User2,User3"

if the task doesn't diable users: Monthly Inactive Users task ran successfully on datetime No users were disabled.

0

Hello,

Thank you for your patience. Please, find the script below. I the script:

  • $days - Specifies the number of days a user should be inactive for to be updated by the script.
  • $description - Specifies the description that will be set for inactive users.
  • $pipelined - If set to $True, updating users will be passed through Adaxes pipeline to apply configured workflows (e.g. trigger corresponding business rules, create a log record in Adaxes for each update).
  • $to - Specifies the email address of the notification recipient.
  • $subject - Specifies the email notification subject.
  • $reportHeader - Specifies the report header.
  • $noUserFoundMessage - Specifies the text that will be present in the email notification if no inactive users are found.
  • $reportFooter - Specifies the report footer.
$days = 60 # TODO: modify me
$description = "Account disabled due to inactivity for $days days." # TODO: modify me
$pipelined = $False # TODO: modify me

# E-mail settings
$to = "recipient@domain.com" # TODO: modify me
$subject = "Inactive users" # TODO: modify me
$reportHeader = "<h2>Inactive users</h2>"
$noUserFoundMessage = "No users found." # TODO: modify me
$reportFooter = "<hr /><p><i>Please do not reply to this e-mail, it has been sent to you for notification purposes only.</i></p>" # TODO: modify me

# Build search filter
$threshold = (Get-Date).AddDays(- $days)
$thresholdInt64 = $threshold.ToFileTime()
$thresholdGeneralizedTime = [Softerra.Adaxes.Utils.Transform]::ToGeneralizedTime($threshold.ToUniversalTime())

$filterUsers = "(sAMAccountType=805306368)"
$filterCreatedBefore = "(whenCreated<=$thresholdGeneralizedTime)"

$filterNoLastLogonTimestamp = "(!(lastLogonTimestamp=*))"
$filterLoggedOnBeforeTimestamp = "(lastLogonTimestamp<=$thresholdInt64)"

$filterNoLastLogon = "(!(lastLogon=*))"
$filterLoggedOnBefore = "(lastLogon<=$thresholdInt64)"

$filterPasswordChangedBefore = "(pwdLastSet<=$thresholdInt64)"

$filter = "(&" +
    $filterUsers + $filterCreatedBefore +
    "(|" + $filterNoLastLogonTimestamp + $filterLoggedOnBeforeTimestamp + ")" +
    "(|" + $filterNoLastLogon + $filterLoggedOnBefore + ")" +
    $filterPasswordChangedBefore + ")"

# Search users
$searcher = $Context.TargetObject
$searcher.SearchFilter = $filter
$searcher.SearchScope = "ADS_SCOPE_SUBTREE"
$searcher.PageSize = 500

# Generate report
try
{
    # Execute search
    $searchIterator = $searcher.ExecuteSearch()
    $searchResults = $searchIterator.FetchAll()

    $foundedUsers = New-Object System.Text.StringBuilder
    foreach ($searchResult in $searchResults)
    {
        $user = $Context.BindToObjectEx($searchResult.AdsPath, $pipelined)
        $username = $Context.GetDisplayNameFromAdsPath($searchResult.AdsPath)
        $foundedUsers.Append("<li>$username</li>")

        # Disable user
        $user.AccountDisabled = $True

        # Update description
        $user.Put("description", $description)

        # Commit changes
        $user.SetInfo()
    }
}
finally
{
    # Release resources
    if ($searchIterator) { $searchIterator.Dispose() }
}

# Build mail body
$html = New-Object System.Text.StringBuilder
$html.Append($reportHeader)
if ($foundedUsers.Length -eq 0)
{
    $html.Append($noUserFoundMessage)
}
else
{
    $html.Append("<ol>")
    $html.Append($foundedUsers.ToString())
    $html.Append("</ol>")
}
$html.Append($reportFooter)

# Send mail
$Context.SendMail($to, $subject, $NULL, $html.ToString())

To execute the script, create a scheduled task configured for the Organizational Unit object type and specify the required OU in the Activity Scope of the task. Finally, it should look like the following: image.png

0

Is there a way to exclude an OU that is nested inside Company Users so that users that are in that OU are not disabled in the tast? I had this working when the object type was User. I really appreciate your help with all this.

0

Hello,

Yes, it is possible. If there are any other updates that should be done to the script, please, describe all of them in details.

0

That should be the last piece of this task. The scope right now is any user under "Company Users" i need to exclude "Company Users > Don't Disable" but still include all other OU's under "Company Users"

0

Hello,

Thank you for the confirmation. Please, find the updated script below. In the script, we added the $excludedOuDNs variable that specifies distinguished names (DNs) of the OUs users located in which will be ignored by the script. For information on how to obtain an object DN, have a look at the following SDK article: http://adaxes.com/sdk/HowDoI.GetDnOfObject.

$days = 60 # TODO: modify me
$description = "Account disabled due to inactivity for $days days." # TODO: modify me
$pipelined = $False # TODO: modify me
$excludedOuDNs = @("CN=Users,DC=domain,DC=com", "OU=Sales,DC=domain,DC=com") # TODO modify me

# E-mail settings
$to = "recipient@domain.com" # TODO: modify me
$subject = "Inactive users" # TODO: modify me
$reportHeader = "<h2>Inactive users</h2>"
$noUserFoundMessage = "No users found." # TODO: modify me
$reportFooter = "<hr /><p><i>Please do not reply to this e-mail, it has been sent to you for notification purposes only.</i></p>" # TODO: modify me

function IsDescendantOfExcludedOu ($dnObject, $excludedOuDNs)
{
    foreach ($ouDN in $excludedOuDNs)
    {
        if ($dnObject.IsDescendantOf($ouDN))
        {
            return $True
        }
    }

    return $False
}

# Build search filter
$threshold = (Get-Date).AddDays(- $days)
$thresholdInt64 = $threshold.ToFileTime()
$thresholdGeneralizedTime = [Softerra.Adaxes.Utils.Transform]::ToGeneralizedTime($threshold.ToUniversalTime())

$filterUsers = "(sAMAccountType=805306368)"
$filterCreatedBefore = "(whenCreated<=$thresholdGeneralizedTime)"

$filterNoLastLogonTimestamp = "(!(lastLogonTimestamp=*))"
$filterLoggedOnBeforeTimestamp = "(lastLogonTimestamp<=$thresholdInt64)"

$filterNoLastLogon = "(!(lastLogon=*))"
$filterLoggedOnBefore = "(lastLogon<=$thresholdInt64)"

$filterPasswordChangedBefore = "(pwdLastSet<=$thresholdInt64)"

$filter = "(&" +
    $filterUsers + $filterCreatedBefore +
    "(|" + $filterNoLastLogonTimestamp + $filterLoggedOnBeforeTimestamp + ")" +
    "(|" + $filterNoLastLogon + $filterLoggedOnBefore + ")" +
    $filterPasswordChangedBefore + ")"

# Search users
$searcher = $Context.TargetObject
$searcher.SearchFilter = $filter
$searcher.SearchScope = "ADS_SCOPE_SUBTREE"
$searcher.PageSize = 500

# Generate report
try
{
    # Execute search
    $searchIterator = $searcher.ExecuteSearch()
    $searchResults = $searchIterator.FetchAll()

    $foundedUsers = New-Object System.Text.StringBuilder
    foreach ($searchResult in $searchResults)
    {
        $dnObject = New-Object "Softerra.Adaxes.Ldap.DN" $searchResult.Properties["distinguishedName"].Value
        if (IsDescendantOfExcludedOu $dnObject $excludedOuDNs)
        {
            continue
        }

        $user = $Context.BindToObjectEx($searchResult.AdsPath, $pipelined)
        $username = $Context.GetDisplayNameFromAdsPath($searchResult.AdsPath)
        $foundedUsers.Append("<li>$username</li>")

        # Disable user
        $user.AccountDisabled = $True

        # Update description
        $user.Put("description", $description)

        # Commit changes
        $user.SetInfo()
    }
}
finally
{
    # Release resources
    if ($searchIterator) { $searchIterator.Dispose() }
}

# Build mail body
$html = New-Object System.Text.StringBuilder
$html.Append($reportHeader)
if ($foundedUsers.Length -eq 0)
{
    $html.Append($noUserFoundMessage)
}
else
{
    $html.Append("<ol>")
    $html.Append($foundedUsers.ToString())
    $html.Append("</ol>")
}
$html.Append($reportFooter)

# Send mail
$Context.SendMail($to, $subject, $NULL, $html.ToString())
0

This worked great but i'm having two issues.

  1. The task will re-run on users that are already disabled. Can i set it to only disable enabled users?
  2. It sends an email for every OU and then sends an email with the full list it disabled. So I end up with almost 100 emails when the task completes.
0

Any update?

0

Hello,

Sorry for the delay.

The task will re-run on users that are already disabled. Can i set it to only disable enabled users?

Yes, it is possible. We will update the script accordingly.

It sends an email for every OU and then sends an email with the full list it disabled.

Sorry for the confusion, but we are not sure what exactly you mean. Could you, please, post here or send us (support@adaxes.com) a screenshot of the scheduled task including its Activity Scope? Any additional details will be much appreciated.

0

Here is a screenshot of the task. 2021-04-01_9-08-02.png Here is an example of the Active Directory structure. I will get an email for each department inside location 1, then i will get an email that combines all of location 1 then i will get an email for each department inside location 2 and an email that combines all of locaton 2 once it reaches the last OU it will send an email that has every department at every location combined. 2021-04-01_9-09-30.png

0

Hello,

Here is a screenshot of the task.

The behavior occurs because the scheduled task is assigned over the Company users OU subtree, not the OU itself as it was shown in the post where we shared the initial script. To achieve the desired:

  1. Launch Adaxes Administration console.
  2. In the Console Tree, expand your service node.
  3. Navigate to Configuration\Scheduled Tasks and select the task you need.
  4. In the Activity Scope section on the right, select Company Users and click Edit below. image.png
  5. Select the The Organizational Unit object checkbox.
  6. Clear all the other checkboxes and click OK. image.png
  7. Save the changes. Finally, the Activity Scope of the task should look exactly like below (the Scope column should be This object only): image.png

Can i set it to only disable enabled users?

To achieve the desired, replace this line in the script

$filterUsers = "(sAMAccountType=805306368)"

with the below one:

$filterUsers = "(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))"

Related questions

0 votes
1 answer

Hi Team I am testing out a scheduled task to send out an email for password self service enrolment and located a previous question which suggested using the adm- ... or has the state of a users self service enrollment moved to another property?

asked Feb 26, 2021 by Richard_NRL (90 points)
0 votes
1 answer

Is there a way to get an email alert before the Adaxes lisense expires? Ex.: our license expires 13.09.2025 and would like an alert to be sent 14 days before this date.

asked Oct 18 by Handernye (100 points)
0 votes
1 answer

If I have a scheduled task powershell script that's targeting an OU of users and in that script I were to call $context.cancel in the case of an error happening for a single ... it cancel the entire scheduled tasks and it won't run for other users in that OU?

asked Oct 18 by wrichardson (20 points)
0 votes
1 answer

Hello, I've created a custom command to run a script which will send an email alert if the script encounters an error. I have the command set to run as a scheduled task ... script that sends it: Custom Command Name: Task Name: Time: Error Message: Thank you.

asked Sep 17 by GronTron (320 points)
0 votes
1 answer

Similar to Powershell's "whatif"? I'd like to enable this scheduled task - But would like to confirm who will actually be affected before enabling this. Is there at least ... objects in the console log? I could run that before adding the 'modify' actions back.

asked Jun 25 by msinger (210 points)
3,548 questions
3,238 answers
8,232 comments
547,810 users