Forcing ATCTS Compliance via Automation

Rich
6 min readDec 16, 2021

TL;DR How to easily disable or expire noncompliant users in bulk IOT force ATCTS compliance.

Background

Higher has dictated that your organization’s ATCTS compliance needs to be 95% instead of 90%. As we all know users will spend more time arguing about why they didn’t do their annual cyber awareness training than taking the 15–20 minutes to actually do it. The annual AUP takes 30 seconds, but compliance with that tends to run even lower.

This presupposes that you have been delegated rights to your organization’s user OU in AD and that your org’s leadership has directed this course of action. That being given, this focuses on how to automate the task.

ATCTS

Everyone already generates reports showing who has not done their cyber awareness training and/or AUP within the last year. The trick is to modify the report and add the DoD ID numbers of the users. ATCTS calls it the EDIPI.

Export the resulting report to *.xlsx as normal. Next copy/paste just the column of DoD ID #s, create a new spreadsheet with just the #s in one column, and save it as a *.csv. Name it something that makes sense to you, I used ‘IABadBoys.csv’.

Admin accounts, aka Privileged Users

Best practice dictates that administrators have two accounts; one as a normal Domain User and a Privileged User account that has been delegated rights to their respective org’s user and/or workstation OUs. Naturally the Privileged User account must be used to modify user’s accounts. Save the *.csv file IABadBoys.csv somewhere that your Privileged User account can access. I used ‘C:\Users\Public\Documents’. Run PowerShell_ISE as your Privileged User, do a ‘cd C:\Users\Public\Documents’, copy/paste the script, then run it.

Side note on the AD attribute EmployeeID

For simplicities sake we will assume your organization uses the following:

Initially it is tempting to find users by their EmployeeID attribute in AD. However I quickly realized that this was not workable in practice. The people that create our user’s accounts are rather, how shall do I put this, “mistake prone”. The EmployeeID is just an AD attribute and does not affect the user’s ability to login. Hence the user will not complain if it is fat fingered. The UserPrincipalName (UPN) however will affect their ability to login. As a result it is a much more accurate method to compare ATCTS to AD.

Matching users in ATCTS to AD

So we have an EDIPI in ATCTS and a PIV in AD. How do we compare them? After some Microsoft training, asking CW6 Google, and a fair amount of trial and error I settled on the following:

Get-ADUser -Filter (‘UserPrincipalName -Like “‘ + $user + ‘*”’)

‘$user’ is of course a PowerShell variable which will be populated with the DoD ID #s of our noncompliant users. This can be accomplished with a ForEach loop.

Notifying the users

Of course the noncompliant users are notified via email first and warned that their account will be disabled if they remain noncompliant. The easy way to do this is to pair a form email with a ForEach loop:

#Get the list
$Users = Get-Content .\IABadBoys.csv
#Process the list
ForEach ($user in $users)
{
#Get the user’s info from AD
#Example: (‘GivenName -like “‘ + $name + ‘*”’)
$info = Get-ADUser -Filter (‘UserPrincipalName -Like “‘ + $user + ‘*”’) -Properties * | Select-Object EmailAddress
“‘($info)’” >> Email.csv
}

This method places a ‘()’ instead of an email address if the user exists in our org’s ATCTS but not in our OU in AD. This problem is far more common than it should be due to users failing to in and out-process. Simply do a ‘Ctrl + H’ in Excel, replace the ‘( and the )’ with nothing, then copy/paste the entire column of email addresses into Outlook and send the warning. We can also inactivate those ‘()’ users in ATCTS after waiting a week or two to confirm. This will take them off our hitlist and make our ATCTS compliance #s a few digits better.

Run the thing

To reiterate:

  • Save the *.csv in ‘C:\Users\Public\Documents’
  • Run PowerShell_ISE as your Privileged User
  • ‘cd C:\Users\Public\Documents’
  • Copy/paste the script & run it

There are two versions. It is up to the leadership and your org’s policy which one is used. One disables the users and the other sets their account expiration to the current DTG. Either way the user will be unable to login afterwards.

Expire noncompliant users

#Disable IA Bad Boys given a CSV containing their DoD ID #s
#Run this with care, recommend test driving it on a short list of non-VIPs initially
#Get the list
$Users = Get-Content .\IABadBoys.csv
#Process the list
ForEach ($user in $users)
{
$BadBoy = (Get-ADUser -Filter (‘UserPrincipalName -Like “‘ + $user + ‘*”’) -Properties *).SamAccountName
$ADM = $env:USERNAME
$date = date
Set-ADAccountExpiration -DateTime $date -Identity $BadBoy -Confirm
Set-ADUser -Identity $BadBoy -Description “Expired for IA noncompliance on $date by $ADM”
}

Disable noncompliant users

#Disable IA Bad Boys given a CSV containing their DoD ID #s
#Run this with care, recommend test driving it on a short list of non-VIPs initially
#Get the list
$Users = Get-Content .\IABadBoys.csv
#Process the list
ForEach ($user in $users)
{
$BadBoy = (Get-ADUser -Filter (‘UserPrincipalName -Like “‘ + $user + ‘*”’) -Properties *).SamAccountName
Disable-ADAccount -Identity $BadBoy -Confirm
$ADM = $env:USERNAME
$date = date
Set-ADUser -Identity $BadBoy -Description “Expired for IA noncompliance on $date by $ADM”
}

Notes

The script captures the SamAccountName of the Privileged User who ran it and the current DTG. It then puts these in the user’s account description in AD along with why their account was set to expired or disabled. This way when the user complains to their local service desk that they cannot login it will be obvious to the IT personnel why this is. They can then be directed to where to knock out the requirements and have their account re-enabled once they are compliant.

The script will ask for confirmation on each user as it goes through the CSV. If you are feeling confident in your list you can simply hit ‘Yes to All’. Hitting Yes to confirm each name is still faster than manually searching for each noncompliant user in a GUI tool like Active Directory Users & Computers (ADUC) or Active Directory Administrative Center (ADAC), disabling them, and putting a reason in the account description.

It is also less mistake prone since you will invariably end up with multiple John Smiths, someone will have legally changed their name, someone will have gotten married and changed their name, etc.

Summary

If you read this far then I hope you found this useful. I have used ForEach loops and querying AD to automate a few IA tasks. Finding users based on their DoD ID # took me a bit of trial and error, so maybe this can save someone some time. If you have any questions just shoot me a message on FB or my work email.

-Rich

References:

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_foreach?view=powershell-7.2

https://docs.microsoft.com/en-us/powershell/module/activedirectory/get-aduser?view=windowsserver2022-ps

https://docs.microsoft.com/en-us/powershell/module/activedirectory/set-adaccountexpiration?view=windowsserver2022-ps

https://docs.microsoft.com/en-us/powershell/module/activedirectory/disable-adaccount?view=windowsserver2022-ps

--

--

Rich

I work various IT jobs & like Windows domain security as a hobby. Most of what’s here is my notes from auditing or the lab.