When Windows PowerShell first shipped, one of the most commonly asked questions was, "Can I manage Active Directory (AD) using PowerShell?" At the time, Microsoft's answer wasn't what most administrators wanted to hear. PowerShell had a built-in Active Directory Service Interfaces (ADSI) "type accelerator" that let you access AD objects, but you were pretty much on your own figuring out how to make it work to perform AD administrative tasks. Shortly thereafter, Quest Software offered a free set of cmdlets for performing AD administration tasks, such as creating, modifying, and deleting AD objects and searching for objects in AD. For a long time, this was the state of PowerShell and AD management.

When Microsoft shipped Windows Server 2008 R2, everything changed because it introduced the Active Directory Module for Windows PowerShell. The AD module includes a set of cmdlets for managing AD as well as an AD Provider that lets you navigate AD as if it were a drive letter. I'll describe how to install the AD module and how it works in detail.

Installing the Active Directory Module

Unlike previous tools that use LDAP to communicate with AD, the AD module uses the Active Directory Web Services (ADWS) protocols to communicate with an AD domain controller (DC). The MSDN blog posting "Active Directory Web Services Overview" describes these communication protocols in detail, but suffice it to say that both the PowerShell cmdlets in the AD module and the Active Directory Administrative Center (ADAC) use ADWS to communicate with and get information from AD.

When you install Windows Server 2012 or Server 2008 R2 DCs in your AD domain, ADWS will be installed and running by default on each of them. If you have a domain composed entirely of Windows Server 2008 or Windows Server 2003 DCs, you need to do a separate ADWS install. Microsoft provides the free Active Directory Management Gateway Service package for this purpose. If you install this package on at least one Server 2008 or Server 2003 AD DC in your domain, you can use the AD module for PowerShell as well as ADAC.

The AD module itself is installed by default on any DC running Server 2012 or Server 2008 R2. If you're running a Windows 8 or Windows 7 box (or any non-DC running Server 2012 or Server 2008 R2), you need to install the Remote Server Administration Tools from the Microsoft Download Center.

No matter whether the Remote Server Administration Tools were already on your system or you installed them separately, the next step is to open the Control Panel Add/Remove Programs applet and select Turn Windows features on or off from the menu on the left. In the Windows Feature dialog box that appears, scroll down to the Remote Server Administration Tools section. Look for the Active Directory Module for Windows PowerShell check box, which will be in the \Remote Server Administration Tools\Role Administration Tools\AD DS and AD LDS Tools folder, as shown in Figure 1. Select that check box and click OK to install the module.

Figure 1: Installing the AD Module for PowerShell

Afterward, you should see a shortcut labeled Active Directory Module for Windows PowerShell under Administrative Tools on the Start menu. Clicking that shortcut will launch PowerShell with the AD module loaded. If you're already working in PowerShell and simply want to load the module so it's available for use, you can type the following command to get access to the AD cmdlets and the AD Provider:

Import-Module ActiveDirectory

Now let's look at how you can navigate AD using the AD Provider.

Using the Active Directory Provider

PowerShell incorporates the concept of PowerShell drives, which I like to simply refer to as PS drives. In simple terms, a PS drive is a way of representing a resource like a navigable file system that's composed of folders and leaf items. Not every resource can be represented this way, but many—including AD and the registry—fit well into that model. The AD module contains the provider for an AD PS drive. What this means is that you can navigate and even modify AD as if it were a file system.

So, how do you navigate AD using the AD Provider? Assuming that you already have PowerShell open and the AD module loaded, the first step is to run the Set-Location cmdlet, which has several aliases, including sl and cd:

Set-Location AD:

This command changes the current working location to the AD PS drive. As a result, the PowerShell prompt will show AD:\ instead of C:\. Next, to see the items in the AD PS drive, you can use the Get-ChildItem cmdlet, which has an alias of dir:

Get-ChildItem

Figure 2 shows sample results from my machine.

Figure 2: Listing the Domain Partitions Available in the AD PS Drive

As you can see, this command returned a list of all the available domain partitions. The most interesting one for me is the domain partition named cpandl, which contains users and computers. To change to that domain, I simply type:

Set-Location "dc=cpandl,dc=com"

Note that I'm using the Set-Location cmdlet with the distinguished name (DN) of my AD domain. That's required to properly navigate into it. Once I'm in the domain directory (as indicated by AD:\dc=cpandl,dc=com in the PowerShell prompt), I can use the Get-ChildItem cmdlet to see my top-level AD structure, which Figure 3 shows.

