0% found this document useful (0 votes)
16 views

adpowershellcmdlets

Uploaded by

Dev Kumar
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views

adpowershellcmdlets

Uploaded by

Dev Kumar
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 16

PS C:\> Import-Module ActiveDirectory

The import also creates a new PSDrive, but we won't be using it. However, you
might want to see which commands are in the module:
PS C:\> get-command -module ActiveDirectory

The beauty of these commands is that if I can use a command for one AD
object, I can use it for 10 or 100 or 1,000. Let's put some of these cmdlets to
work.

Task 1: Reset a User Password

Let's start with a typical IT pro task: resetting a user's password. We can easily
accomplish this by using the Set-ADAccountPasswordcmdlet. The tricky part is
that the new password must be specified as a secure string: a piece of text
that's encrypted and stored in memory for the duration of your PowerShell
session. So first, we'll create a variable with the new password:
PS C:\> $new=Read-Host "Enter the new password" -AsSecureString

Next, we'll enter the new password:


PS C:\>

Now we can retrieve the account (using the samAccountname is best) and
provide the new password. Here's the change for user Jack Frost:
PS C:\> Set-ADAccountPassword jfrost -NewPassword $new

Unfortunately, there's a bug with this cmdlet: -Passthru, -Whatif, and -Confirm
don't work. If you prefer a one-line approach, try this:
PS C:\> Set-ADAccountPasswordjfrost -NewPassword

(ConvertTo-SecureString -AsPlainText -String

"P@ssw0rd1z3" -force)

Finally, I need Jack to change his password at his next logon, so I'll modify the
account by using Set-ADUser:
PS C:\> Set-ADUserjfrost -ChangePasswordAtLogon $True
The command doesn't write to the pipeline or console unless you use -True. But
I can verify success by retrieving the username via the Get-ADUsercmdlet and
specifying the PasswordExpired property, shown in Figure 2.

Figure 2: Results of the Get-ADUserCmdlet with the PasswordExpired Property

The upshot is that it takes very little effort to reset a user's password by using
PowerShell. I'll admit that the task is also easily accomplished by using the
Microsoft Management Console (MMC) Active Directory Users and Computers
snap-in. But using PowerShell is a good alternative if you need to delegate the
task, don't want to deploy the Active Directory Users and Computers snap-in,
or are resetting the password as part of a larger, automated IT process.

Task 2: Disable and Enable a User Account

Next, let's disable an account. We'll continue to pick on Jack Frost. This code
takes advantage of the
-Whatif parameter, which you can find on many cmdlets that change things, to
verify my command without running it:
PS C:\> Disable-ADAccount jfrost -whatif

What if: Performing operation "Set" on Target "CN=Jack Frost,

OU=staff,OU=Testing,DC=GLOBOMANTICS,DC=local".

Now to do the deed for real:


PS C:\> Disable-ADAccountjfrost

When the time comes to enable the account, can you guess the cmdlet name?
PS C:\> Enable-ADAccountjfrost
These cmdlets can be used in a pipelined expression to enable or disable as
many accounts as you need. For example, this code disables all user accounts
in the Sales department:
PS C:\> get-aduser -filter "department -eq 'sales'" |

disable-adaccount

Granted, writing the filter for Get-ADUser can be a little tricky, but that's
where using -Whatif with the Disable-ADAccountcmdlet comes in handy.

Task 3: Unlock a User Account

Now, Jack has locked himself out after trying to use his new password. Rather
than dig through the GUI to find his account, I can unlock it by using this
simple command:
PS C:\> Unlock-ADAccount jfrost

This cmdlet also supports the -Whatif and -Confirm parameters.

Task 4: Delete a User Account

Deleting 1 or 100 user accounts is easy with the Remove-ADUsercmdlet. I don't


want to delete Jack Frost, but if I did, I could use this code:
PS C:\> Remove-ADUserjfrost -whatif

What if: Performing operation "Remove" on Target

"CN=Jack Frost,OU=staff,OU=Testing,DC=GLOBOMANTICS,DC=local".

Or I could pipe in a bunch of users and delete them with one simple command:
PS C:\> get-aduser -filter "enabled -eq 'false'"

