fireguy1125
asked on
Synchronize/Mirror AD Security Group Membership Script
I need to synchronize group membership for several AD security groups. I was able to put together a script that will add any new group members from the source security group to the destination security group, however, I also need to be able to have the script remove members from the destination security group, when they are removed from the source. How can I modify this script to achieve this?
Thank you in advance.
$source = Get-ADGroupMember -Identity SourceADGroup
foreach ($user in $source) {
Add-ADGroupMember -Identity DestADGroup -Members $user.distinguishedname
}
Thank you in advance.
ASKER
Thank you, where would I specify the source and destination group? Am I just replacing [PSObject] in lines 3 and 4?
No. It's a complete script accepting arguments.
.\Copy-ADGroupMember.ps1 -Identity SourceADGroup -Destination DestADGroup -Mirror -WhatIf
If you really want to hard code that, make a function out of it and call the function:
.\Copy-ADGroupMember.ps1 -Identity SourceADGroup -Destination DestADGroup -Mirror -WhatIf
If you really want to hard code that, make a function out of it and call the function:
Function Copy-ADGroupMember {
[CmdletBinding(SupportsShouldProcess=$True, ConfirmImpact='High')]
Param(
[Parameter(ValueFromPipeline=$True, Position=0)]
[PSObject]$Identity,
[PSObject]$Destination,
[Switch]$Mirror
)
$SourceMembers = Get-ADGroupMember -Identity $Identity | Select-Object -ExpandProperty distinguishedName
$TargetMembers = Get-ADGroupMember -Identity $Destination | Select-Object -ExpandProperty distinguishedName
$DifferenceMembers = Compare-Object -ReferenceObject $SourceMembers -DifferenceObject $TargetMembers
$ProcessMembers = $DifferenceMembers | Where-Object {$_.SideIndicator -eq '<='} | Select-Object -ExpandProperty InputObject
If ($PSCmdlet.ShouldProcess($Destination, "Add objects:`r`n`t$($ProcessMembers -join "`r`n`t")`r`n")) {
Add-ADGroupMember -Identity $Destination -Members $ProcessMembers
}
If ($Mirror) {
$ProcessMembers = $DifferenceMembers | Where-Object {$_.SideIndicator -eq '=>'} | Select-Object -ExpandProperty InputObject
If ($PSCmdlet.ShouldProcess($Destination, "Remove objects:`r`n`t$($ProcessMembers -join "`r`n`t")`r`n")) {
Remove-ADGroupMember -Identity $Destination -Members $ProcessMembers
}
}
}
.\Copy-ADGroupMember.ps1 -Identity SourceADGroup -Destination DestADGroup -Mirror -WhatIf
ASKER
Thank you. The script seems to work, but throws errors. Can these be suppressed?
PS C:\scripts> .\Copy-ADGroupMember.ps1 -Identity SourceADGroup -Destination DestDL -Mirror -Confirm:$False
Remove-ADGroupMember : Cannot validate argument on parameter 'Members'. The argument is null or empty. Provide an
argument that is not null or empty, and then try the command again.
At C:\scripts\Copy-ADGroupMem ber.ps1:17 char:56
+ ... Remove-ADGroupMember -Identity $Destination -Members $ProcessMembers
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Remove-ADGroupMember], ParameterBindingValidation Exception
+ FullyQualifiedErrorId : ParameterArgumentValidatio nError,Mic rosoft.Act iveDirecto ry.Managem ent.Comman ds.RemoveA DG
roupMember
PS C:\scripts> .\Copy-ADGroupMember.ps1 -Identity SourceADGroup -Destination DestDL -Mirror -Confirm:$False
Add-ADGroupMember : Cannot validate argument on parameter 'Members'. The argument is null or empty. Provide an
argument that is not null or empty, and then try the command again.
At C:\scripts\Copy-ADGroupMem ber.ps1:12 char:52
+ Add-ADGroupMember -Identity $Destination -Members $ProcessMembers
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Add-ADGroupMember], ParameterBindingValidation Exception
+ FullyQualifiedErrorId : ParameterArgumentValidatio nError,Mic rosoft.Act iveDirecto ry.Managem ent.Comman ds.AddADGr ou
pMember
PS C:\scripts>
PS C:\scripts> .\Copy-ADGroupMember.ps1 -Identity SourceADGroup -Destination DestDL -Mirror -Confirm:$False
Remove-ADGroupMember : Cannot validate argument on parameter 'Members'. The argument is null or empty. Provide an
argument that is not null or empty, and then try the command again.
At C:\scripts\Copy-ADGroupMem
+ ... Remove-ADGroupMember -Identity $Destination -Members $ProcessMembers
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Remove-ADGroupMember], ParameterBindingValidation
+ FullyQualifiedErrorId : ParameterArgumentValidatio
roupMember
PS C:\scripts> .\Copy-ADGroupMember.ps1 -Identity SourceADGroup -Destination DestDL -Mirror -Confirm:$False
Add-ADGroupMember : Cannot validate argument on parameter 'Members'. The argument is null or empty. Provide an
argument that is not null or empty, and then try the command again.
At C:\scripts\Copy-ADGroupMem
+ Add-ADGroupMember -Identity $Destination -Members $ProcessMembers
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Add-ADGroupMember], ParameterBindingValidation
+ FullyQualifiedErrorId : ParameterArgumentValidatio
pMember
PS C:\scripts>
[CmdletBinding(SupportsShouldProcess=$True, ConfirmImpact='High')]
Param(
[PSObject]$Identity,
[PSObject]$Destination,
[Switch]$Mirror
)
$SourceMembers = Get-ADGroupMember -Identity $Identity | Select-Object -ExpandProperty distinguishedName
$TargetMembers = Get-ADGroupMember -Identity $Destination | Select-Object -ExpandProperty distinguishedName
$DifferenceMembers = Compare-Object -ReferenceObject $SourceMembers -DifferenceObject $TargetMembers
$ProcessMembers = $DifferenceMembers | Where-Object {$_.SideIndicator -eq '<='} | Select-Object -ExpandProperty InputObject
If ($ProcessMembers -and $PSCmdlet.ShouldProcess($Destination, "Add objects:`r`n`t$($ProcessMembers -join "`r`n`t")`r`n")) {
Add-ADGroupMember -Identity $Destination -Members $ProcessMembers
}
If ($Mirror) {
$ProcessMembers = $DifferenceMembers | Where-Object {$_.SideIndicator -eq '=>'} | Select-Object -ExpandProperty InputObject
If ($ProcessMembers -and $PSCmdlet.ShouldProcess($Destination, "Remove objects:`r`n`t$($ProcessMembers -join "`r`n`t")`r`n")) {
Remove-ADGroupMember -Identity $Destination -Members $ProcessMembers
}
}
ASKER
Thanks, that resolved those errors. However I just tested the script, and find that when the destination group has no members yet, it fails to populate with members in the source group. It works when the destination group contains at least one member. here is the error I get:
Please note that the line 13 referenced in the error is
PS C:\scripts> .\Copy-ADGroupMember.ps1 -Identity SourceADGroup -Destination DestDL -Mirror -Confirm:$False
Compare-Object : Cannot bind argument to parameter 'DifferenceObject' because it is null.
At C:\scripts\Copy-ADGroupMember.ps1:13 char:87
+ ... ject -ReferenceObject $SourceMembers -DifferenceObject $TargetMembers
+ ~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Compare-Object], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.CompareObje
ctCommand
Please note that the line 13 referenced in the error is
$DifferenceMembers = Compare-Object -ReferenceObject $SourceMembers -DifferenceObject $TargetMembers
(I added 4 commented lines to the top of your script when I ran, so for your original script line error would likely be line 9) Hope this didn't confuse you!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Works beautifully, thank you!
Will by default only copy; use -Mirror to remove members from destination that aren't in the source anymore.
Use -Confirm:$False to suppress the confirmation prompt (or change ConfirmImpact to 'None' if you never want to be asked)
Open in new window