Blog: SANS Audit Advice & Resources

Blog: SANS Audit Advice & Resources

Learning Powershell: How to Extract User Objects from Active Directory using Powershell!

Welcome to the show notes for ournext episode! Last time we were talking about Powershell, demonstrating some different ways that we could use it to begin to automate some of our audit and administrative tasks. For example, pulling some information out of our Active Directory.

In this week's AuditCast we're going to continue on and try to modularize some of the code that we wrote last week. At the same time, we'll try to simplify, clean it up, and finally generalize it just a bit, to create something that we can use in many different tasks that we'll be examining over the next couple of weeks. Before starting the AuditCast, I actually did do one or two things that I've done ahead of time.

The first thing is that I took some of the code that we were working with last week, the code that actually got the handle for doing a domain search, and I moved that into what's called a "function." This week we'll see how we can leverage these sorts of things. You should be able to see that see that this code is essentially exactly the same code we wrote last week; the only difference is it's in a function.

function Get-DirectoryServiceSearcher
{
#-------------------------------------------------------------------------------------#
# The following block of code can be used repeatably within a script to obtain a
# DirectorySearcher object for the current domain.
#-------------------------------------------------------------------------------------#
# Set up an AD Directory Searcher within the current domain
$domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$domainSearcher = New-Object System.DirectoryServices.DirectorySearcher

# Configure the searcher
$domainSearcher.SearchScope = "subtree"
# Scope choices are:
# Base - Search only the specified scope
# OneLevel - Search only the children one level beneath the scope
# Subtree - Starting from the specified scope, search it and all descendants

# Set the starting point for the scope
$domainSearcher.SearchRoot = "LDAP://$Domain"

#-------------------------------------------------------------------------------------#
# Finally, return the searcher object
$domainSearcher
}


The very last thing that the function does may look a little odd. To return a value from a function in Powershell, you can either use the "return" keyword, or just put the value as the last item in the function! If you'd like details on what's happening in this function, I'd suggest that you go back and review last week's AuditCast where this code was first developed.

While we could just paste this function into the code that we're going to write this week, our real goal is to see how to start creating little reusable blocks of code that can then be assembled for almost any need. This means that I'm going to need a way to actually access this code from another script. That's where our second piece of pre-written code comes in.

function Get-ScriptDirectory
{
$invocation = (Get-Variable MyInvocation -Scope 1).Value
Split-Path $Invocation.MyCommand.Path
}

To use this code, all we need to do is paste this function into each script that will try to leverage our little blocks of code. What this code does is figure out what the correct path is for the script that is running. You may recall that Powershell requires that you use a fully distinguished or specify a relative path when you want to reference a piece of code or run a piece of code. This function allows us to solve this problem. With this function copied into a script and the Get-DirectoryServiceSearcher.ps1 sitting in the same directory, all we need to do to import that code is this:
$import = Join-Path(Get-ScriptDirectory) "Get-DirectoryServiceSearcher.ps1"
.$import

This defines a variable named $import and uses Join-Path, which is a built-in command. This allows me to create a path; essentially I'm going to tell it to join the path of whatever the current script directory and prepend it to the name of a file that like to grab the file (in this case, DirectoryServiceSearcher.ps1).

What can we do with this? Well, I'd recommend that you have a look at the related AuditCast where we use these simple pieces to develop an extremely hand function that allows us to extract arbitrary objects out of Active Directory and turn them into custom-built objects right inside of Powershell!

If you're looking for the source code for the function that we wrote, look no further!

function Get-ADObjects($LDAPFilter="(&(objectCategory=Person)(objectClass=User))")
{
$domainSearcher = Get-DirectoryServiceSearcher
$domainSearcher.Filter = $LDAPFilter
$domainSearcher.SizeLimit=100
$results = $domainSearcher.FindAll()
$aDObjects = @()

foreach($result in $results)
{
$thisObject = New-Object System.Object
foreach ($property in $result.Properties.PropertyNames)
{
$thisObject | Add-Member -type NoteProperty -Name $property -Value $result.Properties.Item($property)
}
$aDObjects += $thisObject
}
$aDObjects
}


David Hoelzer teaches several full week courses ranging from basic security through to advanced exploitation and penetration testing. For a thorough treatment of this specific issue and a discussion of controls to mitigate this and similar issues, consider attending thefull week course on Advanced System & Network Auditing. More information can be found here:AUD 507 course. AUD 507 gives both auditors and security professionals powerful tools to automate and manage security over time.

1 Comments

Posted March 26, 2012 at 5:07 AM | Permalink | Reply

Juned Ansari

The article is good..

But with the release of server 2008 R2 and Powershell version 2 you can use the Active Directory module for Windows PowerShell in Windows Server 2008 R2 and avoid such lengthy dotnet calls and scripts to access info related to objects in AD

But yes there are still certain things that can be accessed only by dotnet calls :-)

Post a Comment






* Indicates a required field.