Figure 3: Viewing the Top-Level AD Hierarchy

Suppose I want to look at the users in the SDM organizational unit (OU). To get into that OU, I simply type:

Set-Location "OU=SDM"

The PowerShell prompt will now show AD:\ou=SDM,dc=cpandl,dc=com. At this point, I can use the Get-ChildItem cmdlet to see all the user objects in that OU. Let's say I want to change the Description property on the user object representing my user account Darren Mar-Elia. There's a cmdlet for that! The Set-ItemProperty cmdlet lets you change a property in an AD object. If I want to change my user account's description to Chief Techie, I'd run the command:

Set-ItemProperty -Path '.\CN=Darren Mar-Elia' `
  -Name "Description" -Value "Chief Techie"

As you can see from this command, I'm using the cmdlet's -Path parameter to point to my user account in the current directory. I'm also using the -Name parameter to indicate that I want to modify the Description property and the -Value parameter to indicate that I want the description to be Chief Techie.

Note that if you want to find all objects that have a particular property value, you can use the Get-ItemProperty cmdlet. If you just want to get a reference to an AD object, the Get-Item cmdlet will do the trick.

As you can see, it's pretty straightforward to work with AD this way. Although it might not be a mechanism you'd use for doing mass changes, it's handy to be able to deal with AD as if it were a file system. With that said, I find that most administrators use the AD cmdlets rather than the AD PS drive to manage AD. So, let's see how some of these cmdlets work.

Using the Active Directory Cmdlets

The AD module that comes with Windows 7 contains 76 cmdlets for managing AD. You can use them for doing pretty much everything, including searching AD objects, creating and deleting AD objects, and manipulating AD configuration information (e.g., forest mode, fine-grained password policy). The cmdlets are generally grouped by their verbs, such as Add-, Remove-, Get-, and Set-. Note that not every Get- cmdlet includes a corresponding Set- cmdlet and vice versa, so you might have to do some digging to find the cmdlet that's right for a task. For example, you can set the AD forest functionality level by using the Set-ADForestModecmdlet, but if you want to find out the current forest functionality level of a forest, you need to use the Get-ADForest cmdlet and view the ForestMode property on the returned object.

Now let's take a look at some common tasks that you can perform using the AD cmdlets. Specifically, I'll show you how to add user accounts, manage group membership, reset user account passwords, and search for AD objects.

Adding User Accounts

The New-ADUser cmdlet provides an easy way to add user accounts to AD. Suppose I want to add a new user account named Bill Smith to my SDM OU. In the most basic form, I can create a new user using the command:

New-ADUser -Name "Bill Smith" -SamAccountName "bsmith" `
  -GivenName "Bill" -Surname "Smith" `
  -DisplayName "Bill Smith" -Path "OU=SDM,DC=cpandl,DC=com"

In this command, I'm filling in some basic information about the user account. Most notably, I'm using the -SamAccountName parameter to provide the SAM account name, which is required to create a user object. I'm also using the -Path parameter to tell the cmdlet where to put the object—in this case, in my SDM OU in the cpandl.com domain. In addition, I'm providing the user's first name (-GivenName parameter), last name (-Surname parameter), and display name (-DisplayName parameter).

Although running this command would create the user account, there would be two caveats. First, the account would be disabled. Second, the account wouldn't have a password associated with it, which is required in most domains.

To avoid having to enable the account and add a password separately, you can modify the New-ADUser command I showed you. To have New-ADUser automatically enable the account, you need to specify the -Enabled $true parameter in the command. An enabled account requires a password, so you also need to specify the password in the command.

To provide a password, you can use the -AccountPassword parameter. However, you can't simply enter the password in plaintext on the command line. This parameter requires that the password be passed in as a secure string (i.e., have a data type of SecureString). There are two ways to convert the password into a secure string, both of which involve using a variable.

The first method uses the ConvertTo-SecureString cmdlet, which converts plaintext strings to secure strings. For example, if I want to convert the password P@ssw0rd12 into a secure string and assign it to the $pwd variable, I'd run the command:

$pwd = ConvertTo-SecureString -string "P@ssw0rd12" `
  -AsPlainText -force

This isn't the safest method for providing a password, because someone could be looking over my shoulder as I type this command. A safer way is to have the New-ADUser command prompt me for the password and mask the password as I type it. This can be done with the Read-Hostcmdlet and its -AsSecureString parameter:

