Set-ADAccountStatusByOu.ps1

<#PSScriptInfo
 
.VERSION 1.0
 
.GUID 6676ad7a-f1d3-4257-a585-936e79b46068
 
.AUTHOR Chris Carter
 
.COMPANYNAME
 
.COPYRIGHT (c)2018 Chris Carter
 
.TAGS ActiveDirectory Accounts Disable Enable OU
 
.LICENSEURI http://creativecommons.org/licenses/by-sa/4.0/
 
.PROJECTURI https://gallery.technet.microsoft.com/scriptcenter/Set-Active-Directory-48215ce4
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES ActiveDirectory
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES Initial Release
 
 
#>


<#
.SYNOPSIS
Sets the status of accounts (enabled or disabled) by OU
.DESCRIPTION
Set-ADAccountStatusByOu sets the status of accounts (enabled or disabled) by an entire Organizational Unit. You may specify the OU by name or distinguished name. Enabling or disabling is handled by the Enable or Disable switch parameters, with Disable being the default. The SearchScope parameter is for controlling whether child ojbects of the OU are also affected.
 
In the event that there are multiple OUs in the domain named the same, a menu is given showing all the distinguished names found, and the option to use all or a specific OU to set user statuses.
 
This script is best used to run as a Scheduled Task to automatically disable users that are put into specifice OUs, like one for ex-employees. If used in this way, specify the Force parameter. This will stop any user input being requested and default to a choice of All.
.PARAMETER OrganizationalUnit
The Organizational Unit that contains the users you want to enable or disable.
 
The alias for this parameter is Ou.
.PARAMETER SearchScope
Specifies the scope of an Active Directory search. The acceptable values for this parameter are:
 
Base
OneLevel
Subtree
 
A Base query searches only the current path or object. A OneLevel query searches the immediate children of that path or object. A Subtree query searches the current path or object and all children of that path or object.
 
The default is Subtree.
.PARAMETER Disable
The accounts in the specified OU will be disabled if this parameter is used.
.PARAMETER Enable
The accounts in the specified OU will be enabled if this parameter is used.
.PARAMETER Force
This will force a choice of All without user input if there are any OUs named the same.
.INPUTS
System.String
 
 
You can pipe Organizational Unit names and distinguished names as strings to Set-ADAccountStatusByOu.
 
.OUTPUTS
None
 
 
Set-ADAccountStatusByOu does not generate any output.
 
.EXAMPLE
PS C:\> Set-ADAccountStatusByOu -Ou Ex-employees
 
This command will disable all of the accounts in the Ex-employees OU and its children.
.EXAMPLE
PS C:\> Set-ADAccountStatusByOu -Ou "Current Employees" -Enable
 
This command will enable all of the accounts in the "Current Employees" OU and its children.
.EXAMPLE
PS C:\> Set-ADAccountStatusByOu -Ou Ex-Employees -SearchScope OneLevel
 
This command will disable all of the accounts in the Ex-employees OU, but not in any of its children.
.NOTES
This command uses the ActiveDirectory PowerShell Module. This module is automatically installed on domain controllers and workstations or member servers that have installed the Remote Server Administration Tools (RSAT). If you are not on a machine that meets this criteria, the command will fail to work.
.LINK
Get-ADUser
.LINK
Get-ADOrganizationalUnit
.LINK
Enable-ADAccount
.LINK
Disable-ADAccount
#>


#Requires -Version 3.0
[CmdletBinding(DefaultParameterSetName="Disable",SupportsShouldProcess=$true,HelpURI="https://gallery.technet.microsoft.com/scriptcenter/Set-Active-Directory-48215ce4?redir=0")]