-property WhenChanged -SearchBase "OU=Employees,

DC=Globomantics,DC=Local" | where {$_.WhenChanged

-le (Get-Date).AddDays(-180)} | Remove-ADuser -whatif

This one-line command would find and delete all disabled accounts in the
Employees organizational unit (OU) that haven't been changed in at least 180
days.

Task 5: Find Empty Groups


Group management seems like an endless and thankless task. There are a
variety of ways to find empty groups. Some expressions might work better than
others, depending on your organization. This code will find all groups in the
domain, including built-in groups:
PS C:\> get-adgroup -filter * | where {-Not

($_ | get-adgroupmember)} | Select Name

If you have groups with hundreds of members, then using this command might
be time-consuming; Get-ADGroupMember checks every group. If you can limit
or fine-tune your search, so much the better.

Here's another approach:


PS C:\> get-adgroup -filter "members -notlike '*'

-AND GroupScope -eq 'Universal'" -SearchBase

"OU=Groups,OU=Employees,DC=Globomantics,

DC=local" | Select Name,Group*

This command finds all universal groups that don't have any members in my
Groups OU and that display a few properties. You can see the result in Figure
3.

Figure 3: Finding Filtered Universal Groups

Task 6: Add Members to a Group

Let's add Jack Frost to the Chicago IT group:


PS C:\> add-adgroupmember "chicago IT" -Members jfrost
It's that simple. You can just as easily add hundreds of users to a group,
although doing so is a bit more awkward than I would like:
PS C:\> Add-ADGroupMember "Chicago Employees" -member

(get-aduser -filter "city -eq 'Chicago'")

I used a parenthetical pipelined expression to find all users with a City property
of Chicago. The code in the parentheses is executed and the resulting objects
are piped to the -Member parameter. Each user object is then added to the
Chicago Employees group. It doesn't matter whether there are 5 or 500 users;
updating group membership takes only a few seconds This expression could
also be written using ForEach-Object, which might be easier to follow.
PS C:\> Get-ADUser -filter "city -eq 'Chicago'" | foreach

{Add-ADGroupMember "Chicago Employees" -Member $_}

Task 7: Enumerate Members of a Group

You might want to see who belongs to a given group. For example, you should
periodically find out who belongs to the Domain Admins group:

PS C:\> Get-ADGroupMember "Domain Admins"

Figure 4 illustrates the result.

Figure 4: Finding Members of the Domain Admins Group

The cmdlet writes an AD object for each member to the pipeline. But what
about nested groups? My Chicago All Users group is a collection of nested
groups. To get a list of all user accounts, all I need to do is use the -Recursive
parameter:
PS C:\> Get-ADGroupMember "Chicago All Users"

-Recursive | Select DistinguishedName

If you want to go the other way -- that is, find which groups a user belongs to --
you can look at the user's MemberOf property:
PS C:\> get-aduserjfrost -property Memberof |

Select -ExpandPropertymemberOf

CN=NewTest,OU=Groups,OU=Employees,

DC=GLOBOMANTICS,DC=local

CN=Chicago Test,OU=Groups,OU=Employees,

DC=GLOBOMANTICS,DC=local

CN=Chicago IT,OU=Groups,OU=Employees,

DC=GLOBOMANTICS,DC=local

CN=Chicago Sales Users,OU=Groups,OU=Employees,

DC=GLOBOMANTICS,DC=local

I used the -ExpandProperty parameter to output the names of MemberOf as


strings.

Task 8: Find Obsolete Computer Accounts

I'm often asked how to find obsolete computer accounts. My response is


always, "What defines obsolete?" Different organizations most likely have a
different definition for when a computer account (or user account, for that
matter) is considered obsolete or no longer in use. Personally, I've always
found it easiest to find computer accounts that haven't changed their password
in a given number of days. I tend to use 90 days as a cutoff, assuming that if a
computer hasn't changed its password with the domain in that period, it's
offline and most likely obsolete. The cmdlet to use is Get-ADComputer:
PS C:\> get-adcomputer -filter "Passwordlastset

-lt '1/1/2012'" -properties *| Select name,passwordlastset

