Active Directory|PowerShell

Expanding the Active Directory Searcher and PowerShell

I hope by now that you are comfortable using the Active Directory Searcher object. If you have no idea what I am talking about, take a few minutes to get caught up on the previous articles, Discovering the Active Directory Searcher with PowerShell and Finding Groups with the Active Directory Searcher and PowerShell.

 

 

Sponsored Content

Maximize Value from Microsoft Defender

In this ebook, you’ll learn why Red Canary’s platform and expertise bring you the highest possible value from your Microsoft Defender for Endpoint investment, deployment, or migration.

Let’s expand the scope and find multiple objects with user accounts.

$searcher = New-Object system.DirectoryServices.DirectorySearcher
$searcher.SearchRoot = "LDAP://ou=employees,dc=globomantics,dc=local"
$searcher.filter = "(objectclass=user)"
$props = "distinguishedname","name","samaccountname","title","department","directreports",
"whencreated","whenchanged","givenname","sn","userprincipalname","adspath"
foreach ($item in $props) {
    $searcher.PropertiesToLoad.Add($item) | out-null
}

I have limited my search to an OU that contains my active user accounts. I have also specified the properties I want to retrieve. Once the searcher is configured, I can find all matching objects.

Finding all user objects (Image Credit: Jeff Hicks)
Finding All User Objects (Image Credit: Jeff Hicks)

Let’s look at a representative sample.

A search result (Image Credit: Jeff Hicks)
A Search Result (Image Credit: Jeff Hicks)

As we looked at before, it might be nice to clean this up and create an object to write to the pipeline.

foreach ($user in $all[4]) {
$h = @{}
foreach ($p in $props) {
 $value =  $user.Properties.item($p)
 if ($value.count -eq 1) {
    $value = $value[0]
 }
 $h.add($p,$value)
}

new-object psobject -property $h
}

Creating a better result object (Image Credit: Jeff Hicks)
Creating a Better Result Object (Image Credit: Jeff Hicks)

Because the result properties are treated as collection objects, I needed to expand them. I still wanted to keep properties that were actual collections, like directreports. I tested with a single object and I could modify the loop to go through everything in $all. It makes more sense to create a function.

Function Convert-ADSearchResult {
[cmdletbinding()]
Param(
[Parameter(Position = 0,Mandatory,ValueFromPipeline)]
[ValidateNotNullorEmpty()]
[System.DirectoryServices.SearchResult]$SearchResult
)

Begin {
    Write-Verbose "Starting $($MyInvocation.MyCommand)"
}

Process {
    Write-Verbose "Processing result for $($searchResult.Path)"
    #create an ordered hashtable with property names alphabetized
    $props = $SearchResult.Properties.PropertyNames | Sort-Object

    $objHash = [ordered]@{}

    foreach ($p in $props) {
     $value =  $searchresult.Properties.item($p)
     if ($value.count -eq 1) {
        $value = $value[0]
     }
     $objHash.add($p,$value)
    }

new-object psobject -property $objHash
}

End {
    Write-Verbose "Ending $($MyInvocation.MyCommand)"
}
}

The function is designed to take pipelined input from any search result.

Converted search result (Image Credit: Jeff Hicks)
Converted Search Result (Image Credit: Jeff Hicks)

Now I can process everything and work with the results as necessary.

$all | Convert-ADSearchResult | Select Name,UserPrincipalName,Department,Title,When* | Out-GridView

Gridview results (Image Credit: Jeff Hicks)
Gridview Results (Image Credit: Jeff Hicks)

Here is another way to do this.

Grouping search results (Image Credit: Jeff Hicks)
Grouping Search Results (Image Credit: Jeff Hicks)

But let’s say I wanted to find all users in the Finance department. That requires some special formatting in my LDAP filter.

$searcher.filter = "(&(objectclass=user)(department=finance))"

You need to enclose each filter part inside the (&) construct, which tells PowerShell to search for both of these things.

