One of the most popular targets for PowerShell management is Active Directory. While we may be moving to a post-AD world, it will be a while before you no longer need to deal with users, groups, and computers in Active Directory. Certainly, the easiest approach is to use the Active Directory module. You can get this by installing the latest version of Remote Server Administration Tools (RSAT). There may be situations, however, where you do not have access to those tools. There also may be times you want to build a customized toolset that doesn’t rely on the module. PowerShell is all about having options. I thought I would spend some time over the next several articles on how to manage Active Directory with alternate methods.

It is probably a safe bet that there is an entirely new generation of IT Pros who have never been exposed to VBScript and other “old school” techniques. Sometimes those old school ways still have value. For Active Directory, one such tool is the ADSI accelerator. ADSI used to be the only way to connect and manage directory services. You should consider it a legacy technique. ADSI communicates with domain controllers over TCP port 389. Keep in mind, this might not work with cloud-based servers.

It is very easy to make an ADSI connection to a domain. You won’t even need to specify a domain controller.



1 2 3 4 $domainname = "globomantics" #or use $env:userdomain #connect to the $domain [ ADSI ] $domain = "WinNT://$domainname"



One very important thing to keep in mind, the ADSI accelerator is not case-sensitive. The WinNT moniker is case-sensitive.

The object isn’t especially rich (once you use the correct moniker).

And using the properties isn’t exactly obvious.

First, properties are returned as arrays. This requires some extra work to improve readability.



1 2 3 4 $domain | Select @ { Name = "Name" ; Expression = { $_ . name . value } } , @ { Name = "PwdHistory" ; Expression = { $_ . PasswordHistoryLength . value } } , @ { Name = "MinPasswordAge" ; Expression = { $_ . MinPasswordAge . value } } , @ { Name = "MaxPasswordAge" ; Expression = { $_ . MaxPasswordAge . value } }





You also may need to do some research to understand values. For example, the password age properties are given in seconds. Therefore, this might help to make it more meaningful.



1 2 3 4 $domain | Select @ { Name = "Name" ; Expression = { $_ . name . value } } , @ { Name = "PwdHistory" ; Expression = { $_ . PasswordHistoryLength . value } } , @ { Name = "MinPasswordAge" ; Expression = { New-Timespan -seconds $_ . MinPasswordAge . value } } , @ { Name = "MaxPasswordAge" ; Expression = { New-Timespan -seconds $_ . MaxPasswordAge . value } }





We will be using these techniques repeatedly.

The last part of the domain object I want to touch on is children. While ADSI is somewhat hierarchical, the WinNT moniker doesn’t expose the Active Directory objects in organizational units. But you can still get access to the objects in the domain through the Children property.

Subscribe to Petri Newsletters Office 365 Insider Our Petri Office 365 Insider is dedicated to sharing detailed knowledge from top Office 365 experts. Delivered once a month to your inbox. All Newsletters Petri.com may use your contact information to provide updates, offers and resources that may be of interest to you. You can unsubscribe at any time. To learn more about how we manage your data, you can read our Privacy Policy and Terms of Service. !Already a Petri.com member? Login here for 1-click registration.

This value includes all objects. Separating them out takes a little work because you need to use each child’s object schemaclassname property.



1 $domain . children | group { $_ . schemaclassname }





If you need to select a certain type, you can use a command like this:



1 $g = ( $domain . children ) . Where ( { $_ . schemaclassname -eq 'group' } )



As before, you need to massage the objects a bit to produce reader-friendly output.



1 2 3 4 5 6 7 8 9 10 $g | Select @ { Name = "Name" ; Expression = { $_ . name . value } } , @ { Name = "Description" ; Expression = { $_ . Description . value } } , @ { Name = "Type" ; Expression = { switch ( $_ . grouptype . value ) { "2" { "Global" } "4" { "DomainLocal" } "8" { "Universal" } } } } , Path | Out-Gridview



And even though I’m showing the de-code for a universal group, using WinNT doesn’t always identify those groups. In my case, I have universal groups but ADSI reports them as global groups.

You can do something similar with user accounts:



1 2 3 4 5 $u = ( $domain . children ) . Where ( { $_ . schemaclassname -eq 'user' } ) $u [ 0 . . 49 ] | Select @ { Name = "Name" ; Expression = { $_ . name . value } } , @ { Name = "FullName" ; Expression = { $_ . fullname . value } } , @ { Name = "Description" ; Expression = { $_ . Description . value } }





Again, everything exposed through WinNT is very simple. But it can be quick to access. You don’t need to know where the object lives in AD, just its name or ADSI path.

We are just scratching the surface here. There is so much more I want to get into. Next time we’ll dig a bit more into using ADSI and we will begin exploring LDAP.