Tag Archives: AD

Get Active Directory (Sites and Services) Subnets

I just started reading chapter 16 — Managing sites and subnets — in Richard Siddaway‘s book Learn Active Directory in a Month of Lunches. I already know a good deal about Active Directory (AD). I’ve been using and supporting it, in one fashion or another, since its introduction in 2000. Even so, that didn’t stop me from picking up this title. I’ll buy and read a book about a topic I already know, even if I’m only going to pick up a few new details. I also like to remind myself of things I already know, in an effort to keep things as fresh as possible in my mind. I’ve also found myself curious about other people’s writing styles. Since I’ve been writing and posting here, for coming up on a year and a half, I believe that my writing has improved, and it makes me eager to read other people’s writings, too.

I went a little off topic there, but anyway, I read a couple pages of the chapter, and then typed the command below into my Windows PowerShell console. This was in an effort to determine the subnets used by an AD site, before reading any further.

PS> (Get-ADReplicationSite -Identity Downtown02 -Properties Subnets).Subnets.ForEach{$_.Split(',',2)[0].Split('=')[-1]}
10.115.0.0/16
10.122.0.0/15
10.140.0.0/16

So what’s happening here? By default, the Active Directory Get-ADReplicationSite cmdlet returns information about your (computer’s) AD site; however, you can filter the results to get information about another AD site, or even, all the AD sites. In my example, I’ve indicated that I only want information about a single site, Downtown02. Although you don’t see it in the default properties that are returned by this cmdlet, there are extended properties returned when the -Properties parameter is included. This behavior is similar to some of the other AD cmdlets. In fact, you can see which AD cmdlets have a -Properties parameter by enter this: Get-Command -Module ActiveDirectory -ParameterName Properties. In our example, we are only returning the Subnets property, not all of the properties, as we would when using -Properties *.

The Subnet property is returned as a Distinguished Name, such as: CN=10.115.0.0/16,CN=Subnets,CN=Sites,CN=Configuration,DC=mydomain,DC=com. Due to this, I’ve added the .Split() method, twice. The first time it was used, we split at the comma and returned two pieces of our string, when it’s entered as .Split(‘,’,2). That’s difficult to explain, so here’s what that looks like:

PS> (Get-ADReplicationSite -Identity Downtown02 -Properties Subnets).Subnets.ForEach{$_.Split(',',2)}
CN=10.115.0.0/16
CN=Subnets,CN=Sites,CN=Configuration,DC=catnet,DC=mydomain,DC=com
CN=10.122.0.0/15
CN=Subnets,CN=Sites,CN=Configuration,DC=catnet,DC=mydomain,DC=com
CN=10.140.0.0/16
CN=Subnets,CN=Sites,CN=Configuration,DC=catnet,DC=mydomain,DC=com

In the example above, notice it only split at the first comma in the string. That’s what the 2 does (“leave me 2 sections”). Adding the [0] index, below, only keeps the first element of the results of each split.

PS> (Get-ADReplicationSite -Identity Downtown02 -Properties Subnets).Subnets.ForEach{$_.Split(',',2)[0]}
CN=10.115.0.0/16
CN=10.122.0.0/15
CN=10.140.0.0/16

The second time we use the .Split() method, we split at the equal sign and return the last element, like so: .Split(‘=’)[-1]. After these two .Split() methods have run, we have our subnets, just like we’d see them in the Name category, of the Active Directory Sites and Services MMC. I should mention the syntax in this command. Take a closer look, if you haven’t already: It’s using the ForEach method, not the ForEach-Object cmdlet, as you might have expected to see. This syntax became possible in PowerShell 4.0.

Okay, so I’ve mentioned this a time or two, now. I often learn something new, share it here, and then I find a better way. Sometime, while I’m still writing. Well, that happened again. We don’t need to get fancy with the results of Get-ADReplicationSite as we have above, and can instead, use the Get-ADReplicationSubnet cmdlet. How’d I find the cmdlet? Well, (while writing), I decided to search for the string “subnet” in all the cmdlet names from the ActiveDirectory module: Get-Command -Module ActiveDirectory -Name *subnet*. Here’s the command to use to return the same information we did with the first example in this post.

PS> (Get-ADReplicationSubnet -Filter * -Properties Site | Where-Object Site -like '*Downtown02*').Name
10.115.0.0/16
10.122.0.0/15
10.140.0.0/16

If you’re wondering why I didn’t use the -Filter parameter to filter on the site, well then, here you go. Here’s a quicker and more efficient method in which to write the command.

PS> (Get-ADReplicationSubnet -Filter {Site -eq 'Downtown02'}).Name
10.115.0.0/16
10.122.0.0/15
10.140.0.0/16

Thanks for joining me, and now back to my reading.