Filtering by department (Image Credit: Jeff Hicks)
Filtering by Department (Image Credit: Jeff Hicks)

You can keep adding filter components inside the (&).

Multiple filters (Image Credit: Jeff Hicks)
Multiple Filters (Image Credit: Jeff Hicks)

You can also use wildcards.

Filtering with wild cards (Image Credit: Jeff Hicks)
Filtering with Wildcards (Image Credit: Jeff Hicks)

Once you have objects in PowerShell, you can work with them any way you want. I hope you will take some time to try these things out in your own test environment. Next time, we will look at searching for groups. We also still need to address handling very large number of search results and filtering tips. I hope you will keep checking back.

Related Topics:

BECOME A PETRI MEMBER:

Don't have a login but want to join the conversation? Sign up for a Petri Account

Register
Comments (2)

2 responses to “Expanding the Active Directory Searcher and PowerShell”

  1. <p>I am using a script based on searchroot which I'd like to modify to export a list of members of an active directory security group. Can I ask for someone to take a quick look and provide advice?</p><p><br></p><p><br></p><p>script:</p><p><br></p><p>#========================</p><p># Gather SCCM-Computers OU Containing Assets</p><p>#========================</p><p><br></p><p>$searchRoot = "LDAP://OU=SCCM-Computers,DC=wc,DC=com"</p><p><br></p><p>$Searcher = New-Object DirectoryServices.DirectorySearcher</p><p>$Searcher.Filter = "(&amp;(objectCategory=computer))"</p><p><br></p><p>$Searcher.SearchRoot = $searchRoot</p><p><br></p><p>$computer = $Searcher.FindAll()</p><p><br></p><p>$messageBody = ""</p><p>$messageSubject = ""&nbsp;</p><p><br></p><p>if ($computer.Count -ne 0) {</p><p> $messageSubject = "WARNING! Computers in SCCM-Computers OU."&nbsp;</p><p> $messageBody = "&lt;font color='FF0000'&gt;&lt;h3&gt;Please move the below computers out of the SCCM-Computers OU. Thank you!&lt;/h3&gt;&lt;/font&gt;&lt;ul&gt;"</p><p><br></p><p> foreach ($child in $computer) {&nbsp;</p><p> $messageBody = "$($messageBody)&lt;li&gt;$($child.Properties.name)&lt;/li&gt;"</p><p> }</p><p><br></p><p> $messageBody = "$($messageBody)&lt;/ul&gt;"</p><p><br></p><p> $MailMessage = New-Object System.Net.Mail.MailMessage&nbsp;</p><p><br></p><p> $MailMEssage.IsBodyHtml = $true</p><p><br></p><p> $sender = New-Object System.Net.Mail.MailAddress("[email protected] ", "IT AppServices")&nbsp;</p><p> $MailMessage.Sender = $sender</p><p><br></p><p> $MailMessage.From = $sender&nbsp;</p><p><br></p><p><br></p><p> $MailMessage.To.add( (New-Object System.Net.Mail.MailAddress("[email protected]", "Hardware, Team")) )</p><p><br></p><p><br></p><p> $MailMessage.Subject = $messageSubject&nbsp;</p><p><br></p><p> $MailMessage.Body = $messageBody</p><p><br></p><p> $SMTPClient = New-Object System.Net.Mail.SmtpClient&nbsp;</p><p> $SMTPClient.host = "relay.wc.com"&nbsp;</p><p> $SMTPClient.Send($MailMessage)</p><p>}</p><p><br></p>

Leave a Reply

External Sharing and Guest User Access in Microsoft 365 and Teams

This eBook will dive into policy considerations you need to make when creating and managing guest user access to your Teams network, as well as the different layers of guest access and the common challenges that accompany a more complicated Microsoft 365 infrastructure.

You will learn:

  • Who should be allowed to be invited as a guest?
  • What type of guests should be able to access files in SharePoint and OneDrive?
  • How should guests be offboarded?
  • How should you determine who has access to sensitive information in your environment?

Sponsored by: