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 (270k 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

Using the powershell module, I know how to create a scheduled task, and also how to bind to a scheduled task that is already known. I also have used code to try creating ... same time as another. These are all one-time tasks and will be removed once executed.

asked Jan 19 by aweight (40 points)
0 votes
1 answer

So I have custom forms for onboarding / offboarding users. We sometimes know 2-3 weeks in advance so I would like to add the ability to schedule these for the future. I ... to take all the data that was inputed and then process the request on the given date?

asked Aug 4, 2023 by thatcher (120 points)
0 votes
1 answer

Hello! how do i manage do get adaxes to remove all groups from the user after one month? We have a Business Rule where you can add an end of Date when the Account ... value field the powershell script works but not with the +1 Month. Thanks for your help!

asked Jun 14, 2023 by eww ag (140 points)
0 votes
1 answer

seting up a scheduled task to move users to thier correct OU. For some we can do this based on employee type and direct to a specific OU. For most of our users we will have to script this to move to the manager's OU.

asked Apr 12, 2023 by mightycabal (1.0k points)
3,326 questions
3,026 answers
7,727 comments
544,678 users