PowerShell Tips and Tricks for Scripting Active Directory Test Environments

PowerShell Tips and Tricks for Scripting Active Directory Test Environments

In my role as a Technical Product Manager, I often find myself prepping demos, setting up test environments, and helping customers test and administrate their Active Directory environments with PowerShell. PowerShell, being the most efficient and ubiquitous method of management at scale in the Windows Server world, is my goto tool anytime I need to work with Active Directory.

The vast majority of my Active Directory scripting these days is targeted at test, demo, and QA environments that frequently need to be rebuilt or adjusted to fit a new need or process.

This post is not going to be a suggestion for creating or configuring a new lab environment or even managing production Active Directory environments, but instead, we’ll focus on a few PowerShell Tips and Tricks for Scripting Active Directory Test Environments after recent experiences working with colleagues and customers.

Using Custom Objects and Splatting

If you have used Active Directory Cmdlets or any Cmdlets, you should be quite familiar with Input Parameters. These are the inputs we specify when running a command. For example, the New-ADUser has parameters that specify properties of a new Active Directory user that we wish to create:

New-ADUser -FirstName "John" -LastName "Smith" -DisplayName "John Smith"

It is usually the case that we don’t need to specify more than a handful of parameters per Command in our scripting. However, the New-ADUser Command itself has over 63 parameters. Once you need to start populating a large number of parameters, your script can quickly become hard to manage and troubleshoot.

Thankfully there are solutions to this problem! To efficiently specify the parameters when creating Active Directory users (or using other PowerShell cmdlets) you have two excellent options:

  1. Splatting
  2. Creating Custom PSObjects

Splatting

Splatting is an excellent “trick” in PowerShell that essentially allows us to embed a set of parameter inputs into a hashtable that we can pass to our Command as parameter inputs.

PowerShell Document On Splatting

Splatting is a method of passing a collection of parameter values to a command as a unit. PowerShell associates each value in the collection with a command parameter.

Let’s apply this idea to an Active Directory object by creating a hashtable with all of our parameters and values for our New User:

$UserObject = @{
    firstName= "John"
    lastName = "Smith"
    displayName    = "John Smith"
    title = "The Boss"
    department = "The Boss Department"
}

Now that I have UserObject hashtable I can “Splat” this hashtable to my New-ADUser Command by specifying UserObject with @ instead of $.

New-AdUser @UserObject

PowerShell interprets this as New-AdUser @UserObject -firstName “John” -lastName “Smith” -displayName “John Smith” -title “The Boss” -department “The Boss Department” 

Now imagine how much easier this is to manage when using 50 parameters instead of 5 and you can quickly see how this allows us to keep our script more organized and adaptable!

PowerShell Custom Objects

A similar and equally viable method is instead of creating a plain hashtable to be splatted, we can create a Custom PowerShell Object using a hashtable and then pass the Object to the New-ADUser Command over the PowerShell pipeline.

The New-ADUser Command was explicitly built to handle having objects passed it over the pipeline so we can make use of this in our scripts.

First, let’s create a PowerShell object based on the same hashtable we used above in our splatting example.

$UserObject = [PSCustomObject]@{
    firstName= "John"
    lastName = "Smith"
    displayName    = "John Smith"
    title = "The Boss"
    department = "The Boss Department"
}

The setup to this method looks very similar to splatting. Still, instead of interpreting our hash table as parameters, we will simply pass the PowerShell object over the pipeline into our New-AdUser Command.

$UserObject | New-AdUser

NOTE Some AD Cmdlets might not accept objects from the pipeline, so make sure to check the documentation on the Cmdlet you are using first!

Both examples of Splatting and using a PSCustomObject will achieve the same result and are excellent choices for improving your Active Directory scripts!

Working without External Data Artifacts

The Case for CSV Files and External Artifacts

Probably one of the single most advantageous tricks when getting started with PowerShell for Active Directory is to become familiar with the import-CSV and export-CSV commands. These commands allow for the import of CSV files that, in turn, will let you take bulk actions with PowerShell. Likewise, the export command allows exporting Active Directory data to CSV files which is very useful for quickly creating reports.

Because of this simplicity, it is very easy for us the require the use of external artifacts in the form of CSV files in order to provide data to our PowerShell scripts. As an example, let’s assume we have a new Active Directory User script that takes a CSV file of first names and last names to populate users in an Active Directory Domain.