$pwd = Read-Host -AsSecureString

After this command runs, I'll see the familiar * character as I type my password. After typing the password, I'll need to press Enter.

Now that the password is stored as a secure string in the $pwd variable, I can pass it to the New-ADUser cmdlet as follows:

New-ADUser -Name "Bill Smith" -SamAccountName "bsmith" `
  -GivenName "Bill" -Surname "Smith" `
  -DisplayName "Bill Smith" `
  -Path "OU=SDM,DC=cpandl,DC=com" `
  -Enabled $true -AccountPassword $pwd

As you can see, the command includes the -Enabled and -AccountPassword parameters to enable the account and securely associate a password with it.

Creating one user at a time is neat, but you might need to provision several users at the same time. This is where PowerShell can really shine. For example, suppose I need to create three user accounts. I can create a comma-separated value (CSV) file that contains the account information, then use the Import-CSV cmdlet to feed that information to the New-ADUser cmdlet.

Figure 4 shows my CSV file, which is named userlist.csv.

Figure 4: Using a CSV File to Create Several Users at the Same Time

In this file, notice that the column headers correspond to the parameter names provided in the previous New-ADUser command. Once again, this is intentional. When the CSV data is fed into the New-ADUser cmdlet, the cmdlet will pick up these parameter names from the PowerShell pipeline so that I don't have to specify them in the command. So, here's the command that I'd use to create the three user accounts:

Import-CSV -Path C:\data\userlist.csv |
  New-ADUser -Enabled $true -AccountPassword $pwd

As you can see, I piped the strings outputted by the Import-CSV cmdlet to the New-ADUser cmdlet. Because the pipeline understands that the column headers in the CSV file are parameter names and the rest of the rows contain the values, I only need to provide the -Enabled and -AccountPassword parameters. This is a great feature of the pipeline. It makes using PowerShell for these kinds of automation tasks that much more powerful.

Managing Group Membership

Adding users or computers to groups is a common task in AD management. The AD module makes it relatively easy to perform this task. With the Add-ADGroupMember cmdlet, you can add one or more accounts to a group. For example, suppose I want to add the three users I just created to the Marketing Users group. The simplest way to do that is to run the command:

Add-ADGroupMember -Identity "Marketing Users" `
  -Members jadams,tthumb,mtwain

In this command, I'm using the -Identity parameter to provide the name of the group. I'm also using the -Members parameter to provide the users' SAM account names. If you have multiple SAM account names, they need to be provided in a comma-separated list.

You can combine the operation to create the three users and the operation to add them to the Marketing Users group in a single command so that everything is done in one shot. However, the Add-ADGroupMember cmdlet doesn't support passing group member names into the pipeline. Therefore, you need to use the Add-ADPrincipalGroupMembership cmdlet if you want to leverage the pipeline. This cmdlet can take user, computer, or group objects as input from the pipeline and add those objects to the specified group.

Here's how to combine the user creation operation with the operation to add the new users to the Marketing Users group in a single command:

Import-CSV -Path C:\data\userlist.csv |
  New-ADUser -Enabled $true -AccountPassword $pass `
  -PassThru | Add-ADPrincipalGroupMembership `
  -MemberOf "Marketing Users"

Notice that I'm adding the -PassThru parameter to the New-ADUser portion of the command. This parameter tells New-ADUser to pass the user objects it creates to the pipeline. If this parameter isn't included, the Add-ADPrincipalGroupMembership cmdlet will fail.

Also notice that I'm using only the -MemberOf parameter to specify the group name in the Add-ADPrincipalGroupMembership portion of the command. The pipeline takes care of the rest, adding each of my three new users to the Marketing Users group.

So, using a single PowerShell command, I created three new users, put those users in my OU, gave them passwords, and added them to the Marketing Users group. Now let's look at some other common AD maintenance tasks that you can automate using PowerShell and the AD module.

Resetting User Account Passwords

Occasionally users might need to have their user account passwords reset. You can easily automate this task with the Set-ADAccountPassword cmdlet, which is pretty straightforward. You use it to either change or reset an account password. If you change a password, you need to know the old password and supply the new one. If you want to reset the password, you only need to supply the new password. However, you need the Reset Password permission on the user object in AD to be able to perform the password reset.

Like the -AccountPassword parameter of the New-ADUser cmdlet, the Set-ADAccountPassword cmdlet leverages the SecureString data type for passwords, so you need to use one of the techniques I showed you to convert the plaintext passwords into secure strings. For example, suppose that I need to reset the password for the Tom Thumb user account I created. After I store the new password as a secure string in the $pass variable, I can run the command:

Set-ADAccountPassword -Identity "tthumb" `
  -NewPassword $pass -Reset

