Disable or Warn Inactive Users

SYNOPSIS:
Disable-InactiveUsers.ps1
Disable or warn inactive users that their accounts will be disabled. This script requires the AD comandlets and the ImportExcel module.

DESCRIPTION:
Disables Inactive users if the -Remediate switch is used.
Writes user accounts that would be disabled to file if the -Remediate switch is not used.
Creates a folder structure if doesn’t exist.
c:\PowerShellScripts\adUserManagement{scripts,in,out/year/month}
Exclusions CSV file must be in c:\PowerShellScripts\adUserManagement\in\
Output is written to c:\PowerShellScripts\adUserManagement\out\year\month\
Inactive user accounts are identified as accounts for which the LastLogon or the PasswordLastSet dates are 90 days or more older than the current date.
This is a bare bones script that provides an easy way to identify accounts to be excluded by SAM or OU.

OUTPUT:

The script generates an Excel workbook that is emailed to an array of email addresses.
It generates a log file in CSV format.
It generates an email to the impacted users with an HTML formatted message.
This is a warning message if the -Remediate switch is not used. If -Remediate is used it generates an email to impacted users stating their account has been disabled.
•Illustrates nested functions, use if ImportExcel and Export-Csv, switch parameter, mandatory and non-mandatory parameters.

PARAMETERS:
TimeFrame – Number of days inactive that an account must be to be disabled.
Default value is 90 days.
UpdateInformation – String value that will be appended to the end of the Description field in Active Directory for the disabled user account.
Default value is “Disabled due to inactivity” with the date appended to the end.
Remediate – Switch will disable the AD accounts and append the Description field with the UpdateInformation String.
LogFileName – String value for the name of the log file.
Default value is “LogFile.csv”
ExclusionsFile – Exclusions list in csv format. Input the path to a csv file with 1 SAMAccountName (SAM) or DistiguishedName (DN) per line if the account or all accounts under the DN should NOT be disabled. You can run this script without the Remediate parameter, then check the InactiveUsers file to see what would have been disabled. Populate your exclusion file based on data from the InactiveUsers file. NO Default value.
InactiveUsersFile – CSV file of accounts that satisfy the inactive account parameters.

EXAMPLES:
disable-InactiveUsers -ExclusionsFile exclusions.csv -TimeFrame 90 -LogFileName -Remediate

disable-InactiveUsers -ExclusionsFile exclusions.csv -LogFileName
disable-InactiveUsers -ExclusionsFile exclusions.csv -Remediate