Report on Active Directory Objects in Abandoned Organizational Unit

Before we really start this post, I should mentioned that there’s no reason that the script discussed in this post can’t be run against an Organizational Unit (OU) that hasn’t been abandoned. It just worked out that I wrote the script in order to determine if an OU had be abandoned.

I threw a small script together in the last couple days and thought I’d share it. The reason for the script was because I may have had an Active Directory (AD) OU that was no longer being used. In order to determine if this was really the case, I wanted to check various properties on the user and computer objects in the OU, to include any nested OUs. These properties included the last logon time stamp, the last date the objects changed, and a few others.

The first couple of lines in the script set two different variables. The first one stores the Domain’s Distinguished Name, and the second one is assigned the location of the abandoned OU. The second variable is based partly on the first. This script requires the ActiveDirectory module and assumes it’s being run on PowerShell 3.0 or greater, as the AD module isn’t explicitly imported.

$DomainDN = ((Get-ADDomain).DistinguishedName)
$AbandonedOU = Get-ADObject -Filter * -SearchBase "OU=Finance,OU=Departments,$DomainDN"

In the next part of the script, we start to send the $AbandonedOU variable’s objects across the pipeline, to the Foreach-Object cmdlet. As each object passes across, we determine what type of AD object we’re dealing with. If it’s a user object, we set the $Command variable to the string, Get-ADUser. If it’s a computer object we set the $Command variable to the string, Get-ADComputer. If it’s neither, such as a nested OU, we’ll return to the $AbandonedOU variable and send the next object without assigning anything to the $Command variable (or running any of the upcoming code).

$AbandonedOU | ForEach-Object {
    If ($_.ObjectClass -eq 'user') {
        $Command = 'Get-ADUser'
    } ElseIf ($_.ObjectClass -eq 'computer') {
        $Command = 'Get-ADComputer'
    } Else {
        return
    }

Providing we have a user or computer AD object, we’ll run the code in the next example. This will execute the cmdlet, whether it be Get-ADUser or Get-ADComputer, returning the requested properties that we then calculate (think, customize).

    & $Command -Identity $_ -Properties * |
        Select-Object Name,
            @{N='Type';E={$_.ObjectClass}},
            @{N='Created';E={$_.whenCreated}},
            @{N='Last Logon TimeStamp';E={[datetime]::FromFileTime($_.LastLogonTimeStamp)}},
            @{N='Changed';E={$_.whenChanged}},
            @{N='Added To Domain By';E={$_.nTSecurityDescriptor.Owner}}
}

Finally, we sort the collection of objects we’ve returned and customized, and in my case, pump the data out to a CSV file at the root of my C:\ drive. As you’ll see below, I’ve included both the code in the previous example and the additional code.

    & $Command -Identity $_ -Properties * |
        Select-Object Name,
            @{N='Type';E={$_.ObjectClass}},
            @{N='Created';E={$_.whenCreated}},
            @{N='Last Logon TimeStamp';E={[datetime]::FromFileTime($_.LastLogonTimeStamp)}},
            @{N='Changed';E={$_.whenChanged}},
            @{N='Added To Domain By';E={$_.nTSecurityDescriptor.Owner}}
} | Sort-Object 'Last Logon TimeStamp' -Descending | Export-Csv -Path C:\AbandonedOU.csv -NoTypeInformation

I want to mention something about the line above that calculates the “Added To Domain By” property. In many environments this is going to only be <DOMAIN>\Domain Admins. The reason I added this, is because in the AD environment in which this ran, users, other than the Domain Admins, can join computers. I know this is a default; however, in many environments it is not allowed. This may or may not be a helpful property in your environment.

Cheers, and thanks for reading! I’ve included the complete script below.

$DomainDN = ((Get-ADDomain).DistinguishedName)
$AbandonedOU = Get-ADObject -Filter * -SearchBase "OU=Finance,OU=Departments,$DomainDN"

$AbandonedOU | ForEach-Object {
    If ($_.ObjectClass -eq 'user') {
        $Command = 'Get-ADUser'
    } ElseIf ($_.ObjectClass -eq 'computer') {
        $Command = 'Get-ADComputer'
    } Else {
        return
    }

    & $Command -Identity $_ -Properties * |
        Select-Object Name,
            @{N='Type';E={$_.ObjectClass}},
            @{N='Created';E={$_.whenCreated}},
            @{N='Last Logon TimeStamp';E={[datetime]::FromFileTime($_.LastLogonTimeStamp)}},
            @{N='Changed';E={$_.whenChanged}},
            @{N='Added To Domain By';E={$_.nTSecurityDescriptor.Owner}}
} | Sort-Object 'Last Logon TimeStamp' -Descending | Export-Csv -Path C:\AbandonedOU.csv -NoTypeInformation