Active Directory

Three Active Directory Automation Scripting Tips Using PowerShell

Active Directory is one of the most common products I see being automated. After all, it’s the perfect candidate. How many times do new users have to be created, group memberships changed, or new computers added? Employees are coming and going all the time, and the actions to perform these tasks are the same—every time.

Microsoft® has an Active Directory (AD) PowerShell module that allows anyone to manage AD objects and write scripts to tie various tasks together. However, with PowerShell expertise, we can create scripts that go past just finding users and groups. We can automate any task you can think of in AD.

Find All Effective Members of a Group

AD has a great feature that allows you to add groups to other groups. This cuts down on the number of repeated group assignments you have to make, and makes AD much cleaner. However, when navigating to a group in the AD Graphical User Interface (GUI), you can only see the members in that immediate group. You may see others, but you’ll have to look at the members of those groups over and over again.

It can become a pain when you want to see all of the affected user accounts, but we can solve that using a PowerShell code and a recursive function.

To find members of a group with PowerShell, use the Get-AdGroupMember cmdlet. This command returns all members in just that group. However, a property on each of those members is an AD attribute indicating if it’s a user, a group, etc. That way, we know what kind of object it is. Knowing this, we can build code to look at each of those members, check to see if they’re a group, and if so, run Get-AdGroupMember again. If not, we return the member.

We need to use a recursive function—a function that calls itself, forcing it to find user accounts nested deep inside of various groups. By using a recursive function like this, a user can be nested ten groups deep, and we’ll still find it.

An example of how this can be done is below. This function can be called via Get-NestedGroupMember -Group MyGroup.

function Get-NestedGroupMember {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string]$Group
)

## Find all members in the group specified
$members = Get-ADGroupMember -Identity $Group
foreach ($member in $members) {
## If any member in that group is another group just call this function again
if ($member.objectClass -eq 'group') {
Get-NestedGroupMember -Group $member.Name
} else { ## otherwise, just output the non-group object (probably a user account)
$member.Name
}
}
}
Easily Find Inactive Group Policy Objects

The next tip is finding inactive Group Policy Objects (GPOs). Especially in large organizations, GPOs can get out of hand and run wild unless controlled. Sometimes there ends up being dozens of GPOs created that aren’t doing anything at all. Rather than picking these out one at a time via the GUI, we can build a simple script to find them all in one shot.

There are two ways to define an inactive GPO. This GPO could have all of its settings disabled, or it could not be linked to an organizational unit. We can create a script to find both of these types. First, we’ll pull all of the GPOs in the environment:

$allGpos = Get-Gpo -All

Once we have them all, we can then filter those GPOs by the ones that have all settings disabled:

$disabledGpos = $allGpos | Where-Object { $_.GpoStatus -eq 'AllSettingsDisabled' }
foreach ($oGpo in $disabledGpos) {
[pscustomobject]@{
Name = $oGpo.DisplayName
Status = 'Disabled'
}
}

Next, we can find all GPOs that aren’t linked to an organizational unit. This is a little trickier, but nothing we can’t handle using the code below:

## Create an empty array
$unlinkedGpos = @()
foreach ($oGpo in $allGpos) {
## Gather up all settings in the GPO
[xml]$oGpoReport = Get-GPOReport -Guid $oGpo.ID -ReportType xml;
## Only return the GPOs that don't have a LinksTo property meaning they aren't linked to an OU
if ('LinksTo' -notin $oGpoReport.GPO.PSObject.Properties.Name) {
[pscustomobject]@{
Name = $oGpo.DisplayName
Status = 'Unlinked'
}
}
}

This script will return a list of GPOs that look like this:

Name Status
---- ------
GPO1 Unlinked
GPO2 Disabled
GPO3 Disabled
Find How Long Ago a User Reset Their Password

For my last tip, let’s figure out how long ago a user’s password was set. More specifically, let’s write a small script that will allow us to find only those users that have had their password set within a configurable amount of days.

This small script uses the Get-AdUser command and filters the users returned using the Where-Object command. In this example, we’re looking at the passwordlastset attribute for each user that is greater than 30 days ago.

$daysOld = 30
$today = Get-Date
Get-AdUser -Filter { enabled -eq $true } -Properties passwordlastset | Where-Object 
{ $_.passwordlastset -gt $today.AddDays(-$daysOld) }
Summary

We’ve just skimmed the surface on what’s possible when automating with PowerShell and Active Directory. By leveraging Microsoft’s Active Directory module and stringing together commands with PowerShell, we’re able to come up with some interesting scripts.