I've written a script that our provisioning team uses to manage terminated users and group memberships.
The script works well, but it takes a long time due to how I chose to enumerate group memberships to begin with.
The current script uses Get-ADGroup $group -pr Members | select -ExpandProperty Members to enumerate membership.
I figure there has to be a more efficient method of doing this, so I wrote this:
$grpMemberships = Get-ADPrincipalGroupMembership $user | select name
foreach ($Group in $Groups){
if ($grpMemberships -contains $group) {
Write-Host "$grpMembership found!"
Remove-ADGroupMember $grpMembership -members $user
Write-Host "Removing $user from $grpMembership"
"$user is a member of $group" | out-file -filepath Termed_Users-$get-date -f yyy-MM-dd.txt -Append
Write-Host ""
}
}
The problem is that this never seems to execute. Any idea why this doesn't work?
Thank you #Olaf
I figured it out with your assistance.
foreach ($grpMembership in $grpMemberships.name) {
foreach ($Group in $Groups){
if ($Groups -contains $grpMembership) {
Write-Host "$grpMembership found!"
#Remove-ADGroupMember $grpMembership -members $user
Write-Host "Removing $user from $grpMembership"
"$user is a member of $group" | out-file -filepath Termed_Users-$(get-date -f yyy-MM-dd).txt -Append
Write-Host ""
}
}
}
Related
I currently have a script that is able to disable a list of usernames using a text file which has a list of username specified:
$users = Get-Content C:\disableusers.txt
foreach ($user in $users) {
Disable-ADAccount -Identity $user
Write-Host "user $($user) has been disabled"
}
I was wondering if it is possible to incorporate moving using from one OU to another during the execution of this script?
e.g. moving from "Users" OU to "Disabled Users" OU.
I have created another script which does move a list of usernames to "Disabled Users" OU:
$users=Get-Content C:\disableusers.txt
$OU = "distinguishedName of my Disable Users OU"
foreach ($user in $users) {
Get-ADUser $user | Move-ADObject -TargetPath $OU
}
Any help on this is much appreciated thanks.
Both of your snippets look good to me, if you are interested in combining them into one you could use -PassThru from Disable-ADAccount to pass the disabled object through the pipeline to Move-ADObject:
$OU = "distinguishedName of my Disable Users OU"
Get-Content C:\disableusers.txt | ForEach-Object {
try {
Disable-ADAccount $_ -PassThru |
Move-ADObject -TargetPath $ou
Write-Host "user $($user) has been disabled and moved"
}
catch {
Write-Error $_
}
}
I'm looking to export users with their groups in Active Directory through powershell, but I can't seem to get the pipe to work for some reason the powershell script I'm using right now is
`
$groups = get-adgroup -filter *
foreach ($group in $groups) {
$naam = $group.name
$members = Get-ADGroupMember -identity $group
write-host “Group: $naam”
write-host “————————————-”
foreach ($member in $members) {
$memnaam = $member.samaccountname
write-host “$naammem”
}`
I just can't seem to figure this out any recommendations?
`
$groups = get-adgroup -filter *
foreach ($group in $groups) {
$naam = $group.name
$members = Get-ADGroupMember -identity $group
write-host “Group: $naam”
write-host “————————————-”
foreach ($member in $members) {
$memnaam = $member.samaccountname
write-host “$naammem”
} | Export-CSV c:\FileName.csv`
Check for typos in variable names (you have one) and that you've closed all parentheses and braces. Even better, don't use variables where not needed:
$groups = get-adgroup -Filter *
# If you save your search as an object you won't need to re-run it multiple times to use the data
Write-Host "Processing groups"
$SearchResult = $Groups | ForEach-Object {
$GroupName = $_.Name
# Some simple error trapping
Try {
# Writing to host for informational only
Write-Host "$GroupName..." -NoNewline
$Members = (Get-ADGroupMember -Identity $_ -ErrorAction Stop).SamAccountName
}
Catch {
$Members = $_
}
# Output results as an object
[pscustomobject]#{
Group = $GroupName
Members = $Members
}
Write-Host "Done"
}
Write-Host "Processing complete"
# If you want to display it in console
$SearchResult | Format-List
# Or a GridView
$SearchResult | Out-GridView
I am working on a solution that will help keep our Active Directory clean, so I want to use a Powershell script that will remove the disabled accounts from all groups.
I got the following script:
foreach ($username in (Get-ADUser -SearchBase "OU=Terminated Users,DC=corp,DC=company,DC=com" -filter *)) {
# Get all group memberships
$groups = get-adprincipalgroupmembership $username;
# Loop through each group
foreach ($group in $groups) {
# Exclude Domain Users group
if ($group.name -ne "domain users") {
# Remove user from group
remove-adgroupmember -Identity $group.name -Member $username.SamAccountName -Confirm:$false;
# Write progress to screen
write-host "removed" $username "from" $group.name;
# Define and save group names into filename in c:\temp
$grouplogfile = "c:\temp\" + $username.SamAccountName + ".txt";
$group.name >> $grouplogfile
}
}
}
It's working fine but only for security groups. Users are not deleted from distribution groups. I searched the Internet and people mostly suggest to use "Remove DistributionGroup Member" cmdlet. However, this is the Exchange cmdlet and we use Google Workspace for our email, so this cmdlet is not recognized when I run it on the DC.
Any idea how to solve it? Thanks!
The cmdlet Remove-ADPrincipalGroupMembership will help:
#get all disabled users in specified OU
$disabledUsers = get-aduser -SearchBase "OU=test_piotr,DC=corp,DC=company,DC=com" -LDAPFilter '(userAccountControl:1.2.840.113556.1.4.803:=2)' -Properties memberof,samaccountname
#Loop through array and remove groupmembership and store operation result in $result
$result = #(
foreach ($user in $disabledusers){
try {
#Only process user account if memberships are present
If ($user.memberof){
#Remove all memberships the user has currently, no need to exclude domain users as $user.memberof does not return it
$null = Remove-ADPrincipalGroupMembership -Identity $user.samaccountname -MemberOf $user.memberof -Confirm:$false -ErrorAction:stop
write-host "Removed user: $($user.samaccountname) from groups: $($user.memberof -join ',')"
#Build object for logfile, you could also loop through $user.memberof to create one object per removed group
$attrsHt = #{
smaccountname=$user.samaccountname
group=($user.memberof -join ',')
status='removed'
exception=$null
}
New-Object -typename psobject -Property $attrht
}
}
Catch {
write-error "Failed to remove user: $($user.samaccountname) from groups: $($user.memberof -join ',') - Exception: $_"
$attrsHt = #{
smaccountname=$user.samaccountname
group=($user.memberof -join ',')
status='error'
exception=$_
}
New-Object -typename psobject -Property $attrht
}
}
)
I have a list of accounts (SAM account names) and a list of groups all the accounts need to be removed from. My problem is that I have to specify -server DC01 since the users are in a different domain. I can do that for removing 1 user at a time with:
$Groups = Get-Content C:\temp\groups.txt
$user = get-aduser <username> -Server "DC01.domain.com"
foreach ($Group in $Groups) {
Write-Host "Removing $user from $group" -Foreground Yellow
Remove-ADGroupMember -Identity $group -Members $user -Confirm:$false
}
But I have several long lists of users, and there's got to be a way to do this for all of them.
I tried adding the ** entries below, but no dice:
$Groups = Get-Content C:\temp\groups.txt
$user = Get-Content C:\temp\users0.txt **-Server "DC01.domain.com"**
foreach ($Group in $Groups) {
Write-Host "Removing $user from $group" -Foreground Yellow
Remove-ADGroupMember -Identity $group -Members $user **-searchbase = "DC=domain,DC=com"** -Confirm:$false
}
Thanks in advance for any suggestions!
I cannot test this right now, but I believe you can set the -Members parameter to an array of users.
Apparently, the Remove-ADGroupMember does not work if you supply an array of DistinguishedNames when the users are from another domain, so we need to use the full default (Microsoft.ActiveDirectory.Management.ADUser) objects as returned by the Get-ADUser cmdlet.
$DCGroups = (Get-ADDomain your.domainA.com).PDCEmulator # get a PDC emulator in domain A where the groups are
$DCUsers = (Get-ADDomain your.domainB.com).PDCEmulator # get a PDC emulator in domain B where the users are
$Groups = Get-Content 'C:\temp\groups.txt' # the groups are in domainA
# get an array users ADUser Objects from Domain B
$users = Get-Content 'C:\temp\users0.txt' | ForEach-Object {
$user = Get-ADUser -Filter "SamAccountName -eq '$_'" -Server $DCUsers -ErrorAction SilentlyContinue
if ($user) { $user }
}
# remove these users from the groups in Domain A
foreach ($Group in $Groups) {
Write-Host "Removing $($users.Count) users from $Group" -Foreground Yellow
Remove-ADGroupMember -Identity $Group -Members $users -Confirm:$false -Server $DCGroups
}
Edit
To overcome the exception being thrown when you try to remove a user that is not a member of the group, you need to add some extra code to make sure the -Members parameter of Remove-ADGroupMember contains only ADUser objects that currently are member of this group.
$DCGroups = (Get-ADDomain your.domainA.com).PDCEmulator # get a PDC emulator in domain A where the groups are
$DCUsers = (Get-ADDomain your.domainB.com).PDCEmulator # get a PDC emulator in domain B where the users are
$Groups = Get-Content 'C:\temp\groups.txt' # the groups are in domainA
# get an array users ADUser Objects from Domain B
$users = Get-Content 'C:\temp\users0.txt' | ForEach-Object {
$user = Get-ADUser -Filter "SamAccountName -eq '$_'" -Server $DCUsers -ErrorAction SilentlyContinue
if ($user) { $user }
}
# remove these users from the groups in Domain A
foreach ($Group in $Groups) {
# get a list of SamAccountNames of users that are currently a member of this group
$members = Get-ADGroupMember -Identity $Group | Where-Object {$_.objectClass -eq 'user'} | Select-Object -ExpandProperty SamAccountName
# create a subset of users that are indeed in the members list
$removeThese = #($users | Where-Object { $members -contains $_.SamAccountName })
if ($removeThese.Count) {
Write-Host "Removing $($removeThese.Count) users from $Group" -Foreground Yellow
Remove-ADGroupMember -Identity $Group -Members $removeThese -Confirm:$false -Server $DCGroups
}
else {
Write-Host "No users need to be removed from group '$Group' " -Foreground Green
}
}
I am writing a powershell script to disable users due to the fact that we get a list of them everyday and it is monotonous. I paste the list from the ticket into a csv formatted as Lastname, Firstname then run my script with imports the list, serches ad and ask if you want to disable if it finds them. Here is the code...
# Set variables
$Import = "C:\Scripts\Support Files\Users_To_Disable.csv"
$Export = "C:\Scripts\Support Files\Disabled_Users_Output.txt"
# Import user list
$Users = Import-CSV $Import
foreach ($User in $Users)
{
# Set user variables
$LastName = $User.("Surname")
$FirstName = $User.("GivenName")
# Use user variables from list to search ad
$UserName = (Get-ADUser -Filter "GivenName -like '$FirstName*' -and Surname -like '$LastName*'").SamAccountName
# What to do if it finds nothing
If ($UserName -eq $Null)
{
Write-Host $LastName, $FirstName NA -ForegroundColor Yellow
Write-Output "$LastName, $FirstName NA" | Out-File $Export -Append
}
# What to do if it finds a user
Else
{
# Ask for user input
Write-Host $LastName, $FirstName Found -ForegroundColor Green
Write-Host UserName = $UserName -ForegroundColor Green
DO {
$Disable = Read-Host "Do you want to disable user? (Y/N)"
If($Disable -eq "Y")
{
# Disable the user
Disable-ADAccount -Identity $UserName
# Move the user
Get-ADUser $UserName | Move-ADObject -TargetPath "OU=Disabled - Retention,DC=intranet,DC=sw"
# Add Disabled Users group
Add-ADGroupMember "Disabled Users" -Members "$UserName"
# Set Disable Users as primary group
$Group = Get-ADGroup "Disabled Users" -Properties #("PrimaryGroupToken")
Get-ADUser "$UserName" | Set-ADUser -Replace #{PrimaryGroupID=$Group.PrimaryGroupToken}
# Remove all other groups
$User = Get-ADUser "$UserName" -Properties MemberOf
$Groups = $User.MemberOf |ForEach-Object { Get-ADGroup $_ }
$Groups | ForEach-Object { Remove-ADGroupMember -Identity $_ -Members $User -Confirm:$false }
# Output
Write-Host $LastName, $FirstName Disabled -ForegroundColor Red
Write-Output "$LastName, $FirstName Disabled" | Out-File $Export -Append
Break
}
}
Until ($Disable -eq "N")
}
}
Invoke-Item $Export
All of that works, what is scary is that if there are blank cells above a user then it returns all of the users in ad and asks if you want to disable all of them. In other words if the csv looks like this...
Surname GivenName
User Test
Everything works fine, but if it looks like this...
Surname GivenName
User Test
Pandemonium, well not really but it does ask if you want to initiate a resume generating event, which I don't so how can I build in some safety that would stop it from returning all of ad when there are blanks in the csv before users?
You can eliminate the blank lines by filtering out Null values on your import, which should resolve the problem.
$Users = Import-CSV $Import | Where-Object {$_.Surname}