PopulateADgroupFromLDAPfilter.ps1
<#PSScriptInfo
.VERSION 1.0.1 .GUID 68d2ca31-4f91-4914-a5ff-60c50445236f .AUTHOR Jack Olsson .COMPANYNAME .COPYRIGHT .TAGS .LICENSEURI .PROJECTURI https://github.com/jaols/PSJumpStart .ICONURI .EXTERNALMODULEDEPENDENCIES ActiveDirectory .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES #> #Requires -Module PSJumpStart <# .SYNOPSIS Populate group members for a group from LDAPfilter .DESCRIPTION The script will search for principals (AD-objects) in AD according to LDAP-filter, then add any missing principals AND remove extra principals If -WhatIf switch is used you will see information on actions but NO ACTION WILL TAKE PLACE. Use the standard flag -Verbose to get extended information on execution. Use the CMD-file to launch as a scheduled task. Log informaiton is written to std out as the CMD will redirect this to a log-file. .PARAMETER TargetGroup The group name to populate members for .PARAMETER LDAPfilter Search filter to use for finding users .PARAMETER searchRootOU Root OU-path for search. .PARAMETER ADserver Default AD server to use for operations .EXAMPLE NAME -TargetGroup ALLUsers -LDAPfilter "(&(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2))" Set all enabled users as member of the group ALLUsers .EXAMPLE NAME -TargetGroup "MailUsers" -LDAPfilter "(&(objectCategory=person)(objectClass=user)(mail=*)(!userAccountControl:1.2.840.113556.1.4.803:=2))" Set all enabled users WITH a mail address as member of the group MailUsers. .EXAMPLE NAME -TargetGroup AutoEnroll_MachineCertificate -LDAPfilter "(&(objectCategory=computer)(departmentNumber=*))" Set all computers with the departmentNumber attribute set as member of AutoEnroll_MachineCertificate .NOTES You may want to use dfp files for default values. If so you need to remove the Mandatory flags in the script parameter list. Author: Jack Olsson Date: 2018-07-24 Changelog: 2018-08-01 Added support for retreiving ADserver if not set Moved default setting from param to code.. #> [CmdletBinding(SupportsShouldProcess = $True)] param ( [Parameter(Mandatory=$true)] [string]$TargetGroup, [Parameter(Mandatory=$true)] [string]$LDAPfilter, [string]$searchRootOU, [string]$ADserver ) #region local functions function GetLocalDefaultsFromDfpFiles($CallerInvocation) { #Load script default settings foreach($settingsFile in (Get-SettingsFiles $CallerInvocation ".dfp")) { Write-Verbose "GetLocalDefaultsFromDfpFiles: [$settingsFile]" if (Test-Path $settingsFile) { $settings = Get-Content $settingsFile #Enumerate settingsfile rows foreach($row in $settings) { #Remarked lines are not processed if (($row -match "=") -and ($row.Trim().SubString(0,1) -ne "#")) { $key = $row.Split('=')[0] $var = Get-Variable $key -ErrorAction SilentlyContinue if ($var -and !($var.Value)) { try { $var.Value = Invoke-Expression $row.SubString($key.Length+1) Write-Verbose "GetLocalDefaultsFromDfpFiles: $key = $($var.Value)" } Catch { $ex = $PSItem $ex.ErrorDetails = "Err adding $key from $settingsFile. " + $PSItem.Exception.Message throw $ex } } } } } } } #endregion #region Init if (-not (Get-Module ActiveDirectory)) { Import-Module ActiveDirectory } if (-not (Get-Module PSJumpStart)) { Import-Module PSJumpStart } #Get Local variable default values from external DFP-files GetLocalDefaultsFromDfpFiles($MyInvocation) #Get global deafult settings when calling modules $PSDefaultParameterValues = Get-GlobalDefaultsFromDfpFiles $MyInvocation -Verbose:$VerbosePreference #endregion Msg "Start Execution" #Get default OU if not used in dfp files or arguments if ([string]::IsNullOrEmpty($ADserver)) { $searchRootOU = ([adsi]"LDAP://rootdse").defaultNamingContext } #Get ADserver to run ALL operations if ([string]::IsNullOrEmpty($ADserver)) { $ADserver = (Get-ADDomainController ).Name } Write-Verbose "Get current members for $TargetGroup" $currentMembers = Get-ADGroupMember -Identity $TargetGroup -Server $ADserver if ([string]::IsNullOrEmpty($currentMembers)) { Msg "Group has no members" $currentMembers=@() } else { Msg "Group has $($currentMembers.Count) current members" } Write-Verbose "Extract users in $searchRootOU using $LDAPfilter" $members = Get-ADObject -LDAPFilter $LDAPfilter -SearchBase $searchRootOU -Server $ADserver Msg "Found $($members.Count) members from query" $newMembers = @() foreach($member in $members) { $isMember = $false foreach($current in $currentMembers) { if ($member.ObjectGUID -eq $current.ObjectGUID) { $isMember = $true } } if (!$isMember) { Write-Verbose("Add new member: " + $member.DistinguishedName) $newMembers += ($member.ObjectGUID).ToString() #$newMembers += $member.DistinguishedName } } if ($newMembers.Count -gt 0) { Msg "Set $($newMembers.Count) new members" if ($pscmdlet.ShouldProcess($TargetGroup,"Add-ADGroupMember")) { Add-ADGroupMember -Identity $TargetGroup -Members $newMembers -Server $ADserver } } $removeMembers = @() foreach($current in $currentMembers) { $remove = $true foreach($member in $members) { if ($member.ObjectGUID -eq $current.ObjectGUID) { $remove = $false } } if ($remove) { Write-Verbose("Remove member: " + $current.DistinguishedName) $removeMembers += $($current.DistinguishedName) } } if ($removeMembers.Count -gt 0) { Msg "Remove $($removeMembers.Count) members" if ($pscmdlet.ShouldProcess($TargetGroup,"Remove-ADGroupMember")) { Remove-ADGroupMember -Identity $TargetGroup -Members $removeMembers -Confirm:$false } } Msg "End Execution" |