Param(
    [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [Alias("Ou")]
        [String[]]$OrganizationalUnit,

    [ValidateSet("Base","OneLevel","Subtree")]
        [String]$SearchScope="Subtree",

    [Parameter(ParameterSetName="Disable")]
        [Switch]$Disable,

    [Parameter(ParameterSetName="Enable")]
        [Switch]$Enable,

    [Switch]$Force
)

Begin {
    #Function to get DN of OU
    Function Get-Dn($OU) {
        #If OU matches the DN format, return original
        if ($OU -imatch '(?:(?:(?:OU|CN)=.+?)(?<!\\),)+?(?:(?:DC=.+?)(?<!\\),)?DC=.+$') {
            Write-Verbose "Distinguished Name entered"
            $OUDN = $OU
        }
        else {
            #Search for input OU and store distinguished name property
            Write-Verbose "Resolving Distinguished Names"
            $OUDN = (Get-ADOrganizationalUnit -Filter "Name -eq '$OU'" -ea SilentlyContinue).DistinguishedName
        }
        $OUDN
    }

    #Function to give the user a choice when multiple OUs with the same name are found
    Function Select-Dn ($OUs) {
        #Create collection to hold the choices
        $choices = New-Object 'System.Collections.ObjectModel.Collection[System.Management.Automation.Host.ChoiceDescription]'
        #Menu title
        $Title = "Continue?"
        #Menu message with the All choice added since it is always an option
        $Message = "Choose from the options below to choose which OU to use to continue the $($PSCmdlet.ParameterSetName) operation:`nAll`: All OUs listed"
        
        #Create All choice and add to choice collection (All is 0 in the result)
        $All = New-Object System.Management.Automation.Host.ChoiceDescription -Args "&All", "$($PSCmdlet.ParameterSetName) the users in all OUs listed."
        $choices.Add($All)

        #Go through the DNs (for loop used because we need a number to choose)
        for ($i=0; $i -lt $OUs.Count; $i++) {
            #Add 1 to index because All is the 0 choice
            $j = $i + 1
            #Add incremented number and current index to the message
            $Message += "`n$j`: $($OUs[$i])"
            #Create and add the DN as the incremented entry in the choice collection
            $choices.Add((
                New-Object System.Management.Automation.Host.ChoiceDescription -Args "&$j", "$($OUs[$i])"
            ))
        }
        #Create and add the None choice to the choice collection
        $None = New-Object System.Management.Automation.Host.ChoiceDescription -args "&None", "Do not $($PSCmdlet.ParameterSetName) the users in any of the OUs listed."
        $choices.Add($None)
        #Add the none option to the message
        $Message += "`nNone`: No OU listed"

        #This generates out menu, and prompts the user
        $Host.UI.PromptForChoice($Title, $Message, $choices, 0)
    }

    #Function to select the DN(s) based on user choice
    Function Get-Choice ($Result, $OUs) {
        switch ($Result) {
            #All chosen, return all OUs back
            0                                 { $OUs }
            #Numbered item chosen, return only selected DN back (the index of the chosen DN is offset because the All choice is 0
            {$_ -gt 0 -and $_ -le $OUs.Count} { $OUs[($_ - 1)] }
            #None chosen, so exit (index is offset because of All choice is 0
            {$_ -eq ($OUs.Count + 1)}         { exit }
        }
    }

    Function Disable-User ($User) {
        #If the user is enabled then disable, otherwise do nothing
        if ($User.Enabled) {
            Write-Verbose "Disabling $User"
            if ($PSCmdlet.ShouldProcess($User, "Disable")) {
                $User | Disable-ADAccount -Confirm:$false
            }
        }
        else { Write-Verbose "$User is already disabled...skipping user" }
    }

    Function Enable-User ($User) {
        #If the user is disabled then enable, otherwise do nothing
        if (-not $User.Enabled) {
            Write-Verbose "Enabling $User"
            if ($PSCmdlet.ShouldProcess($User, "Enable")) {
                $User | Enable-ADAccount -Confirm:$false
            }
        }
        else { Write-Verbose "$User is already enabled...skipping user" }
    }

    #Function get all the users necessary and which action to perform
    Function Set-AllAccounts ($OuDn, $Activity) {
        Write-Verbose "Getting users in $OuDn"
        #Go through all the users found in the specified OU
        foreach ($user in (Get-ADUser -Filter * -SearchBase $OuDn -SearchScope $SearchScope)) {
            #Determine which function to call based on the specified activity
            switch ($Activity) {
                "Disable" { Disable-User -User $user }
                "Enable"  { Enable-User -User $user }
            }
        }
    }
}

Process {
    foreach ($Ou in $OrganizationalUnit) {
        #Test for and get the DN of the OU
        $OuDn = Get-Dn -OU $Ou

        #If no OUs found, write error and exit
        if (-not $OuDn) { Write-Error "No OU found with the name `"$Ou`""; exit }

        #There could be more than one OU with the same name, so warn about multiple entries,
        #and show distinguished names of entries. Give choice for each
        if ($OuDn.Count -gt 1 -and (-not $Force)) {
            Write-Warning "There are multiple OUs named $OU"
            #Generate menu and prompt user
            $result = Select-Dn -OUs $OuDn
            #Get the DN(s) based on user's choice
            $OuDn = Get-Choice -Result $result -OUs $OuDn
        }

        #Go through each DN (the user could choose All)
        foreach ($o in $OuDn) {
            #Perform the desired action on the OU in question based on the parameter set name
            Set-AllAccounts -OuDn $o -Activity $PSCmdlet.ParameterSetName
        }
    }
}