In this command, I'm using the -Identity parameter to provide the SAM account name for the Tom Thumb user account. I'm also using the -NewPassword parameter with the $pass variable to provide the new password. Finally, I'm specifying the -Reset parameter to tell the cmdlet that this is a password reset rather than a password change.

There's one additional task I want to perform: Toggle the flag on the Tom Thumb user account to force Tom to change his password at next logon. This is a common practice when you have to reset a user's password. I can accomplish this task by using the Set-ADUser cmdlet with the -ChangePasswordAtLogon parameter set to $true:

Set-ADUser -Identity tthumb -ChangePasswordAtLogon $true

You might be wondering why I didn't use the pipeline to send the output of the Set-ADAccountPassword cmdlet to the Set-ADUser cmdlet to accomplish both operations in a single PowerShell command. Interestingly, I tried that and it didn't work. I presume there's some limitation in the Set-ADAccountPassword cmdlet that prevents the single command from succeeding. In any case, it's easy enough to toggle the flag using the Set-ADUser command I just showed you.

Searching for Active Directory Objects

Another common AD task is to search for AD objects that meet certain criteria. For example, you might need to find all the computers running a certain Windows OS in an AD domain. The Get-ADObject cmdlet is the best cmdlet to use for LDAP searches. For example, if I want to find the computers running Server 2008 R2 in my cpandl.com domain, I'd use the command:

Get-ADObject -LDAPFilter `
  "(&(operatingSystem=Windows Server 2008 R2 Enterprise)`
  (objectClass=computer))" -SearchBase "dc=cpandl,dc=com" `
  -SearchScope Subtree

This command uses three parameters to get the job done: -LDAPFilter, -SearchBase, and -SearchScope. The -LDAPFilter parameter takes a standard LDAP query as input. In this example, I'm querying for all computer objects that have their OperatingSystem attribute set to Windows Server 2008 R2 Enterprise. The -SearchBase parameter tells the cmdlet where to start the search in the AD hierarchy. In this case, I'm searching from the root of the cpandl.com domain, but you can easily limit the search to a particular OU if desired. The -SearchScope parameter tells the cmdlet whether to recurse all containers underneath the search base to find the specified objects. In this case, I'm using the Subtree option so that the cmdlet searches all the containers underneath it.

When I run this command, it'll display the objects that meet my criteria. Alternatively, I could pipe the results to other cmdlets to do something with those objects.

Note that for large searches, you might find it useful to use the -ResultPageSize parameter to control the paging of search results. I typically set this parameter to 1000 to tell the Get-ADObject cmdlet to return 1,000 objects at a time. Otherwise, you might find that you don't get all the results you expected because the number of objects being returned exceeds the maximum policy set for a single search request.

Another cmdlet that Microsoft provides related to searching is Search-ADAccount. This cmdlet is especially useful for searching for a variety of preset conditions, such as disabled accounts, accounts with expired passwords, and accounts that are locked out. For example, the following command finds all user accounts that have expired passwords in my SDM OU:

Search-ADAccount -PasswordExpired -UsersOnly `
  -SearchBase "OU=sdm,dc=cpandl,dc=com" `
  -SearchScope OneLevel

In this command, I'm using the -PasswordExpired parameter to indicate that I'm looking for accounts with expired passwords. The -UsersOnly parameter tells the cmdlet to search user objects only (i.e., exclude computer objects). As I did in the previous example, I'm using the -SearchBase and -SearchScope parameters to tell the cmdlet where to search. However, in this case, I'm using the OneLevel option to search within the immediate OU only (i.e., not within any child OUs) to find accounts with expired passwords.

Only Scratched the Surface

I've only scratched the surface of the capabilities of the AD module, but I hope you have a sense of the power contained therein. As I mentioned previously, there are more than 70 cmdlets in this module. Areas that I didn't touch on include deleting objects using the Remove- cmdlets, restoring deleted objects using the Restore-ADObject cmdlet, and modifying User Account Control (UAC) properties on user objects with the Set-ADAccountControl cmdlet. If there's an AD administration task you need to perform, there's likely a cmdlet that can handle the job.