The filter works best with a hard-coded value, but this code will retrieve all
computer accounts that haven't changed their password since January 1, 2012.
You can see the results in Figure 5.
Figure 5: Finding Obsolete Computer Accounts

Another option, assuming that you're at least at the Windows 2003 domain
functional level, is to filter by using the LastLogontimeStamp property. This
value is the number of 100 nanosecond intervals since January 1, 1601, and is
stored in GMT, so working with this value gets a little tricky:
PS C:\> get-adcomputer -filter "LastlogonTimestamp -gt 0"

-properties * | select name,lastlogontimestamp,

@{Name="LastLogon";Expression={[datetime]::FromFileTime

($_.Lastlogontimestamp)}},passwordlastset | Sort

LastLogonTimeStamp

I took the liberty of adding a custom property that takes the


LastLogonTimeStamp value and converts it into a friendly date. Figure 6
depicts the result.

Figure 6: Converting the LastLogonTimeStamp Value to a Friendly Date

To create a filter, I need to convert a date, such as January 1, 2012, into the
correct format, by converting it to a FileTime:
PS C:\> $cutoff=(Get-Date "1/1/2012").ToFileTime()

PS C:\> $cutoff

129698676000000000

Now I can use this variable in a filter for Get-ADComputer:


PS C:\> Get-ADComputer -Filter "(lastlogontimestamp -lt

$cutoff) -or (lastlogontimestamp -notlike '*')" -property

* | Select Name,LastlogonTimestamp,PasswordLastSet

This query finds the same computer accounts that I found in Figure 5. Because
there's a random offset with this property, it doesn't matter which approach
you take -- as long as you aren't looking for real-time tracking.

Task 9: Disable a Computer Account

Perhaps when you find those inactive or obsolete accounts, you'd like to disable
them. Easy enough. We'll use the same cmdlet that we use with user accounts.
You can specify it by using the account's samAccountname:
PS C:\> Disable-ADAccount -Identity "chi-srv01$" -whatif

What if: Performing operation "Set" on Target "CN=CHI-SRV01,

CN=Computers,DC=GLOBOMANTICS,DC=local".

Or you can use a pipelined expression:


PS C:\> get-adcomputer "chi-srv01" | Disable-ADAccount

I can also take my code to find obsolete accounts and disable all those
accounts:
PS C:\> get-adcomputer -filter "Passwordlastset

-lt '1/1/2012'" -properties *| Disable-ADAccount

Task 10: Find Computers by Type

The last task that I'm often asked about is finding computer accounts by type,
such as servers or laptops. This requires a little creative thinking on your part.
There's nothing in AD that distinguishes a server from a client, other than the
OS. If you have a laptop or desktop running Windows Server 2008, you'll need
to get extra creative.
You need to filter computer accounts based on the OS. It might be helpful to
get a list of those OSs first:
PS C:\> Get-ADComputer -Filter * -Properties OperatingSystem |

Select OperatingSystem -unique | Sort OperatingSystem

Figure 7 shows what I have to work with.

Figure 7: Retrieving a List of OSs

I want to find all the computers that have a server OS:


PS C:\> Get-ADComputer -Filter "OperatingSystem -like

'*Server*'" -properties OperatingSystem,OperatingSystem

ServicePack | Select Name,Op* | format-list

I've formatted the results as a list, as you can see in Figure 8.

Figure 8
As with the other AD Get cmdlets, you can fine-tune your search parameters
and limit your query to a specific OU if necessary. All the expressions that I've
shown you can be integrated into larger PowerShell expressions. For example,
you can sort, group, filter, export to a comma-separated value (CSV), or build
and email an HTML report, all from PowerShell and all without writing a single
PowerShell script! In fact, here's a bonus: a user password-age report, saved as
an HTML file:
PS C:\> Get-ADUser -Filter "Enabled -eq 'True' -AND

PasswordNeverExpires -eq 'False'" -Properties

PasswordLastSet,PasswordNeverExpires,PasswordExpired |

Select DistinguishedName,Name,pass*,@{Name="PasswordAge";

Expression={(Get-Date)-$_.PasswordLastSet}} |sort