The Case Against CSV Files and External Artifacts

While no one can fault the use of CSV files or external data artifacts in general, I have found that, in some instances, it can limit the “portability” of your scripts. I have experienced several cases where I have tried to share scripts that required moderate to heavy CSV file editing to work across the environment. It’s very easy for me to deliver a script to a colleague or customer that can just be run immediately, but it becomes MUCH more complicated and error-prone when I start requiring properly formatted external artifacts.

Luckily, with PowerShell, we have some ways to work around this!

Internalize our Data

This is basically “Good”… “BAD” advice…while not necessarily a good “coding” practiced hardcoded or semi-dynamically including the data in our actual script, is sometimes a good idea! In this example, I can hard code a list of names into my PowerShell script instead of requiring a variety of CSV files providing me with a list of names or other details.

First, Let’s create a set of string arrays to populate a list of first names and last names:

$FirstNames = @("Alan","Arnold","Alexander","Anne","Anika","Bert","Betsy","Carl","Cynthia","David","Danielle")
$LastNames = @("Andel","Apel","Baros","Cernik","Danek","Filipek","Franel")

Using this configuration, instead of having an external artifact containing possible first and last names, I have instead hardcoded them into my script. This is a simple example but it is entirely possible to easily embed hundreds of values into a single array in my script. I can then even retrieve random values from the arrays by using the Get-Random Command in the following way:

$FirstNames | Get-Random

Again, while not necessarily the best practice for a production script, it can be beneficial for demo or training purposes.

For Active Directory scripting, I often find that variablizing my users, domains, and any other required data properties into a series of arrays, objects, or hashtables remove the need for external files.

This is an excellent technique for creating “demo” users or other resources in an Active Directory domain.

Retrieving Common Variables from Online Sources

Expanding upon the previous concept of not using external data files, this time instead of hard-coding values, let’s leverage the resources available to the information security community to retrieve data for us. The information security community at large has a vast number of publicly available resources available and we can use these to our advantages in our PowerShell script.

For our first examples, we’ll be using: SecLists Seclists is an excellent resource for anyone in Information Security, SecLists is: “a collection of multiple types of lists used during security assessments, collected in one place. List types include: usernames, passwords, URLs, sensitive data patterns, fuzzing payloads, web shells, and many more.”

Using the data in SecLists Github Repository and other online resources, we can retrieve lists of common first names, last names, locations, job titles and other items that may be nice to have in our scripts.

By cloning these repositories or merely using a Command like Invoke-WebRequest, we can retrieve the content for use in our scripts.

NOTE Ensure you review the content of the files you are downloading prior to using them in your environment and definitely do not use this in your production environment. This is really only safe for demo environments!

# Get Lists of Names and Titles From Github and Public Data Sets
$FirstNames = (Invoke-WebRequest -UseBasicParsing -Method Get -Uri 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Usernames/Names/names.txt' | Select-Object -ExpandProperty 'Content') -split '\n' 

$LastNames = (Invoke-WebRequest -UseBasicParsing -Method Get -Uri 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Usernames/Names/familynames-usa-top1000.txt' | Select-Object -ExpandProperty 'Content') -split '\n'

$JobTitles = (Invoke-WebRequest -UseBasicParsing -Method Get -Uri 'https://raw.githubusercontent.com/Stutern/job-titles/master/job-titles.csv' | Select-Object -ExpandProperty 'Content') -split '\n'

$Cities = ("Denver","Seattle","Los Angeles","San Diego","Las Vegas","Denver","Austin","Chicago","Madison","Minneapolis","Milwaukee","New York","Newark","Houston","Prague","Berlin","Basel","Frankfurt")

$Departments = ("Accounting","Sales","Human Resources","Information Technology","Executive","Consulting","Marketing","Retail")

Now we have a diverse set of resources we can use in our test/demo scripts without having to rely on artifact files alongside our scripts. By utilizing publicly available datasets, services, and APIs we can dynamically populate scripts with data as long as our script has access to these online resources.

Conclusions

This post contains a variety of PowerShell Tips and Tricks for Scripting Active Directory Test Environments based on some of my recent experiences. While many readers of this blog may not need to partake in the types of operations I am most-commonly performing; this hopefully should still serve to widen the reader’s knowledge and use of PowerShell.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Start a Free StealthAUDIT® Trial!

No risk. No obligation.