Im trying to get all AD users where the user in the manager field is disabled
The below does not work, ive tried multiple ways though cannot figure it out
Get-ADUser -SearchBase "XXX" -filter {enabled -eq $true} -Properties * | where {Get-aduser -Filter {distinguishedname -eq $_.manager -and enabled -eq $false}}
I don't have an AD readily available that has populated Manager attribute, so the script is not tested. Anyway, a simple way is to create two collections with Get-ADUser. Fill one with all the disabled accounts and one with enabled ones. Loop through the enabled accounts and check if manager is found from the disableds.
To make things faster, store the disabled accounts as a hash table with Group-Object and use hashtable's ContainsKey() method like so,
$disabled = Get-ADUser -filter { enabled -ne $true } | group-object `
-AsHashTable -AsString -Property Name
$users = Get-ADUser -filter { enabled -eq $true }
foreach($user in $users) {
if( $disabled.ContainsKey($user.Manager) ) {
# User's manager is a disabled account
}
}
Related
I'm looking for some guidance on creating a powershell script that will check security and distribution groups from specific OU's and see if the owner is a user who's disabled.
We have lots of old groups in our AD created by ex employees that need to be cleaned up.
This is what i've started with.
$managedByGroups = get-adgroup -filter 'groupCategory -eq "Distribution"' -SearchBase "OU=SydExchangeGroups,OU=SydGroups,OU=Sydney,DC=my,DC=org,DC=biz" -Properties distinguishedname, managedby | select sAMAccountName, managedby
$disabledUsers = Get-ADUser -Filter {Enabled -eq $false} -SearchBase "OU=SydDisabledUsers,OU=SydMisc,OU=Sydney,DC=my,DC=org,DC=biz" | select distinguishedname
foreach ($group in $managedByGroups){
if($managedByGroups.managedby -eq $disabledUsers.distinguishedname)
{
write-output
}
}
Thanks
There are a number of issues with your if block:
you are looping through $managedByGroups, but you are never using that variable (it should be $group.managedby)
you are trying to compare 1 element with a list of elements, in this case consider using -in operator instead of -eq.
you should treat the case when there is no value for managedby attribute, in case you do not get the desired results.
An alternative to your code may is below.
I'm first getting the list of managedby users, then i'm looping though each entry, and if it is not null, we try to do a get-aduser filtering by enabled status and the distinguishedname.
$DisabledManagedBy variable will contains ADUser objects which are disabled.
$grp = get-adgroup -filter 'groupCategory -eq "Distribution"' -Properties ManagedBy,DistinguishedName
$DisabledManagedBy = foreach ($item in $grp.ManagedBy) {
if ($item) {
Get-ADUser -Filter {Enabled -eq $false -and DistinguishedName -like $item} -Properties DistinguishedName
}
}
I worked this out eventually by doing the following:
$myDisabledUsers = #()
$date = get-date -format dd-MM-yyyy
$managedSydGroups = Get-ADGroup -Filter * -Properties * -Searchbase "OU=SydExchangeGroups,OU=SydGroups,OU=Sydney,DC=my,DC=biz,DC=org" | where {$_.managedby -ne $null} | select name, managedby
$disabledSydUser = Get-ADUser -Filter * -SearchBase "OU=SydDisabledUsers,OU=SydMisc,OU=Sydney,DC=my,DC=biz,DC=org" | where {$_.enabled -eq $false} | select -ExpandProperty distinguishedname
$disabledOwners = foreach($group in $managedSydGroups)
{
$managedByString = [string]$group.managedby
if($disabledSydUser -contains $managedByString)
{$myDisabledUsers += $group}
}
We have a (2 way) trust relationship between 2 forests:
acme.com
someOtherForest.com
We have several subDomains in forest acme.com
domain1.acme.com
domain2.acme.com
I have (nested) groups in domain1.acme.com that contain both users in domain2.acme.com and foreignSecurityPrincipals from someOtherForest.com.
The server I am connected to uses a DC (dc1) on domain1.acme.com.
I have been using the following script to output all the members from a given group (recursively). It outputs foreignSecurityPrincipals as well as domain1 users perfectly fine, but errors on members who are from domain2:
$Groups = Get-ADGroup -Properties * -Filter * -SearchBase "CN=app-users,OU=app,DC=domain1,DC=acme,DC=com"
Foreach($G In $Groups) {
$members = Get-ADGroupMember $G -recursive | Get-ADUser -Properties Mail |Select-Object DistinguishedName,sAMAccountName, Mail |
Export-CSV -Path C:\output.csv -NoTypeInformation
}
If I add -server dc1:3268 (the GC of the DC) to the Get-AdUser section, then domain2 members are output fine, however it errors on foreignSecurityPrincipals.
Is there a way to output both foreignSecurityPrincipals and members from all subDomains of acme.com?
You're on the right track with using the GC port since that will take care of your forest.
But the problem is still the Foreign Security Principals. The documentation for Get-ADGroupMember says that it outputs "principal objects that represent users, computers or groups". So it'll only work for those three types of objects, not Foreign Security Principals.
That of course makes things a little more difficult for two reasons:
You don't have the ability to use the -Recursive property, so you have to handle that manually.
You still have to resolve the Foreign Security Principals.
This tipped me off that we can use Get-ADObject instead.
I was bored, so I wrote this for you. We do have a similar setup of domains here, so I was able to test it. But keep in mind that the domains are hard-coded. It assumes any foreign security principal will be on that one domain and not any other. So make sure you update the domain names (3 places).
It resolves the external accounts by taking the objectSid from the Foreign Security Principal, which is actually the SID of the account on the external domain, and using that to look up the user on that domain.
function Get-Members {
param([Microsoft.ActiveDirectory.Management.ADGroup]$group)
$members = $group | Select-Object -ExpandProperty Members | Get-ADObject -Server dc1:3268 -Properties Mail,SamAccountName,objectSid,ObjectClass
$returnMembers = New-Object System.Collections.ArrayList
foreach ($member in $members) {
if ($member.ObjectClass -eq "ForeignSecurityPrincipal") {
$returnMembers.Add((Get-ADUser -Server someOtherForest.com $member.objectSid -Properties Mail,SamAccountName)) | Out-Null
} elseif ($member.ObjectClass -eq "Group") {
$nestedMembers = (Get-Members ($member | Get-ADGroup -Properties Members))
if ($nestedMembers) {
if ($nestedMembers.Count -gt 1) {
$returnMembers.AddRange($nestedMembers) | Out-Null
} else {
$returnMembers.Add($nestedMembers) | Out-Null
}
}
} else {
$returnMembers.Add($member) | Out-Null
}
}
return $returnMembers
}
$Groups = Get-ADGroup -Server dc1:3268 -Properties Members -Filter * -SearchBase "CN=app-users,OU=app,DC=domain1,DC=acme,DC=com"
Foreach($G In $Groups) {
$members = Get-Members $G |Select-Object DistinguishedName,sAMAccountName, Mail |
Export-CSV -Path C:\output.csv -NoTypeInformation
}
Gabriel Luci's answer helped me edit my original script, to create a fast AD query that produces the same result set.
This is working for our setup, but I cannot be sure it would work for every AD setup.
WARNING: Errors that occur are suppressed using the -erroraction 'silentlycontinue' option.
This will display all members (domain, subdomain, and trusted Forest domains) of a group (in the server's domain) including nested groups. Each user will only appear once, regardless of how many nested groups they are a member of.
$set = New-Object 'System.Collections.Generic.HashSet[Microsoft.ActiveDirectory.Management.ADUser]'
$Groups = Get-ADGroup -Properties * -Filter * -SearchBase "CN=app-users,OU=app,DC=domain1,DC=acme,DC=com"
Foreach($G In $Groups)
{
$members = Get-ADGroupMember $G -recursive | Get-ADUser -Properties Mail -erroraction 'silentlycontinue'
$subDomainMembers = Get-ADGroupMember $G -recursive | Get-ADUser -Server dc1:3268 -Properties Mail -erroraction 'silentlycontinue'
Foreach ($i In $members){
$set.Add($i)| Out-Null
}
Foreach ($i In $subDomainMembers){
$set.Add($i)| Out-Null
}
}
$set |Select-Object -Unique DistinguishedName,sAMAccountName, Mail | Export-CSV -Path C:\output.csv -NoTypeInformation
I was wondering if this script could be changed into one for only active users?
import-module ActiveDirectory
Start-Transcript -Path "C:\test\teetest.txt"
$groups = Get-ADGroup -filter {(name -like "runners*") -or (name -like "helpers*")
foreach($group in $groups)
{
$countUser = (Get-ADGroupMember $group.DistinguishedName).count
Write-Host "The group $($group.Name) has $countUser user(s)."
}
Stop-Transcript
Any help would be appreciated.
If I understand your question correctly and by active users you mean groups with at least 1 member(i.e. greater than 0). You could just filter out results using Where-Object cmdlet. Like so:
$groups = Get-ADGroup -filter {(name -like "runners*") -or (name -like "helpers*") -Properties Members | Where-Object { $_.Members.Count –gt 0 }
Yes, you can add a filter to only get the number of active Members in the Group.
Since Get-ADGroupMember doesn't supply all properties for the Users you have to do another lookup for each of them:
$countUser = (Get-ADGroupMember $group.DistinguishedName | % { Get-ADuser -Identity $_ -Property Enabled | Where-Object {$_.Enabled -eq $true}}).count
Explanation:
% { Get-ADuser -Identity $_ -Property Enabled - Get the Informations for each User found in the Group with the Enabled Property added to it
Where-Object {$_.Enabled -eq $true} - Filters the users that are enabled
I think this may be because the Get-ADGroupMember not just returns user objects with a limited set of properties, but can also return groups and computers.
Since you are only looking for users that are direct descendents of the groups 'runners*' or 'helpers*', it is better to limit the objects returned by the Get-ADGroupMember cmdlet to be users only.
Below I do this by adding Where-Object { $_.objectClass -eq "user" }.
Next, to ensure the .Count property can be used I would suggest to enclose the thing in a #() so the returned value actually is an array and therefore has the Count property.
For a script like this, I also suggest NOT to try and put it all in one single line, because that makes spotting mistakes (like forgetting a closing bracket) more difficult.
Try this:
Start-Transcript -Path "C:\test\teetest.txt"
$groups = Get-ADGroup -Filter {(name -like "runners*") -or (name -like "helpers*")}
foreach($group in $groups) {
$countUser = 0
Get-ADGroupMember $group.DistinguishedName | Where-Object { $_.objectClass -eq "user" } |
ForEach-Object {
if ((Get-ADuser -Identity $_.DistinguishedName).Enabled) { $countUser++ }
}
Write-Host "The group $($group.Name) has $countUser user(s)."
}
Stop-Transcript
Replace the $countUser statement alone with below example.
For only Enabled User Accounts
$countUserEnabled = (get-aduser -filter *|where {$_.enabled -eq "True"}).count
For only Disabled User Accounts
$countUserDisabled = (get-aduser -filter *|where {$_.enabled -ne "False"}).count
I am attempting to create a power shell script that prompts input for specific AD groups that a particular org manages that will essentially filter out users that are no longer in the said org and ONLY returns the 'samaccountname' and current department for those particular users. I have started but it does not seem to filter correctly. Any advice would be greatly appreciated.
Add-Type -AssemblyName Microsoft.VisualBasic
$groupName = [Microsoft.VisualBasic.Interaction]::InputBox("Please enter AD group name to display users no longer in department:", "XYZ", "$env")
Get-ADGroupMember -Identity $groupName -Recursive | Get-ADUser -Properties Department -Filter {enabled -eq $true} | ? {$_.DistinguishedName -notlike "*,OU=XYZ,*"} | Select-Object SamAccountName,Department
It appears it doesn't like the -Filter you have for Get-ADUser, I think (not 100% on this) it is because coming through the pipeline, it is sending one user at a time, so there isn't anything to filter.
Here's what I would do/try (maybe a better way, but testing this seems to get where you want to go):
$MatchedUsers=#{}
$GroupMembers=Get-ADGroupMember -Identity $groupName -Recursive | Get-ADUser -Properties Department
ForEach ($User in $GroupMembers) {
If (($User.Enabled -eq "True") -and ($User.DistinguishedName -notlike "*,OU=XYZ,*")) {
$MatchedUsers=#{
'SamAccountName'=$User.SamAccountName
'Department'=$User.Department
}
$obj=New-Object -TypeName PSObject -Property $MatchedUsers
Write-Output $obj
}
}
I'm trying to get a (one line) answer to get a list of users (based on a filter of get-aduser) then use that list to do a search matching on an extended version of their name - e.g. I have:
UserA
UserB
UserAAdmin
UserBAdmin
and want to find (when user A is disabled) the UserAAdmin. This seemed like it would be simple, but I can't seem to use the SAMACCOUNTNAME with a like or equals statement no matter what I try- i.e.
Get-ADUser -Filter {Enabled -eq $false} -Properties sAMAccountName |
ForEach {Get-AdUser -Filter {samaccountname -like ($_.samaccountname + "Admin")}}
(as for the why, well, because the client I'm working with has a structure such that all their user accounts have ADMIN added to the end of their admin accounts and we want to find any disabled USER accounts and find (and then disable) the associated admin account).
Thanks
The answer of Avshalom is correct, but it is not efficient and useless to queries your AD twice ...
Once you have all your disabled users then you can just filter
$Users = Get-ADUser -Filter {Enabled -eq $false}
Foreach ($User in $Users)
{
$Match = "ADM-"+$User.SamAccountName
$Users|?{$_.samaccountname -like $match}
}
If i understand you right, you can try this...
$DisabledUsers = Get-ADUser -Filter {Enabled -eq $false}
Foreach ($User in $DisabledUsers)
{
$Match = $User.SamAccountName + '*'
$MatchedUsers = Get-AdUser -Filter {samaccountname -like $match}
foreach ($MatchUser in $MatchedUsers)
{
"You Can do here what you want"
}
}