
close
close
Ready for some more PowerShell and ADSI fun? In the last article, I showed you how to create an Active Directory (AD) user account with ADSI and PowerShell. Of course, you probably want to put that user into a group or two. In fact, you might even like to manage groups with PowerShell. Let’s see how much we can cover today. As is usual with any series I do, I am assuming that you are caught up on the previous articles.
We will begin with a new user account.
[ADSI]$ken = "LDAP://CN=Ken Dew,OU=IT,OU=Departments,OU=Employees,DC=Globomantics,DC=local"
The MemberOf property, which will show groups that Ken belongs to is empty. The automatic Domain Users group is never shown.
Empty MemberOf Property (Image Credit: Jeff Hicks)
advertisment
[ADSI]$group = "LDAP://CN=Chicago IT,OU=Groups,OU=Employees,DC=Globomantics,DC=local"
The Member property shows the distinguishedname of each member.
Group Members (Image Credit: Jeff Hicks)
$group.Add($ken.ADSPath)
Refreshing the caches on the objects and re-checking membership shows that it was successful.
Adding a Group Member with PowerShell (Image Credit: Jeff Hicks)
advertisment
$group.remove($ken.ADSPath)
These methods are immediate and do not require running SetInfo().
I removed Ken because I wanted to show you an ADSI alternative. Using LDAP is nice but you need to know the exact path to the object. I will cover searching AD in another article. You can also use the WinNT moniker, which treats objects in a flatter fashion. The concepts and commands are similar.
[ADSI]$group = "WinNT://globomantics/Chicago IT,group" $group.Add("WinNT://globomantics/kdew,user")
Verifying the group membership with WinNT is a bit trickier.
$group.Invoke("Members").Foreach({$_.Gettype().InvokeMember("ADSPath","GetProperty",$null,$_,$null,$null)})
Group Members with WinNT (Image Credit: Jeff Hicks)
advertisment
Listing Group Members with ADSI (Image Credit: Jeff Hicks)
$group.member | foreach { [ADSI]$m = "LDAP://$_" $props = 'ADSPath','DistinguishedName','Name','Description','SchemaClassname' $h = [ordered]@{} foreach ($item in $props) { if ($m.$item -is [System.Collections.CollectionBase]) { $h.Add($item,$m.$item.value) } else { $h.Add($item,$m.$item) } } [pscustomobject]$h } | format-list
Enumerating Group Members with PowerShell (Image Credit: Jeff Hicks)
Function Get-GroupMember { [cmdletbinding()] Param([string]$ADSPath) [ADSI]$group = $ADSPath $group.member | foreach { [ADSI]$child = "LDAP://$_" if ($child.SchemaClassName -eq "group") { Get-GroupMember $child.ADSPath } else { $child | Select ADSPath,SchemaClassname } } }
The end result is a list of all non-group accounts because you could have a group with users or computers.
Enumerating Nested Group Membership (Image Credit: Jeff Hicks)
[ADSI]$OU = "LDAP://OU=Groups,OU=Employees,DC=globomantics,DC=local" $new = $ou.create("group","CN=ProjectX") $new.put("sAMAccountName", "ProjectX") $new.setinfo() $new.refreshcache()
By default, this will create a global security group.
A New Group (Image Credit: Jeff Hicks)
New-Variable ADS_GROUP_TYPE_SECURITY_ENABLED 0x80000000 -option constant
With this, I can test if the group is a security group or not.
Testing for a Security Group (Image Credit: Jeff Hicks)
$v = $new.groupType.value -bxor $ADS_GROUP_TYPE_SECURITY_ENABLED $new.put("grouptype",$v) $new.Setinfo()
Re-testing confirms the change.
Changing Group to a Distribution List (Image Credit: Jeff Hicks)
Function Get-GroupScope { [cmdletbinding()] Param([object]$Value) New-Variable ADS_GROUP_GLOBAL -Value 2 -Option Constant New-Variable ADS_GROUP_DOMAINLOCAL -Value 4 -Option Constant New-Variable ADS_GROUP_UNIVERSAL -Value 8 -Option Constant Write-Verbose "Evaluating $value" Switch ($value) { {($_ -band $ADS_GROUP_DOMAINLOCAL) -as [boolean] } { "DomainLocal" } {($_ -band $ADS_GROUP_GLOBAL) -as [boolean] } { "Global"} {($_ -band $ADS_GROUP_UNIVERSAL) -as [boolean] } { "Universal"}Default { Write-Warning "Unable to determine group scope."} } }
Getting Group Scope (Image Credit: Jeff Hicks)
Function Set-GroupScope { [cmdletbinding()] Param( [Parameter(Position = 0,Mandatory,ValueFromPipeline)] [ValidateNotNullorEmpty()] #an ADSI Group object [System.DirectoryServices.DirectoryEntry]$Group, [ValidateSet("DomainLocal","Global","Universal")] [string]$Scope = "Global", [switch]$AsDistribution ) Begin { New-Variable ADS_GROUP_GLOBAL -Value 2 -Option Constant New-Variable ADS_GROUP_DOMAINLOCAL -Value 4 -Option Constant New-Variable ADS_GROUP_UNIVERSAL -Value 8 -Option Constant New-Variable ADS_GROUP_TYPE_SECURITY_ENABLED 0x80000000 -option constant } #begin Process { Write-Verbose "Setting group scope for $($group.name)" $value = $group.groupType.value Write-Verbose "Evaluating $value" Switch ($Scope) { #create a temporary value "DomainLocal" { $tmp = $ADS_GROUP_DOMAINLOCAL } "Global" { $tmp = $ADS_GROUP_GLOBAL } "Universal" { $tmp = $ADS_GROUP_UNIVERSAL } } Write-Verbose "Setting value to $tmp" $group.put("grouptype",$tmp) $group.SetInfo() #Add Security setting unless specified AsDistribution if ($AsDistribution) { #no other change needed Write-Verbose "Group is now a distribution list" } else { Write-Verbose "Re-enabling as a security group" $group.RefreshCache() $group.put("grouptype",($group.groupType.value -bxor $ADS_GROUP_TYPE_SECURITY_ENABLED)) $group.SetInfo() } } #process End { #not used } }
To use this function, you will need an ADSI object for the group. I have been using $new. Right now, this is a global security group.
Getting Current Group Values (Image Credit: Jeff Hicks)
Modifying the Group Scope with PowerShell (Image Credit: Jeff Hicks)
More in PowerShell
Microsoft’s New PowerShell Crescendo Tool Facilitates Native Command-Line Wraps
Mar 21, 2022 | Rabia Noureen
Most popular on petri