cls
#####################################
### Domain Administration with .NET ###
### 2012 ###
#####################################
# These scripts must run with domain administrator credentials.
# Although the DirectoryEntry constructor can take a username
# and password, ADSI uses the current "logged on" credentials.
#region DirectoryEntry objects
# The .NET framework provides a DirectoryEntry class that is used to
# access directory objects including users, groups, OUs, the domain root, etc.
$directoryEntry = New-Object System.DirectoryServices.DirectoryEntry("LDAP://CN=Jared Deckard,OU=GroupName,OU=Users and Groups,DC=domain,DC=com")
# The following line is functionally identical, but casts the path string to a DirectoryEntry
# instead of explicitly creating a new object with the class constructor.
$directoryEntry = [adsi] "LDAP://CN=Jared Deckard,OU=GroupName,OU=Users and Groups,DC=domain,DC=com"
# Note: Creating a DirectoryEntry requires downloading all the objects properties from the
# server and should only be used when the object needs to be modified. The collection returned
# by a search will contain a read-only copy of these properties, but is much faster than
# creating a new DirectoryEntry.
# Any changes made to a DirectoryEntry must be committed to the server with CommitChanges()
$directoryEntry.CommitChanges()
#endregion
#region Setup a directory search
# Create a .NET DirectoryEntry that connects to the domain root using the current credentials
$domainRoot = [adsi] "LDAP://dc=domain,dc=com"
# Create a .NET DirectorySearcher
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.PageSize = 1000 # Limit PageSize to process results 1000 at a time
$objSearcher.SearchScope = "Subtree" # Allows search to traverse child nodes
# Limit the properties to only those needed to speed up the search
$objSearcher.PropertiesToLoad.Clear()
$objSearcher.PropertiesToLoad.Add("cn") | Out-Null
$objSearcher.PropertiesToLoad.Add("member") | Out-Null
# Start searching at the domain root
$objSearcher.SearchRoot = $domainRoot
#endregion
#region Search for users
# Sample user info
$filterBy = "name"
$first = ""
$last = "deck"
# Create a user filter with wild cards for partial matches
$objSearcher.Filter = "(&(objectCategory=User)($filterBy=$first* $last*))"
# Get a collection of matching results
$userResults = $objSearcher.FindAll()
#endregion
#region Process user search results
if($userResults.Count -lt 1) # Process no results
{
Write-Host "No matches found in $($domainRoot.name)" -ForegroundColor Red
}
if($userResults.Count -eq 1) # Process one result
{
# Resolve user path to a full DirectoryEntry object
$FullUserEntry = [adsi] $userResults[0].Path
Write-Host "$($FullUserEntry.name)" -BackgroundColor Green
}
if($userResults.Count -gt 1) # Process many results
{
Write-Host "User matches: "
foreach($UserEntry in $userResults){ Write-Host "$($UserEntry.Properties.cn)" -ForegroundColor Blue }
}
Write-Host ""
#endregion
#region Search for groups
# Sample group name from company name
$Company = "*"
$GroupName = "sec-glb-$Company Users"
# Get group from AD
$objSearcher.Filter = "(&(objectCategory=group)(name=$GroupName))"
$groupResults = $objSearcher.FindAll()
#endregion
#region Process group search results
# Process no results
if($groupResults.Count -lt 1)
{
Write-Host "No matches found in $($domainRoot.name)" -ForegroundColor Red
}
# Process one result
if($groupResults.Count -eq 1)
{
$groupEntry = $groupResults[0]
Write-Host "$($groupEntry.Properties.cn)" -BackgroundColor Green
# Loop over each group member
foreach($UserDN in $groupEntry.Properties.member)
{
# Resolve user DN to a full DirectoryEntry object
$fullUser = [adsi] "LDAP://$UserDN"
Write-Host "+ $($fullUser.name)" -ForegroundColor Blue
}
}
# Process many results
if($groupResults.Count -gt 1)
{
Write-Host "Group matches: "
# Loop over each group
foreach($groupEntry in $groupResults)
{
Write-Host "$($groupEntry.Properties.cn)" -ForegroundColor Blue
# Loop over each group member
foreach($User in $groupEntry.Properties.member){ Write-Host "- $User" -ForegroundColor DarkGray }
}
}
Write-Host ""
#endregion
#region Adding users to a group
# Only the user path (DN) is required to add a user to a group, avoid resolving to DirectoryEntry if possible
$UserPath = "LDAP://CN=Jared Deckard,OU=GroupName,OU=Users and Groups,DC=domain,DC=com"
# The group path must be resolved to a DirectoryEntry to expose the object methods
$GroupPath = "LDAP://CN=sec-glb-ComapanyName,OU=Users and Groups,DC=domain,DC=com"
$FullGroup = [adsi] $GroupPath
try # Exceptions can be thrown for many reasons
{
# Add the user path to the group object's member list
$FullGroup.add($UserPath) | Out-Null
# Commit any changes made to the group object to the domain
$FullGroup.CommitChanges()
# User added successfully
Write-Host "$UserPath added to $GroupPath" -BackgroundColor Green
}
catch # Catch errors to gracefully continue execution
{
# The add should throw an exception because I am already a member of the group
Write-Host $Error[0] -ForegroundColor Red
}
#endregion
#region Creating objects
# Sample object
$ObjectType = "group"
$ObjectName = "tst-PS-ADSI-Example"
try # Always catch exceptions when trying to make changes to the directory
{
# Objects must be created in an existing OU
$ParentOU = [adsi] "LDAP://OU=Users and Groups,dc=domain,dc=com"
# Create a new object in a parent OU
$NewObject = $ParentOU.Create("$ObjectType", "CN=$ObjectName")
# Required attributes may need to be set before the object can be created
# Default values will be used if they are specified by the domain
$NewObject.Put("sAMAccountName", "$ObjectName");
$NewObject.Put("groupType", "-2147483646");
# Commit the changes to the new object
$NewObject.CommitChanges()
# Object created successfully
Write-Host "$ObjectName created successfully" -BackgroundColor Green
}
catch{ Write-Host $Error[0] -ForegroundColor Red }
#endregion
#region Deleting objects
try
{
# The Delete method removes an object from the parent OU
# The change is automatically committed to the domain
$ParentOU.Delete("$ObjectType", "CN=$ObjectName")
# Object deleted successfully
Write-Host "$ObjectName deleted successfully" -BackgroundColor Green
}
catch{ Write-Host $Error[0] -ForegroundColor Red }
#endregion
#region Resources
# http://social.technet.microsoft.com/wiki/contents/articles/4231.working-with-active-directory-using-powershell-adsi-adapter-en-us.aspx
# http://msdn.microsoft.com/en-us/library/system.directoryservices.directoryentry.aspx
#endregion
#region Notes
#####################################
# Created 07/31/12 by Jared Deckard #
#####################################
#region Change Log
# Added "DirectoryEntry objects" - 07/31/12 JD
# Added "Setup a directory search" - 07/31/12 JD
# Added "Search for users" - 07/31/12 JD
# Added "Process user search results" - 07/31/12 JD
# Added "Search for groups" - 07/31/12 JD
# Added "Process group search results" - 07/31/12 JD
# Added "Adding users to a group" - 07/31/12 JD
# Added "Creating objects" - 07/31/12 JD
# Added "Deleting objects" - 07/31/12 JD
# Added "Resources" - 08/02/12 JD
# Changed SetInfo() to CommitChanges() - 08/02/12 JD
#endregion
#endregion