Summary: Learn how to use Windows PowerShell to search Microsoft Active Directory for users that have missing values, and automatically add default values.
Hey, Scripting Guy! We have several network administrators where I work. Unfortunately, all of them have complete rights to Active Directory. This means that any one of the administrators can create a user. We have scripts that we are supposed to use when creating a user, but from time to time, one of the administrators will use Active Directory Users and Computers to manually create the user. When this happens, invariably something gets messed up.
We just had an audit, and we got hit on the inspection due to the fact that our users are created in an inconsistent manner. We have 30 days to resolve our deficiencies before “stuff” hits the fan. What I need is a Windows PowerShell script that will search a particular Active Directory organizational unit for users that are missing a value for a specific attribute. After a user has been identified, I need the script to add a value for that attribute. Do you have a script that can perform this task for us?
— CW
Hello CW,
Microsoft Scripting Guy Ed Wilson here. I keep waiting for things to slow down. It seems like it does not matter how many meetings one goes to, or how many emails one answers. There are always more coming down the pike. It is like “honey do” lists at home or lists of scripts I want to write. I have a whiteboard in my office that contains a list of scripts I want to write someday. It seemed like a good idea at the time. The scripts are all things that will take a bit of research to write. The problem is that script ideas come to the board faster than I can erase completed scripts to make room for more scripts. Scribbles cover the board; I may add a second board.
CW, you are in luck because one of my whiteboard hieroglyphics represents the exact script scenario you detailed in your email to scripter@microsoft.com. Actually, we are both in luck because I get to erase said hieroglyph from the board. The complete FindAndAddEmptyADValues.ps1 Windows PowerShell script is shown here.
FindAndAddEmptyADValues.ps1
Function Get-UsersFromOU
{
Param(
$SearchRoot,
$filter = “ObjectCategory=Person”
)
$ds = [adsiSearcher]$filter
$ds.SearchRoot = [adsi]“LDAP://$SearchRoot”
$ds.findAll()
} #end get-usersFromOu
Function Set-AttributeValue
{
Param(
$SR,
$SearchAttribute,
$NewValue
)
$i = $null
Foreach($user in $sr) {
IF([string]::isNullOrEmpty($user.properties.item($SearchAttribute)))
{
$de = $user.GetDirectoryEntry()
“modifying $($de.name)”
$de.$SearchAttribute = $newValue
$de.setinfo()
$i++
} #end if
} #end foreach-object
“modified $i users”
} # end Set-AttributeValue # *** Entry Point to script *** $sr = Get-UsersFromOU -SearchRoot “ou=testou,dc=nwtraders,dc=com”
Set-AttributeValue -SR $sr -SearchAttribute “description” -NewValue “By Script”
The FindAndAddEmptyADValues.ps1 begins with the Get-UsersFromOU function. The function accepts two parameters: the first parameter specifies the organizational unit (OU) to use for the search root, and the second parameter specifies the search filter. The search filter is set to filter out objects that are equal to the objectcategory of person. A filter such as this one will exclude computer objects. The parameter portion of the Get-UsersFromOU function is shown here:
Function Get-UsersFromOU
{
Param(
$SearchRoot,
$filter = “ObjectCategory=Person”
)
The [adsiSearcher] type accelerator is used to create an instance of the System.DirectoryServices.DirectorySearcher .NET Framework class. The search filter is supplied to the [adsiSearcher] type accelerator for its constructor. Other ways of creating an instance of the DirectorySearcher class are documented on MSDN. The DirectorySearcher class is created here and stored in the $ds variable:
$ds = [adsiSearcher]$filter
The searchRoot property of the DirectorySearcher needs to be an instance of a System.DirectoryServices.DirectoryEntry .NET Framework class. To easily create an instance of the DirectoryEntry class, use the [adsi] type accelerator as shown here:
$ds.SearchRoot = [adsi]“LDAP://$SearchRoot”
To find all of the objects that meet the search filter and are located in the search root, use the findall() method shown here:
$ds.findAll()
The complete Get-UsersFromOU function is shown here.
Function Get-UsersFromOU
{
Param(
$SearchRoot,
$filter = “ObjectCategory=Person”
)
$ds = [adsiSearcher]$filter
$ds.SearchRoot = [adsi]“LDAP://$SearchRoot”
$ds.findAll()
} #end get-UsersFromOU
The Set-AttributeValue function accepts three input parameters. The first is an instance of the System.DirectoryServices.SearchResultCollection class that is returned from the Get-UsersFromOU function. The $searchAttribute parameter is the attribute that is to be checked for a value, and a value is supplied if it is empty or null. The $newValue parameter is the string value to add to the empty or null attribute value. This portion of the Set-AttributeValue function is shown here:
Function Set-AttributeValue {Param(
$SR,
$SearchAttribute,
$NewValue
)
The $i variable is used to count the number of users that are modified. It has its initial value set to $null. Because the $sr variable contains a SearchResultCollection class, I need to walk through the collection to retrieve an individual instance of the SearchResult class. The $user variable will contain a single instance of the SearchResult class on each pass through the collection. The isNullOrEmpty static method is used from the system.string .NET Framework class. This portion of the function is shown here:
$i = $nullForeach($user in $sr) {
IF([string]::isNullOrEmpty($user.properties.item($SearchAttribute)))
The SearchResult class has a GetDirectoryEntry method that will create a DirectoryEntry class that matches the SearchResult. The attribute receives a new value, and the setinfo() method is called to write the changes back to Active Directory. The value of the $i counter variable is then incremented, and a summary string is displayed in the Windows PowerShell console. This portion of the function is shown here:
{$de = $user.GetDirectoryEntry()
“modifying $($de.name)”
$de.$SearchAttribute = $newValue
$de.setinfo()
$i++
} #end if
} #end foreach-object
“modified $i users”
} # end Set-AttributeValue
The complete Set-AttributeValue function is shown here.
Function Set-AttributeValue {Param(
$SR,
$SearchAttribute,
$NewValue
)
$i = $null
Foreach($user in $sr) {
IF([string]::isNullOrEmpty($user.properties.item($SearchAttribute)))
{
$de = $user.GetDirectoryEntry()
“modifying $($de.name)”
$de.$SearchAttribute = $newValue
$de.setinfo()
$i++
} #end if
} #end foreach–object
“modified $i users”
} # end Set-AttributeValue
The entry point to the FindAndAddEmptyAdValues.ps1 script calls the Get-UsersFromOU function and stores the returned SearchResultCollection in the $sr variable. It then calls the Set-AttributeValue function and passes the SearchResultCollection, an attribute to search, and a new value to supply if the attribute value is empty or null. This portion of the script is shown here:
# *** Entry Point to script ***$sr = Get-UsersFromOU -SearchRoot “ou=testou,dc=nwtraders,dc=com” Set-AttributeValue -SR $sr -SearchAttribute “description” -NewValue “By Script”
When I ran the script on my computer, the output shown in the following image appeared in my Windows PowerShell ISE.
CW, that is all there is to using Windows PowerShell to search AD DS for users with empty attribute values and then add values to those attributes. Active Directory Week will continue tomorrow when we will talk about using the Microsoft Active Directory cmdlets to search AD DS for users with empty attribute values.
We invite you to follow us on Twitter and Facebook. If you have any questions, send email to us at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson and Craig Liebendorfer, Scripting Guys
0 comments