PasswordAge -Descending | ConvertTo-Html -Title

"Password Age Report" | Out-File c:\Work\pwage.htm

Although this one-line command might look intimidating at first, it's pretty
simple to follow when you have a little PowerShell experience. The only extra
step that I took was to define a custom property called PasswordAge. The value
is a timespan between today and the PasswordLastSet property. I then sorted
the results on my new property. Figure 9 shows the output from my little test
domain.

Figure 9

The OU names give PowerShell a place to start its search from, which is called
the search base. The search base typically takes the form of an LDAP
distinguished name (DN)—for example, OU=Marketing, DC=cpandl,DC=com—
so that's what I'll store in my array. The following command creates my array
of OUs to search:
$searchBase =
"OU=Test,DC=cpandl,DC=com",
"OU=Sales,DC=cpandl,DC=com",
"OU=QA,DC=cpandl,DC=com"

(Although this command wraps here, you'd enter it all on one line. The same
holds true for the other commands that wrap.) This command assigns the string
array to the $searchBase variable. If you want to make sure that an array is
created, run the command
$searchBase[0]

PowerShell should return the first element in the array


(OU=Test,DC=cpandl,DC=com).

Now I need a command that does the searching. For this particular task, I've
chosen the Search-ADAccountcmdlet. The great thing about this cmdlet is that
it has all the parameters I need to search for inactive computer accounts, so I
don't have to build a complex LDAP filter. For example, to find all inactive
computer accounts in a domain, I can simply run
Search-ADAccount
-AccountDisabled -ComputersOnly

Figure 1 shows an example of what the results will look like.


Figure 1: Retrieving disabled computer accounts with Search-ADAccount

Finally, I need a command that moves the disabled computers to a holding OU.
To perform the move, I'll use the Move-ADObjectcmdlet, which lets you easily
move an object or container from one place to another in AD. For example, the
following command uses this cmdlet to move a disabled computer account to
an OU called BitBucket:
Move-ADObject -Identity
"CN=NT4,CN=Computers,DC=cpandl,DC=com"
-TargetPath
"OU=BitBucket,DC=cpandl,DC=com"

In this case, the -Identity parameter specifies the DN of the object I want to
move (a workstation named NT4) and the TargetPath parameter specifies the
DN of the OU I want to move the object to. It's as simple as that.

I now have all the pieces to perform the bulk search-and-move operation: I
have the list of OUs, the command to find disabled computer accounts, and the
command to move them. There are two ways to put them all together,
depending on how comfortable you are with PowerShell.

The simplest approach is to search for inactive computer accounts in a single


OU, then use PowerShell's built-in pipelining capability to pipe the results to
the command that will move those accounts. This can be done with code such
as
Search-ADAccount -AccountDisabled
-SearchBase
"OU=SDM,DC=cpandl,DC=com" |
Move-ADObject -TargetPath
"OU=BitBucket,DC=cpandl,DC=com"

In this code, I use the Search-ADAccountcmdlet to search for disabled


computer accounts in the SDM OU. I pipe the resulting list of disabled
computer accounts to the Move-ADObjectcmdlet, which will move those
accounts to the BitBucket OU. Note that I didn't need to include the -Identity
parameter for Move-ADObject because the pipeline takes care of passing the
name of each disabled computer account without me explicitly stating it.

The limitation of this approach is that I have to type this command for each OU
on my list. This is where my $searchBase array comes in handy. Using that
array, I can write code to iterate through my OU list:
foreach ($ou in $searchBase)
{Search-ADAccount -AccountDisabled
-ComputersOnly -SearchBase $ou |
Move-ADObject -TargetPath
"OU=BitBucket,DC=cpandl,DC=com"}
Let's look at what this code is doing. First, I use the ForEach-Object cmdlet
(aliased to foreach) to iterate through my list of OU names, which is stored in
$searchBase. For each OU in $searchBase, I call the Search-ADAccountcmdlet
and tell it to look for disabled computer accounts in that OU. I then pipe the
output to the Move-Object cmdlet, which moves them. The end result is that all
disabled computer accounts in the three OUs are moved to the BitBucket OU.