function disable-InactiveUsers {
	[CmdletBinding()]
	param (
		[Parameter(Mandatory = $false)]
		[int]
		$TimeFrame = 90,
		[Parameter(Mandatory = $false)]
		[string]
		$UpdateInformation = 'Disabled due to inactivity',
		[Parameter(Mandatory = $false)]
		[switch]
		$Remediate,
		[Parameter(Mandatory = $false)]
		[string]
		$LogFile = 'LogFile.csv',
		[Parameter(Mandatory = $true)]
		[string]
		$ExclusionsFile,
		[Parameter(Mandatory = $false)]
		[string]
		$InactiveUsersFile = ''
	)
	Function Write-CsvLogFile {
		[CmdletBinding()]
		param (
			[Parameter(Position = 0, Mandatory = $true)]
			[string]
			$LogPath,
			[Parameter(Position = 0, Mandatory = $true)]
			[string]
			$LogData,
			[Parameter(Position = 1, Mandatory = $true)]
			[datetime]
			$timeStamp
		)
		$logOBJ = $logData | Select-Object @{ n = 'Time'; e = { $timeStamp } }, @{ n = 'Event'; e = { $logdata } }
		$logObj | Export-Csv -Path $LogPath -Append -NoTypeInformation
	}
	function sendMail($smtpServer, $Subject, $Body, $To, $From, $attachmentPath1 ) {
		Write-Host 'Sending Email'
		#Creating a Mail object
		$msg = new-object Net.Mail.MailMessage
		#Creating SMTP server object
		$smtp = new-object Net.Mail.SmtpClient($smtpServer)
		$toAddress = new-object system.net.Mail.Mailaddress $To
		$msg.To.Add($toAddress)
		Write-Host "Sending Mail to = $To"
		$msg.IsBodyHTML = $True
		$msg.Body = $($body | ForEach-Object { $_ })
		if ($attachmentPath1) {
			$attachment1 = new-object System.Net.Mail.Attachment $attachmentPath1
			$msg.Attachments.Add($attachment1)
		}
		$msg.From = $From
		$msg.ReplyTo = '[email protected]'
		$msg.subject = $Subject
		#Sending email
		$smtp.Send($msg)
	}
	$scriptName = $MyInvocation.MyCommand.Name
	$fdate = Get-Date -Format 'yyyy-MM-dd'
	$Date = Get-Date -Format 'MM/dd/yyyy'
	$env = Get-ESSEnvironment
	$HostName = ([System.Net.Dns]::GetHostByName(($env:computerName))).Hostname
	#$userName = "Chris Sharp"
	$SMTPServer = $null
	$Subject = $null
	#$InactiveUsersFile = $null
	$MailSender = '[email protected]'
	
}
	
	$rootpath = 'C:\PowerShellScripts'
	$inpath = "$rootpath\adUserManagement\in\"
	$outpath = "$rootpath\adUserManagement\out\" + $fdate.Split('-')[0] + '\' + $fdate.Split('-')[1] + '\'
	$logfile = 'logfile.csv'
	$LogFile = [string]$fdate + '-' + $logfile
	New-Item -Path $outpath -ItemType Directory -Force
	New-Item -Path $inpath -ItemType Directory -Force
	$LogPath = "$outpath$LogFile"
	$ExclusionsPath = "$inpath$ExclusionsFile"
	$InactiveUsersPath = "$outpath$InactiveUsersFile"
	$InactiveUsers = @()
	
	if (Test-Path $InactiveUsersPath) {
		Remove-Item $InactiveUsersPath -ErrorAction Ignore
	}
	 
	if (Test-Path -Path $ExclusionsPath) {
		$exclusions = Import-CSV $ExclusionsPath
		$samExclusions = $exclusions | ForEach-Object { if ($_.Type -eq 'SAM') { $_.Value } }
		$dnExclusions = $exclusions | ForEach-Object { if ($_.Type -eq 'DN') { $_.Value } }
	}
	else {
		Write-Warning 'No Exclusions file found. Exiting script.'
		Exit
	}
	$Users = Get-ADUser -Properties Mail, Name, GivenName, Surname, Enabled, LastLogonDate, PasswordExpired, PasswordLastSet, PasswordNeverExpires, SamAccountName, Description -Filter { Enabled -eq $true }
	foreach ($User in $Users) {
		#region Exclusions
		$samcnt = 0
		$SamExclusions | ForEach-Object { if ($User.SamAccountName -like $_) { $samcnt = $samcnt + 1 } }
		$notSAMExclusion = $samcnt -eq 0
		$dncnt = 0
		$dnExclusions | ForEach-Object { if ($($User.DistinguishedName) -like $_) { $dncnt = $dncnt + 1 } }
		$notDnExclusion = $dncnt -eq 0
		#endregion Exclusions		
		if ($notSamExclusion -and $notDnExclusion) {
			$lastLogonDate = $null
			$passwordLastSetDate = $null
			$userCheckDate = $null
			$lastLogonDate = $User.LastLogonDate
			$passwordLastSetDate = $User.PasswordLastSet
			if (($null -ne $lastLogonDate) -and ($null -ne $passwordLastSetDate)) {
				if ($lastLogonDate -gt $passwordLastSetDate) {
					$userCheckDate = $LastLogonDate
				}
				else {
					$userCheckDate = $passwordLastSetDate
				}
			}
			elseif ($null -eq $lastLogonDate) {
				$userCheckDate = $passwordLastSetDate
			}
			elseif ($null -eq $passwordLastSetDate) {
				$userCheckDate = $lastLogonDate
			}			
			$dateCheck = ($userCheckDate -le (Get-Date).AddDays(-$TimeFrame))
			if ($dateCheck) {
				if ($Remediate) {
					if ($null -ne $UpdateInformation) {
						$newDescription = (Get-ADUser $User.DistinguishedName -Properties Description | Select-Object Description -ExpandProperty Description)
						$newDescription += " $UpdateInformation - $Date"
						$logDate = Get-Date -Format o
						$allGood = $null
						try {
							Disable-ADAccount -Identity $User.DistinguishedName -ErrorAction Stop
							Write-CsvLogFile -LogPath $LogPath -timeStamp $logDate -LogData "$($User.Name) successfully disabled"
							$allGood = $true
						}
						catch {
							Write-CsvLogFile -LogPath $LogPath -timeStamp $logDate -LogData "Error - Failed to disable AD Account $($User.Name)"
							$allGood = $false
						}
						if ($allGood) {
							try {
								
								Set-ADUser $user.DistinguishedName -Replace @{ Description = $newDescription }
								Write-CsvLogFile -LogPath $LogPath -timeStamp $logDate -LogData "Successfully set Description field for $($User.Name) : $newDescription"
							}
							catch {
								Write-CsvLogFile -LogPath $LogPath -timeStamp $logDate -LogData "Error - Failed to set Description field for $($User.Name)"
							}
						}
					}
				}
				$InactiveUsers += $User | Select-Object Enabled, Mail, Name, GivenName, Surname, LastLogonDate, PasswordExpired, PasswordLastSet, PasswordNeverExpires, SamAccountName, DistinguishedName, Description -ExpandProperty Description
			}
		}
	}
	$smtpToArray = @()
	foreach ($usr in $InactiveUsers) {
		if ($($usr.Mail)) {}
		else {
			$email = "$($usr.GivenName)" + '.' + "$($usr.Surname)" + '@domain.com'
			$usr.mail = $email      
		}
		$smtpToArray += "$($usr.Mail)"   
	}
	$InactiveUsers | Export-Csv 'C:\powershellscripts\adUserManagement\out\csvtest.csv' -NoTypeInformation -Force
	$inactiveUsrs = Import-Csv -Path 'C:\powershellscripts\adUserManagement\out\csvtest.csv'
	Remove-Item -Path 'C:\powershellscripts\adUserManagement\out\csvtest.csv' -Force -ErrorAction Ignore
	Remove-Item -Path $InactiveUsersPath -Force -ErrorAction Ignore
	$InactiveUsrs | Export-Excel $InactiveUsersPath -WorksheetName 'InactiveUsers' -TableName 'InactiveUsers' -AutoSize -Title 'Inactive Users' -TitleBold -TitleBackgroundColor Green
	$exclusions | Export-Excel $InactiveUsersPath -WorksheetName 'Exclusions' -TableName 'Exclusions' -AutoSize -Title 'Exclusions From Inactivity' -TitleBold -TitleBackgroundColor Green -KillExcel
	#Send Report
	$Body = "<div class='portrait'><div class='Normal' style='padding-top: 3rem; padding-left: 4.5rem; padding-bottom: 3rem; padding-right: 4.5rem;'>
	<div style='word-break: break-word; overflow-wrap: anywhere; '><table class='borderless' style='width:100%;'><tbody>
	<tr><td>ESS Operations Team</td><td>ESS Inactive Users</td></tr>
	<tr><td>Controls:AC-2(3) & IA-4:This is an auto generated report from script $scriptName running on computer $Hostname.<td><tr>
	<tr><td>Users on the InactiveUsers tab have received the following email.<td><tr>
	</tbody></table>
	<br />
	<br />
	<br />
	<table class='borderless' style='width:100%;'><tbody>
	<tr><td>Your account has been identified as inactive.</td></tr>
	<tr><td>If you still require access. You may have to have your password reset.</td></tr>    
	<tr><td>Do not reply to this auto generated report.</td></tr>
	</tbody></table>"
	$attachmentPath1 = $InactiveUsersPath
	$smtpTo = @('<some email>', 'someotheremail', '<etc.>')
	#$smtpTo = @('[email protected]')

	foreach ($toAddress in $smtpTo) {
		sendMail -smtpServer $smtpServer -Subject $Subject -Body $body -To $toAddress -From $MailSender -attachmentPath1 $attachmentPath1   
	}

	#send Warning
	$warningSubject = "Your ESS AD account has been identified as inactive"
	$warningBody = "<div class='portrait'><div class='Normal' style='padding-top: 3rem; padding-left: 4.5rem; padding-bottom: 3rem; padding-right: 4.5rem;'>
