New-AADConnectInboundRuleDisableExpiredAccounts.ps1

<#PSScriptInfo
 
.VERSION 2.6
 
.GUID 0e878ef7-98d6-4159-9b8b-e6a0870f0c81
 
.DESCRIPTION Create a new AADConnect inbound rule to disable cloud accounts for expired on-premises accounts.
 
.AUTHOR Aaron Guilmette
 
.COMPANYNAME Planet Technologies
 
.COPYRIGHT 2023
 
.TAGS Azure AD Connect AADConnect disable expired account
 
.LICENSEURI
 
.PROJECTURI https://www.undocumented-features.com
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
THIS CODE AND ANY ASSOCIATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK OF USE, INABILITY TO USE, OR RESULTS FROM THE USE OF
THIS CODE REMAINS WITH THE USER.
 
Author: Aaron Guilmette
        aguilmette@go-planet.com
#>


<#
.SYNOPSIS
Create new AAD Connect inbound rules to disable expired accounts
 
.PARAMETER CreateTask
Create a scheduled task that runs a full synchronization on all AD connectors every
other week.
 
.PARAMETER Domain
Specify one or more domains to create the schedule for.
 
.EXAMPLE
.\New-AADConnectInboundRuleDisableExpiredAccounts.ps1
 
Create a new AAD Connect inbound rule for all AD connectors to disable expired accounts
using the first available low precedence value.
 
.EXAMPLE
.\New-AADConnectInboundRuleDisableExpiredAccounts.ps1 -CreateTask -Domain contoso.com
 
Create a new AAD Connect inbound rule for the AD connector matching contoso.com and
establish a scheduled task to execute a full synhronization job every other week.
 
.LINK
https://aka.ms/aarongallery
 
#>

param (
    [array]$Domain,
    [switch]$CreateTask
    )

# Collect all on-premises AD Connectors
## If $Domain is specified, select the matching connectors
If ($Domain)
{
    $DomainQuery = "^$($Domain -join "|")`$"
    [array]$ADConnectors = Get-ADSyncConnector | ? { $_.Subtype -notlike "*Windows Azure Active Directory*" -and $DomainQuery -match $_.Name }
}
else
{
    [array]$ADConnectors = Get-ADSyncConnector | ? { $_.Subtype -notlike "*Windows Azure Active Directory*" }
}

# Create the $NewConnectors variable to contain list of newly created connectors
[array]$NewConnectors = @()

# Create an inbound rule with the lowest precedence for each connector
If ($ADConnectors.Count -ge 1)
{
    foreach ($Connector in $ADConnectors)
    {
        [string]$Identifier = [Guid]::NewGuid().ToString()
        [array]$AllRulesPrecedence = (Get-ADSyncRule).Precedence
        $Precedence = (($AllRulesPrecedence | Measure-Object -Minimum).Minimum - 1)
        $RuleName = "In from AD - Disable Expired Accounts - $($Connector.Name)"
        
        New-ADSyncRule  `
            -Name $RuleName `
            -Identifier $Identifier `
            -Description 'Inbound rule to disable expired accounts' `
            -Direction 'Inbound' `
            -Precedence $Precedence `
            -PrecedenceAfter '00000000-0000-0000-0000-000000000000' `
            -PrecedenceBefore '00000000-0000-0000-0000-000000000000' `
            -SourceObjectType 'user' `
            -TargetObjectType 'person' `
            -Connector $Connector.Identifier.ToString() `
            -LinkType 'Join' `
            -SoftDeleteExpiryInterval 0 `
            -ImmutableTag 'New-AADConnectInboundRuleDisableExpiredAccounts.1' `
            -OutVariable syncRule | Out-Null
        
        # Transformation based on accountExpires
        # If AD accountExpires value is 0 or 9223372036854775807, the account is already configured to never expire
        # so flow accountEnabled "True." Otherwise, calculate the value from the accountExpires date and compare it
        # to the Now() date; if accountExpires compared to Now() is in the future, flow accountEnabled "True." If
        # accountExpires compared to Now() is in the past, flow accountEnabled "False."
        Add-ADSyncAttributeFlowMapping  `
            -SynchronizationRule $syncRule[0] `
            -Destination 'accountEnabled' `
            -FlowType 'Expression' `
            -ValueMergeType 'Update' `
            -Expression 'IIF(CStr([accountExpires])="0",True,(IIF(CStr([accountExpires])="9223372036854775807",True,IIF(DateFromNum([accountExpires])>(CDate(NumFromDate(Now()))),True,False))))' `
            -OutVariable syncRule | Out-Null
        
        # Create the scoping rule conditions
        New-Object  `
            -TypeName 'Microsoft.IdentityManagement.PowerShell.ObjectModel.ScopeCondition' `
            -ArgumentList 'userAccountControl', '2', 'ISBITNOTSET' `
            -OutVariable condition0 | Out-Null
        
        # Add the scoping rule conditions to the rule object
        Add-ADSyncScopeConditionGroup  `
            -SynchronizationRule $syncRule[0] `
            -ScopeConditions @($condition0[0]) `
            -OutVariable syncRule | Out-Null
        
        # Create the rule
        Add-ADSyncRule -SynchronizationRule $syncRule[0] | Out-Null
        
        # Get-ADSyncRule -Identifier $Identifier
        $NewConnectors += "$($RuleName), $($Identifier)"
    }
    Write-Output "New rules created:"
    $NewConnectors
    
    # Create bi-weekly scheduled task
    If ($Create)
    {
        If (!(Get-ScheduledJob "AAD Connect Full Sync" -ea SilentlyContinue) )
        {
            $Trigger = New-JobTrigger -Weekly -At "11:00 PM" -DaysOfWeek Saturday -WeeksInterval 2
            Register-ScheduledJob -Name "AAD Connect Full Sync" -ScriptBlock { Get-ADSyncConnector | ? { $_.Subtype -notlike "*Windows Azure Active Directory*" } | % { Invoke-ADSyncRunProfile -ConnectorName $_.Name -RunProfileName 'Full Synchronization' } } -Trigger $Trigger | Out-Null
        }
    }
}
Else
{ Write-Output "No connectors matching $($Domain) found." }