Hi,
I have a script written in PowerShell that creates a report on AD in exactly the right format that I want. I need this script in order to replace another method of generating this report. The original method actually gathers almost twice as much data than the new script and it has been suggested to me that this is because this new script does not search recursively. Can anyone help me to change this script so that it looks recursively? It has also been suggested to me that i might need the LDAP filter (1.2.840.113556.1.4.1941).
However I have tried using this line, just before the line containing "subtree":
$searcher.Filter = "(member:1.2.840.113556.1.4.1941:=*)"and tried editing this line:
$searcher = [ADSISearcher] "(objectClass=group)"to this
$searcher = [ADSISearcher] "(&(objectClass=group)(memberof:1.2.840.113556.1.4.1941L:=*))"Neither work, it just returns immediately with no output, presumably as the filter is not picking up anything. I didn't have a filter before because I wanted everything
Here is my code:
#requires -version 2
$ScriptName = $MyInvocation.MyCommand.Name
$ADS_GROUP_TYPE_SECURITY_ENABLED = 0x80000000
$PageSize = 250 # Adjust as needed
# Create the Pathname object and enable its EscapedMode property
$ADS_ESCAPEDMODE_ON = 2
$ADS_SETTYPE_DN = 4
$ADS_FORMAT_X500_DN = 7
$Pathname = new-object -comobject "Pathname"
[Void] $Pathname.GetType().InvokeMember("EscapedMode", "SetProperty", $NULL, $Pathname, $ADS_ESCAPEDMODE_ON)
# Returns correctly escaped DN using Pathname object
function Get-EscapedPath {
param(
[String] $distinguishedName
)
[Void] $Pathname.GetType().InvokeMember("Set", "InvokeMethod", $NULL, $Pathname, ($distinguishedName, $ADS_SETTYPE_DN))
$Pathname.GetType().InvokeMember("Retrieve", "InvokeMethod", $NULL, $Pathname, $ADS_FORMAT_X500_DN)
}
# Returns a property from a ResultPropertyCollection if it's defined
function Get-SearchResultProperty {
param(
[System.DirectoryServices.ResultPropertyCollection] $properties,
[String] $propertyName
)
if ( $properties[$propertyName] ) {
$properties[$propertyName][0]
}
else {""
}
}
# Returns a property from a DirectoryEntry if it's defined
function Get-DirEntryProperty {
param(
[System.DirectoryServices.DirectoryEntry] $dirEntry,
[String] $propertyName
)
if ( $dirEntry.$propertyName ) {
$dirEntry.$propertyName[0]
}
else {
""
}
}
write-progress $ScriptName "Enumerating groups"
$domain = [ADSI] ""
$searcher = [ADSISearcher] "(objectClass=group)"
$searcher.SearchRoot = $domain
$searcher.PageSize = $PageSize
$searcher.SearchScope = "subtree";
$searcher.PropertiesToLoad.AddRange(@("name","grouptype","distinguishedname","description","managedby","member"))
$searchResults = $searcher.FindAll()
$groupCounter = 0
$groupCount = $searchResults.Count
foreach ( $searchResult in $searchResults ) {
$properties = $searchResult.Properties
$domainName = "domainname"
$groupName = Get-SearchResultProperty $properties "name"
$groupType = Get-SearchResultProperty $properties "grouptype"
if ( ($groupType -band $ADS_GROUP_TYPE_SECURITY_ENABLED) -ne 0 ) {
$groupTypeString = "Security"
}
else {
$groupTypeString = "Distribution"
}
$groupDescription = Get-SearchResultProperty $properties "description"
$groupDN = Get-SearchResultProperty $properties "distinguishedname"
$groupManagedBy = Get-SearchResultProperty $properties "managedby"
$member = $properties["member"]
if ( $member ) {
$memberCounter = 0
$memberCount = ($member | measure-object).Count
foreach ( $memberDN in $member ) {
$memberDirEntry = [ADSI] "LDAP://$(Get-EscapedPath $memberDN)""" | select-object `
@{Name = "Domain"; Expression = {$domainName}},
@{Name = "Group Name"; Expression = {$groupName}},
@{Name = "Type"; Expression = {$groupTypeString}},
@{Name = "Description"; Expression = {$groupDescription}},
@{Name = "Distinguished Name"; Expression = {$groupDN}},
@{Name = "Managed By"; Expression = {$groupManagedBy}},
@{Name = "Members"; Expression = {$memberDN}},
@{Name = "Full Name"; Expression = {Get-DirEntryProperty $memberDirEntry "name"}},
@{Name = "User Name"; Expression = {Get-DirEntryProperty $memberDirEntry "samaccountname"}},
@{Name = "Display Name"; Expression = {Get-DirEntryProperty $memberDirEntry "displayname"}}
$memberCounter++
$memberPercent = ($memberCounter / $memberCount) * 100 -as [Int]
$params = @{"Activity" = $ScriptName"Completed" = $memberPercent -eq 100"CurrentOperation" = "Enumerating '$groupDN'""PercentComplete" = $memberPercent"Status" = "Groups: {0}/{1} [{2:P2}] - Members: {3}/{4} [{5:P2}]" -f
$groupCounter,
$groupCount,
($groupCounter / $groupCount),
$memberCounter,
$memberCount,
($memberCounter / $memberCount)
}
write-progress @params
}
}
else {
# Group contains no members"" | select-object `
@{Name = "Domain"; Expression = {$domainName}},
@{Name = "Group Name"; Expression = {$groupName}},
@{Name = "Type"; Expression = {$groupTypeString}},
@{Name = "Description"; Expression = {$groupDescription}},
@{Name = "Distinguished Name"; Expression = {$groupDN}},
@{Name = "Managed By"; Expression = {$groupManagedBy}},
@{Name = "Members"; Expression = {""}},
@{Name = "Full Name"; Expression = {""}},
@{Name = "User Name"; Expression = {""}},
@{Name = "Display Name"; Expression = {""}}
}
$groupCounter++
$groupPercent = ($groupCounter / $groupCount) * 100 -as [Int]
$params = @{"Activity" = $ScriptName"Completed" = $groupPercent -eq 100"CurrentOperation" = "Enumerating '$groupDN'""PercentComplete" = $groupPercent"Status" = "Groups: {0}/{1} [{2:P2}]" -f
$groupCounter,
$groupCount,
($groupCounter / $groupCount)
}
write-progress @params
# Periodically force garbage collection to reduce memory usage
if ( ($groupCounter % $PageSize) -eq 0 ) {
[GC]::Collect()
[GC]::WaitForPendingFinalizers()
}
}
$searchResults.Dispose()