D Set group scope
141Active Directory users
will expire in the next 10 days, we’re interested in those set 32 days ago, and so forth. As I’m using a test domain, I had to force some of this, so my example shows a date of 42 days in the past—in other words, all password changes
C
. You’ll need to set this value depending on your password policy and how far ahead you want look.We get the current domain root
D
and create a directory searcherE
, as we’ve seen previously. The filterF
is interesting in that we need the objectcategory and objectclass to restrict the search to users. Leave off the objectcategory and you’ll get computer accounts as well.COMPUTER PASSWORDS Computer passwords set themselves—don’t try to change them manually.
We check the pwdlastset attribute for accounts that fall between our chosen dates using FindAll() and display the results
G
. We’re using a DirectorySearcher object so you don’t have access to the full property list. We can use the distinguished name to access a DirectoryEntry object and list full names, and so on. We could even send the user an email (PowerShell v2 has a Send-MailMessage cmdlet or we can script it). DISCUSSIONA similar result can be achieved using the cmdlets:
$now = (Get-Date).ToFileTime()
$end = ((Get-Date).AddDays(-42)).ToFileTime() $filt = "(&(objectcategory=Person)" +
"(objectclass=user)(pwdlastset>=$end)" + "(pwdlastset<=$now))"
Get-ADUser -LDAPFilter $filt $now = (Get-Date).ToFileTime()
$end = ((Get-Date).Adddays(-42)).ToFileTime() $filt = "(&(objectcategory=Person)" +
"(objectclass=user)(pwdlastset>=$end)" + "(pwdlastset<=$now))"
Get-QADUser -ldapFilter $filt
We set the start and end dates of our search and use the same LDAP filter as earlier. We get the same result, but with less code.
Temporary workers are often given accounts with an expiration date. Searching for these is similar to searching for expiring passwords.
TECHNIQUE 12 Account expiration
This is another search scenario, except this time we’ll be using the accountexpires attribute. One big plus of creating search scripts in this way is that the only real change is the LDAP filter. The body of the script remains the same.
PROBLEM
SOLUTION
Modifying our LDAP filter to use the accountexpires attribute enables us to find accounts that will expire within a certain number of days, as shown in listing 5.21. This is a variation on the password expiration script we saw previously. Set the start and end dates of our search
B
. In this case, we’re interested in accounts that will expire in the next 60 days. Get the current domain root and create a searcherC
. The search filter is simpler in that we’re looking at the user object class and we want to find accounts where the accountexpires attribute falls between our two given datesD
. We use FindAll() because we expect multiple results and we display the resultsE
as previously.$now = (Get-Date).ToFileTime() $end = ((Get-Date).Adddays(60)).ToFileTime() $dom = [System.DirectoryServices.ActiveDirectory.Domain] ::GetCurrentDomain() $root = $dom.GetDirectoryEntry() $search = [System.DirectoryServices.DirectorySearcher]$root $filt = "(&(objectclass=user)" + "(accountexpires<=$end)" + "(accountexpires>=$now))" $search.Filter = $filt foreach ($result in $results){
$result.properties.distinguishedname }
DISCUSSION
Using the cmdlets is easy. All we need to do is define the end date of our search. Using the Microsoft cmdlet, we have this syntax:
Search-ADAccount -AccountExpiring ` -TimeSpan 60.00:00:00 -UsersOnly | Format-Table Name, Distinguishedname
The Quest cmdlet has a simpler syntax:
Get-QADUser -AccountExpiresBefore $((Get-Date).AddDays(60))
With the Microsoft cmdlets, we use a TimeSpan to look 60 days ahead. We use the - UsersOnly parameter to only give us user accounts. The Quest cmdlet only has to be given the date that’s 60 days ahead.
This completes our look at user accounts in Active Directory. You’ve seen a lot of material in this section that should cover most of your needs for automating the administration of user accounts. The scripts are easily modifiable, especially the search and modification scripts. They can all easily be adapted to accept parameters or to read from a file using the examples already given. I’m going to round off the chapter with a look at Active Directory groups.
Listing 5.21 Account expiration check
Set dates
B
Create searcherC
Search filterD
Display resultsE
143 Active Directory groups
5.4
Active Directory groups
Active Directory groups are manipulated in a similar manner to the local groups we’ve already seen. We have the alternative of using cmdlets in this case. We’ll look at creat- ing and modifying groups, and finish the section by discovering how to display nested group memberships from the perspective of a group and a user-something you defi- nitely can’t do in the GUI.
TECHNIQUE 13 Group creation
Group creation is similar to creating local groups. PROBLEM
We need to create an Active Directory group. SOLUTION
The group can be created using ADSI in a similar manner to creating a user in Active Directory, as shown in listing 5.22. There are a number of group types available in Active Directory. We start by creating constants that define the available types and scopes of groups
B
(in listing 5.22). We bind to the OU where we’ll create the groupC
. The group type and scope are combined at the bit level using a binary or operationD
. I deliberately made this a universal group so that it’s obvious that this works. The default group is a global security group. The group is createdE
and immediately saved.$global = 0x00000002
$domainlocal = 0x00000004
$security = 0x80000000
$universal = 0x00000008
$ou = [ADSI]"LDAP://ou=All Groups,dc=manticore,dc=org" $grouptype = $security -bor $universal
$newgroup = $ou.Create("Group", "cn=UKPMs") $newgroup.SetInfo()
$newgroup.GroupType = $grouptype $newgroup.samAccountname = "UKPMs" $newgroup.SetInfo()
Processing is completed by setting the group type
F
and a samaccountnameG
. We need samaccountname or a random one is generated. A final SetInfo() writes every- thing back to the database.DISCUSSION
If we use the cmdlets, we need to supply the information shown. The code matches the script, but each cmdlet is only one line of code. We start with the Microsoft cmd- let, New-ADGroup, and then look at the Quest cmdlet. New-QADGroup:
New-ADGroup -Name "English Scientists" -SamAccountName EngSci ` -GroupCategory Security -GroupScope Global `
-DisplayName "English Scientists" ` -Path "OU=England,dc=manticore,dc=org" `
Listing 5.22 Creating Active Directory group
Set constants
B
C
D
Set group typeE
F
Set samAccountname
G
-Description "Members of this group are English Scientists" New-QADGroup -Name "USPres" -SamAccountName "USPres" ` -GroupType "Security" -GroupScope "Universal" `
-ParentContainer "ou=All Groups,dc=manticore,dc=org"
After creating our group, we need to populate it with members.
TECHNIQUE 14 Changing membership
Managing group membership will be a mixture of manual and automated proce- dures. I hate to say it, but not everything can be automated. If you can use the cmd- lets, they’re ideal for adding single users to a group. If you’re creating a group with a number of users that can be identified to an LDAP search, then use the following script as a guide. It could just as easily be searching on a department or location. If the users are scattered across your Active Directory, then collect their names into a CSV file and modify the script to read the file and add the users to a group.
Group membership can also be set as the user account is created. PROBLEM
All of the users in an OU need to be put into a group. SOLUTION
An LDAP search filter is used to find all of the user accounts in a given OU, and we can use that information to add the users to the group, as in listing 5.23. We start by creat- ing a directory entry
B
(in listing 5.23) for the group. A directorysearcherC
is cre- ated to find all of the users in the OU. Note that we set the root of the search to the OU. There’s no need to search the whole directory when we know the users are in a single OU.$group = [ADSI]"LDAP://cn=UKPMs,ou=All Groups,dc=manticore,dc=org" $root = [ADSI]"LDAP://ou=England,dc=manticore,dc=org"
$search = [System.DirectoryServices.DirectorySearcher]$root $search.Filter = "(&(objectclass=user)(objectcategory=user))" $result = $search.FindAll() foreach ($user in $result)
{
$group.Add("LDAP://" + $user.properties.distinguishedname) $group.SetInfo() $message = $user.properties.distinguishedname +
" added to group " + $group.cn Write-Host $message }
We loop through our results
D
and use the Add() method of the group to addE
the user into the group. We’re constructing the AD path for the user, which is the input parameter the method expects. $user.properties.distinguishedname is used to access the distinguished name property because we’re dealing with a directoryse- archer resultset rather than a user object.Listing 5.23 Changing Active Directory group membership
Group
B
Search for usersC
Loop through results
D
Add userE
F
Save MessageG
145