@BenH and @TheMadTechnician were extremely helpful in assisting me with a script, to remove Distro Lists (only) from users in specific AD OU's. I forgot to add a needed criteria, so decided to post this as a separate question (original thread here)
@BenH's approach was like this:
$OUs = 'OU=PendingDeletion,OU=Users,DC=Stuff,DC=Place,DC=net','OU=HoldForReview,OU=Users,DC=Stuff,DC=Place,DC=net'
$Users = ForEach ($OU in $OUs) {
Get-ADUser -Filter * -SearchBase $OU
}
ForEach ($User in $Users) {
Get-ADPrincipalGroupMembership -Identity $user |
Where-Object {$_.GroupCategory -eq 0} |
ForEach-Object {
Remove-ADPrincipalGroupMembership -Identity $user -MemberOf $_
}
}
My question - can I force the script to only take action on accounts that have expired more than 30days ago, by adding a variable and "Where-Object" logic to the first loop like this?:
$OUs = 'OU=PendingDeletion,OU=Users,DC=Stuff,DC=Place,DC=net','OU=HoldForReview,OU=Users,DC=Stuff,DC=Place,DC=net'
$30DaysOld = (Get-Date).AddDays(-30)
$Users = ForEach ($OU in $OUs) {
Get-ADUser -Filter * -SearchBase $OU |
Where-Object {$_.AccountExpirationDate -gt $30DaysOld}}
ForEach ($User in $Users) {
Get-ADPrincipalGroupMembership -Identity $user |
Where-Object {$_.GroupCategory -eq 0} |
ForEach-Object {
Remove-ADPrincipalGroupMembership -Identity $user -MemberOf $_
}
}
Possible? Or would I need to change the -gt
to a -lt
in order to get the correct date range?
Thanks for looking!
Making an answer as requested. The problem is with the Where
statement:
Where-Object {$_.AccountExpirationDate -gt $30DaysOld}
While logically is sounds like it's right 'where the account expired more than 30 days ago' it actually comes out to 'where the Date that the account expired is greater than what the Date was 30 days ago'. When you consider that some systems measure dates as seconds passed since the Unix Epoch (Jan 1, 1970 at 12:00:00 AM UTC), and dates are converted to integers, and it makes more sense that the -gt
operator selects whichever date happens later chronologically as more seconds have passed since the epoch, and the integer is a larger number.
If you change the -gt
to -lt
it accomplishes what you're looking for. Also, adding -and $_.AccountExpirationDate
to it makes sure that the AccountExpirationDate
is not null. So we end up with:
Where-Object {$_.AccountExpirationDate -lt $30DaysOld -and $_.AccountExpirationDate}
@TheMadTechnician nailed it - I needed to change the nested "where" statement to:
Where-Object {$_.AccountExpirationDate -lt $30DaysOld -and $_.AccountExpirationDate}
So the functioning code is:
$30DaysOld = (Get-Date).AddDays(-30)
$OUs = 'OU=PendingDeletion,OU=Users,DC=Stuff,DC=Place,DC=net','OU=HoldForReview,OU=Users,DC=Stuff,DC=Place,DC=net'
$Users = ForEach ($OU in $OUs) {
Get-ADUser -Filter * -Properties AccountExpirationDate -SearchBase $OU |
Where-Object {$_.AccountExpirationDate -lt $30DaysOld -and $_.AccountExpirationDate}
}
ForEach ($User in $Users) {
Get-ADPrincipalGroupMembership -Identity $user |
Where-Object {$_.GroupCategory -eq 0} |
ForEach-Object {
Remove-ADPrincipalGroupMembership -Identity $user -MemberOf $_ -Confirm:$false
}
}
Hopefully TheMadTechnician will submit their comment as an answer so I can update and give karma where karma is due! If this solves a problem you're searching for, please upvote TheMadTechnician's comment!
OP here - I've been continuing to work on this (with assistance), and added some additional embellishments that I thought someone else might find useful, so I wanted to share it back.
Please don't upvote this answer, TheMadTechnician and BenH deserve all the credit for breaking the back of this. Go upvote that answer, if you find this useful.
This will now write the names of distros removed to the AD account, use a semicolon separator (to cut/paste the names if you need to re-add the distros), and won't add clutter to the AD account if it's run against the account more than once.
Enjoy!
# Variables
$30DaysOld = (Get-Date).AddDays(-30)
$OUs = (
'OU=PendingDeletion,OU=Users,DC=Stuff,DC=Place,DC=net',
'OU=HoldForReview,OU=Users,DC=Stuff,DC=Place,DC=net'
)
# Collect the needed users
$Users = ForEach ($OU in $OUs) {
Get-ADUser -Filter * -Properties AccountExpirationDate,info -SearchBase $OU |
Where-Object {$_.AccountExpirationDate -lt $30DaysOld -and $_.AccountExpirationDate}
}
# Collect each user's Distro Lists & REMOVE
ForEach ($User in $Users) {
$distrosremoved=@()
Get-ADPrincipalGroupMembership -Identity $user |
Where-Object {$_.GroupCategory -eq "distribution"} |
ForEach-Object {
$distrosremoved+=$_.name
Remove-ADPrincipalGroupMembership -Identity $user -MemberOf $_ -Confirm:$false
}
# Collect info from the Telephone > Notes field, and ADD the list of Distros into the existing info
if($distrosremoved){
$distro_str="Removed Distro Lists: `r`n"+($distrosremoved -join "; ")
if ($user.info){
$newinfo=$user.info+"`r`n"+$distro_str
Set-ADUser $user -Replace @{info=$newinfo}
}else{
$newinfo=$distro_str
Set-ADUser $user -Add @{info=$distro_str}
}
}
}