How to Disable Stale (Inactive) Accounts in AD via FIM

A common requirement for organizations is to disable Active Directory (AD) accounts when the account is stale (inactive). Often times the IT department will run a script directly against their AD that will identify those accounts, and then disable and move them to a specified OU. While this is effective for many, it will likely cause problems in an organization where FIM is authoritative for user accounts. In these cases, FIM may reverse the change by moving the inactive account back to the original location and re-enabling the account. Or, if the AD account is moved to an OU that FIM does not have control, then the account is in an orphaned state where changes made to the account in FIM will not impact the account in AD. In addition, FIM will continue to have export errors on the AD MA as it tries to reprovision the account to AD with the same samAccountName. Having an orphaned and enabled inactive account in Active Directory is a significant security concern and errors on export are never a good thing. So, for organizations where FIM is authoritative for user accounts, it is best to use FIM to manage this process. This blog posting will detail a solution that makes this possible.

The Summarized Solution Steps are as follows:

  1. Establish a New Boolean Attribute on User Accounts in FIM called StaleAccount
  2. Add New StaleAccount Attribute to the Metaverse
  3. Configure Attribute Flow on FIM Service MA
  4. Update AD Outbound Portal Sync Rule to do the following when StaleAccount is “True”:
    1. Disable the Account in AD
    2. Change the Description on the Account in AD to “FIM Disabled – Stale Account”
    3. Move the Account to a Disabled Users OU in AD
  5. Enable FIMAutomation PowerShell script that will do the following:
    1. Identify stale accounts in AD
    2. Mark the StaleAccount attribute “True” for those accounts
  6. Add StaleAccount attribute to User RCDCs
  7. Synchronization

Now, I’ll provide the details:

Step 1: Establish a New Boolean Attribute on User Accounts in FIM called StaleAccount

1. Create new Attribute according to the summary settings in the screenshot below:

Disable Stale (Inactive) Accounts in AD via FIM - Create StaleAccount Attribute

2. The screenshot below is a summary of the settings for the new binding:

Disable Stale (Inactive) Accounts in AD via FIM - Create StaleAccount Binding

3. Don’t forget to add the new attribute to the “Administration: Administrators can read and update Users” MPR and the “Administrator Filter Permissions”.

Step 2: Add New Attribute to the Metaverse

Portal Synchronization rules are evaluated in the Metaverse. Therefore, it’s necessary to add the staleAccount attribute with the following steps:

  1. Open Sync Manager and select Metaverse Designer tab
  2. Highlight Person Object Type
  3. From bottom right Actions menu, select Add Attribute
  4. From Add Attribute to Object Type window, select New Attribute button
  5. In the New Attribute window, enter “staleAccount” for the Attribute name, change Attribute type to Boolean, and leave defaults for the other options and select OK
  6. Select the Management Agents tab
  7. Select the MA for the MIM Service and click Refresh Schema from the Actions menu
  8. Enter the service account password, click OK and you should receive a message “The new schema has been committed to the server”

Step 3 : Configure Attribute Flow on FIM Service MA

Portal Synchronization rules are evaluated in the Metaverse. Therefore, it is necessary to flow the StaleAccount attribute with the following steps:

  1. Open Sync Manager and open the Properties of the FIM Service MA
  2. Click on Select Attributes from the left window pane
  3. Select the Show All check box
  4. Find and check the StaleAccount attribute and select OK
  5. Re-open the Properties of the FIM Service MA
  6. Select the Configure Attribute Flow from the left window pane
  7. Add a new import flow for Object Type Person: StaleAccount (Data source)  –> staleAccount (Metaverse)

Step 4: Update AD Outbound Portal Sync Rule when StaleAccount is “True”:

The synchronization rule will disable the account in AD, move the account to a disabled users OU, and change the description to “FIM Disabled – Stale Account”.

  1. In the first flow, use a CustomExpression so that if staleAccount is “True” it will change the description to “FIM Disabled – Stale Account” otherwise the description will be the user’s Lastname, Firstname.
Source: IIF(staleAccount,"FIM Disabled - Stale Account",lastName+", "+firstName)

Destination: Description

2. In the second flow, use a CustomExpression so that if staleAccount is “True” it will write “514” to the userAccountControl attribute in AD, thereby disabling the account, otherwise it will write “512”,     thereby enabling the Account.

Source: IIF(staleAccount,514,512)

Destination: userAccountControl

3. In the final flow, use a CustomExpression so that if staleAccount is “True” it will move the account to a disabled user’s OU, otherwise it will move it to the normal OU for standard users. Of course,     the distinquishedNames will need to be adjusted for your specific environment.