<div style='word-break: break-word; overflow-wrap: anywhere; '><table class='borderless' style='width:100%;'><tbody>
<tr><td>ESS Operations Team</td><td>Inactive Users</td></tr>
</tbody></table>
<br />
<table class='borderless' style='width:100%;'><tbody>
<tr><td>Your account has been identified as inactive.</td></tr>
<tr><td>If you still require access. You may have to have your password reset.</td></tr>    
<tr><td>Do not reply to this auto generated report.</td></tr>
</tbody></table>"
	foreach ($toAddress in $smtpToArray) {
		sendMail -smtpServer $smtpServer -Subject $warningSubject -Body $warningBody -To $toAddress -From $MailSender   
	}
	if ($Remediate) {
		$userbody = "<div class='portrait'><div class='Normal' style='padding-top: 3rem; padding-left: 4.5rem; padding-bottom: 3rem; padding-right: 4.5rem;'>
<div style='word-break: break-word; overflow-wrap: anywhere; '><table class='borderless' style='width:100%;'><tbody>
<tr><td> Inactive Users - Controls:AC-2(3) & IA-4</td></tr>
</tbody></table>
<br />
<table class='borderless' style='width:100%;'><tbody>
<tr><td>Your account has been disabled due to inactivity.</td></tr>    
<tr><td>Do not reply to this auto generated report.</td></tr>
</tbody></table>"
		foreach ($toAddress in $smtpToArray) {
			sendMail -smtpServer $smtpServer -Subject $Subject -Body $userBody -To $toAddress -From $MailSender   
		}
	}
}