Making Mass Modifications

The second scenario I want to cover is making mass changes to AD objects. For
example, you might need to modify a particular attribute on a large number of
objects, based on some other criteria. Let's create a scenario, then look at how
to accomplish it.

Suppose I want to find all of the users who are a member of the Marketing
Employees group. For each of these users, I want to write the string FTE to his
or her employeeType attribute.

First, I need to find the best way to determine a user's group memberships. I
have a couple of options:

 I could read each user's memberOf attribute to determine whether that user is a direct
member of a particular group. That doesn't necessarily give me any indirect
memberships (groups that are a member of other groups), but it does get me part of
the way there. If I need indirect memberships, I could read a user's tokenGroups
attribute, which is a special constructed attribute that represents both direct and
indirect group memberships. It exists in Windows Server 2003 AD and later.
 I could search each group, looking at its members attribute to find out that group's
direct members. I would also need to search through the membership of each group
that's nested within another group. Fortunately, the Active Directory module makes
this task easy. Namely, the Get-ADGroupMembercmdlet provides the -Recursive
parameter, which will chase down any indirect group members.

The second option is a more scalable solution for my scenario, so that's the
approach I'll use.

Next, I need to find the best way to modify attributes on user objects. To do
this, I'll use Set-ADUser. This cmdlet lets you modify properties on user
accounts. It comes with a set of named parameters that include commonly
modified properties. However, you can also modify many other user account
properties by using the generic -Add, -Replace, -Clear, and -Remove
parameters.

The employeeType attribute isn't one of Set-ADUser's named parameters, so I'll


need to use the generic parameters. When using these parameters, it's
important to know that they view an attribute that's not set differently than an
attribute that already has a value. So, you need to use the -Add parameter
when an attribute isn't set and the -Replace parameter when a value already
exists.

Now that I have all the pieces in place to make the bulk change to the
employeeType attribute based on user group membership, let's put it all
together. Once again, I can leverage the PowerShell pipeline, as follows:
Get-ADGroupMember
-Identity "Marketing Employees"
-Recursive |
where { $_.employeeType -eq $null } |
Set-ADUser -Add @{employeeType = "FTE"}
Get-ADGroupMember
-Identity "Marketing Employees"
-Recursive |
where { $_.employeeType -ne $null } |
Set-ADUser -Replace @{employeeType = "FTE"}

Let's look at what these two commands are doing. In the first command, I use
the Get-ADGroupMembercmdlet with the -Recursive parameter to get all the
direct and indirect members of the Marketing Employees group in my domain.
I then use the PowerShell pipeline to send the output to the Where-Object
cmdlet (aliased as where), which checks whether the group member's
employeeType attribute is equal to null (i.e., a value isn't set). If it's null, I pass
the member to the Set-ADUsercmdlet to populate that attribute. Because
employeeType isn't one of Set-ADUser's named parameters and it doesn't
contain a value, I use the -Add parameter to populate it with "FTE". The tricky
thing about using a generic parameter is that you have to pass in a hashtable
that contains the name of the attribute and its value. A hashtable is simply a
key-value pair that you can define by delimiting it with the @{ } construct, as
I've done with @{employeeType = "FTE"}.

The second command is basically the same as the first, except that I change
the where clause to check whether employeeType is not equal to null (i.e.,
already has a value). If it's not null, I pass the member to the Set-
ADUsercmdlet. This time, I use the generic -Replace parameter to change the
existing value to "FTE". Once again, I use a hashtable to provide the new value.

Get the Job Done Quickly and Easily

As the two examples show, searching for AD objects is simple with Search-
ADAccount and moving them is effortless with Move-ADObject. Get-
ADGroupMember makes it easy to recursively root out all direct and nondirect
members of a group—a task that used to take quite a bit of work in the pre-
PowerShell days. And when you need to modify those group members, Set-
ADUser quickly gets the job done.

All in all, when it comes to performing bulk operations against AD, the Active
Directory module delivers. Its cmdlets provide a powerful built-in mechanism to
perform most automation tasks. I encourage you to explore the other cmdlets
in the module, which you can enumerate by typing

You might also like