Source: IIF(staleAccount,"CN="+accountName+",OU=Disabled,OU=Standard Users,DC=Corp,DC=local","CN="+accountName+",OU=Standard Users,DC=Corp,DC=local"

Destination: dn

4. At this point you can run a Full Import/Full Sync on the FIMMA to initialize the environment for the new attribute and flows.

Step 5: Enable FIMAutomation PowerShell Script

FIM provides a method for interacting with the FIM Service via PowerShell with a number of cmdlets which are part of the FIMAutomation Module. Visit the Microsoft Technet Site for more information. In this step we leverage the Export-FIMConfig and Import-FIMConfig cmdlets along with two customized functions called “GetAttribute” and “SetAttribute” which I borrowed from Amer Almotlaq in a response to a blog post question here. Here is the complete script:

######################################################################
# Title: Disable AD Users in AD using FIM Automation Cmdlets         #
# Purpose: This script utilized the FIM Automation Cmdlets to        #
# interact directly with the FIM Service and will mark               #
# the StaleAccount attribute on user accounts in FIM to              #
# "True" for users who have not logged into AD in X number           #
# of days based on the #NumberOfDays variable in the script.         #
# Author: Matt Brooks                                                #
# Version: 1.0                                                       #
######################################################################

# Establishes the number of days to be considered "stale". It is important to not that the script will query the lastLogonTimestamp attribute in AD and with default settings in AD, the 
# lastLogontimeStamp will be 9-14 days behind the current date. Therefore, the (get-date).adddays(-##) should be adjusted accordingly.
$NumberOfDays = (get-date).adddays(-75)

# Queries AD for "stale" users
$StaleUsers = Get-ADUser -SearchBase “OU=Standard Users,DC=Corp,DC=local” -filter {-not(lastlogontimestamp -like "*") -OR (lastlogontimestamp -le $NumberOfDays)} -Properties lastlogontimestamp | `
select samAccountName #,@{n="lastLogontimestamp";e={[datetime]::FromFileTime($_.lastLogonTimestamp)}} 

# Function for setting attribute of user accounts
function SetAttribute
 {
 PARAM($object, $attributeName, $attributeValue)
 END
 { 
 $importChange = New-Object Microsoft.ResourceManagement.Automation.ObjectModel.ImportChange
 $importChange.Operation = 1
 $importChange.AttributeName = $attributeName
 $importChange.AttributeValue = $attributeValue
 $importChange.FullyResolved = 1
 $importChange.Locale = "Invariant"
 if ($object.Changes -eq $null) {$object.Changes = (,$importChange)}
 else {$object.Changes += $importChange}
 }
}

# Function for getting attributes of user accounts
function GetObject
{
 PARAM($objectType,$objectid)
 END
 {
 $importObject = New-Object Microsoft.ResourceManagement.Automation.ObjectModel.ImportObject
 $importObject.ObjectType = $objectType
 $importObject.TargetObjectIdentifier = $objectid
 $importObject.SourceObjectIdentifier = $objectid
 $importObject.State = [Microsoft.ResourceManagement.Automation.ObjectModel.ImportState]::Put
 return $importObject
 }
}

# Loads FimAutomation Powershell Snapin if not already loaded
if(@(get-pssnapin | where-object {$_.Name -eq "FIMAutomation"}).count -eq 0){add-pssnapin "FIMAutomation"}

# Exports each user from FIM, updates the SlaleAccount attribute to "True" and then imports back into FIM
foreach($user in $StaleUsers)
{
$AccountName = $user.samAccountName
$filter = "/Person[AccountName = '{0}']" -f $AccountName
$FIMExport = export-FIMConfig -CustomConfig $filter –onlyBaseResources -Uri "http://localhost:5725"
$obj = GetObject -objectType "Person" -objectid ($FIMExport.ResourceManagementObject.ObjectIdentifier)
SetAttribute -object $obj -attributeName "StaleAccount" -attributeValue "True"
$obj | Import-FIMConfig -uri "http://localhost:5725"
}
write-host "Success"

 trap
 { 
 Write-Host "`nError: $($_.Exception.Message)`n" -foregroundcolor white -backgroundcolor darkred
 Exit
 }

You will want to attach this script to a scheduled task and run it as frequently as desired/required. You can run it now for testing purposes.

Step 6: Add the StaleAccount attribute to User RCDCs

I would recommend updating both the user edit and view RCDCs exposing the new StaleAccount attribute. This is a very good article which describes the process for editing RCDCs: https://blogs.msdn.microsoft.com/connector_space/2014/12/01/rcdc-session-2-adding-a-new-attribute-to-an-existing-tab/

Here is the code that I added to the RCDCs:

 <my:Control my:Name="StaleAccount" my:TypeName="UocCheckBox" my:Caption="{Binding Source=schema, Path=StaleAccount.DisplayName}" my:Description="A checked box indicates that the account has not been used to log into AD in the established time period" my:RightsLevel="{Binding Source=rights, Path=StaleAccount}">
   <my:Properties>
     <my:Property my:Name="Checked" my:Value="{Binding Source=object, Path=StaleAccount, Mode=TwoWay}"/>
   </my:Properties>
 </my:Control>

And this is how the User Edit form looks after making the changes to the RCDC:

Disable Stale (Inactive) Accounts in AD via FIM - User RCDC Update

Step 7: Synchronization

Since you have already completed a Full Import/Sync on the FIM MA, accounts will be updated in AD after each Incremental Import/Sync/Export cycle.

That completes the instructions for configuring FIM to disable inactive user accounts in AD using the FIM Automation Powershell Cmdlets. You are encouraged to ask questions or simply comment on this post. Thanks for reading!

About Matthew Brooks

Over 15 years experience in the IdAM field.

Leave a Reply

Your email address will not be published.