Select AD member properties + extra column - powershell

I'm getting AD members for a group and list certain properties from that group. I can't seem to get the group name using the following code:
Import-Module ActiveDirectory
$strIdentity = "TestGroup"
$GroupMembers = Get-ADGroupMember -Identity $strIdentity -Recursive
$GroupMembers | select $strIdentity, Name, ObjectClass | sort name | Format-Table
When I get the output, I get a {} instead of TestGroup.

Select-Object is for selecting properties of an object so selecting $strIdentity doesn't make any sense here. Omit that part from your Select statement.
But what I think you are trying to do is add a property to reflect the parent group name.
$groupmembers | select #{Name="Group";Expression={$strIdentity}}, Name, ObjectClass
Remember it is all about the objects not text.

Enclose $strIdentity in double quotes:
$GroupMembers | select "$strIdentity",Name, ObjectClass ...
If the above doesn't work, try using a calculated property:
$GroupMembers | select #{Name='GroupName';Expression={$strIdentity}},Name, ObjectClass ...

Related

Sorting Office 365 user account / mailbox properties

I'm accessing my cloud Office 365 Exchange Server via Powershell. Showing all properties of an account can be done via Get-Mailbox 'username' | Select * (MS reference).
On most systems those properties are already sorted (e.g. Get-ADUser 'username' -Properties *). Is it possible to sort the Get-Mailbox output? I thought Get-Mailbox 'username' | Select * | Sort-Object would do the trick but it didn't make any difference (I guess a property doesn't constitute an object). What's the right command to sort the properties for a single user?
Note: Sorting properties of multiple accounts works fine e.g. Get-Mailbox -filter * | select Name, DisplayName | Sort-Object Displayname
Update:
I managed to get a sorted properties list using
(Get-Mailbox 'mailboxname' | select *).PSObject.properties | ForEach-Object {$_.Name} | Sort-Object Name
it gets me the following output:
AcceptMessagesOnlyFrom
AccountDisabled
AddressBookPolicy
ArchiveWarningQuota
...
$_.Name gives me the values but so far I couldn't combine both into one list, I'm trying to get s.th. like this:
AcceptMessagesOnlyFrom = {}
AccountDisabled = False
AddressBookPolicy =
ArchiveWarningQuota = 45 GB (48,318,382,080 bytes)
...
I'm not completely sure this is what you are after, let me know if I'm wrong. As in my comment, Sort-Object can handle sorting a list or an object[] by one or more of it's properties; but sorting one single object by it's properties, say alphabetically, would require a combination of accessing the object's properties with .PSObject.Properties.Name and then sorting this list with Sort-Object. And after that we can use Select-Object with this sorted list to display the object as we want.
Using the object below as an example as I have no idea how of the type Microsoft.Exchange.Data.Directory.Management.Mailbox looks.
$mailbox = [pscustomobject]#{
DisplayName = 'someuser'
UserPrincipalName = 'someuser#somedomain.com'
Mail = 'someuser#somedomain.com'
IsLicensed = $true
}
$properties = $mailbox.PSObject.Properties.Name | Sort-Object
$mailbox | Select-Object $properties
As you can see, object's properties are now sorted alphabetically:
DisplayName IsLicensed Mail UserPrincipalName
----------- ---------- ---- -----------------
someuser True someuser#somedomain.com someuser#somedomain.com
By looking at your edit, seems like you are looking for a one-liner, so this is how it could look:
Get-Mailbox 'mailboxname' | ForEach-Object {
$_ | Select-Object ($_.PSObject.Properties.Name | Sort-Object)
}

Return list of ad accounts and check if member of group

I've written the below, and it works (based on Check if the user is a member of a list of AD groups), however it takes an incredibly long time to run - I'm assuming this is because it retrieves the full group for every user. I've tried moving the $members... line out of the function at the start to retrieve the group list once, but doesn't seem to make any difference.
Is there a more efficient way of returning this info?
samaccountname enabled InDenyGroup
-------------- ------- -----------
admin-abc True yes
admin-def True yes
In this example, the account name filter is "king", as the check is whether an account is in a group or not.
Get-ADUser -Filter "(SamAccountName -like 'admin*') -and (enabled -eq 'true')" |
ft -AutoSize samaccountname,enabled,#{Name='InBlockGroup'; Expression={InDenyGrp($_.samaccountname)}}
Function InDenyGrp([string]$UserID) {
$members = Get-ADGroupMember -Identity "myBlockGroup" | Select -ExpandProperty SamAccountName
If ($members -contains $UserID) {
Return "yes"
} Else {
Return "not in group"
}
}
Thanks.
You query all ADGroup members (not only the DistinguishedNames) of the same ADGroup on each iteration in your Foreach-Object loop again and again (That's the bottleneck).
Either you just query the "blockGroup"'s members (see your posted link) and loop over the members and check whether your users are part of them (there are some properties to compare it with) or you try the code below:
Building a lookup table should increase the performance.
Furthermore, we don't need more information about group members than the DistinguishedNames, therefore Get-ADGroupMember is overkill.
You can extend the LookupTable with members of different groups.
# query blocking group with it's members first (only DistinguishedNames)
$adGroup = Get-ADGroup -Identity '<myBlockGroup>' -Properties 'Members'
# build lookup table of members' DistinguishedNames
$adGroupMemberLookupTable = [System.Collections.Generic.HashSet[string]]::new()
foreach ($member in $adGroup.Members) {
[void]$adGroupMemberLookupTable.Add($member)
}
Get-ADUser -Filter "(SamAccountName -like 'admin*') -and (enabled -eq 'true')" |
Format-Table -AutoSize samaccountname, enabled,
#{Name ='InBlockGroup';
Expression = {
# lookup if user is member of a "blocking" group
$adGroupMemberLookupTable.Contains($_.DistinguishedName)
}
}

Foreach in foreach (nested)

I'm trying to loop all disabled users through an array of groups to check if the users have membership in any of the listed groups. My thought is that for every user in the list loop them through and check if they are present in one of the listed groups. That would require nesting foreach loops, right? The output I get is like this:
...
user1
user2
user3
is not a member of group1
Here is the source code:
$dUsers = Get-ADUser -Filter {enabled -eq $false} |
FT samAccountName |
Out-String
$groups = 'Group1', 'Group2'
foreach ($dUser in $dUsers) {
foreach ($group in $groups) {
$members = Get-ADGroupMember -Identity $group -Recursive |
Select -ExpandProperty SamAccountName
if ($members -contains $dUsers) {
Write-Host "[+] $dUser is a member of $group"
} else {
Write-Host "[-] $dUser is not a member of $group"
}
}
}
I'm pulling my hair because I feel like there is a simple solution, but I'm lost.
Update:
I wanted to put all disabled users in variable $dUsers.
It actually works if I manually put users in the variable like this:
$dUsers = 'user1','user2','user3'
Which gives me the following output:
user1 is not a member of group1
user1 is not a member of group2
user2 is not a member of group1
user2 is not a member of group2
...
This makes me question how it gets "foreached" when the variable is:
$dUsers = Get-ADUser -Filter {enabled -eq $false} |
FT samAccountName |
Out-String
Anyone got a clarification on that?
Update:
This is the final code. It takes a long time to run, even with only two groups.
$dUsers = Get-ADUser -Filter {enabled -eq $false} | Select-Object -Expand SamAccountName
$groups = 'Group1', 'Group2'
Write-host '[+] Checking if any disabled user is member of any SSL groups'
Write-host '[+] This might take a while. Get a coffee!'
write-host '[+] Running...'`n
foreach ($dUser in $dUsers) {
foreach ($group in $groups) {
$members = Get-ADGroupMember -Identity $group -Recursive | Select -ExpandProperty SamAccountName
if($members -contains $dUser) {
Write-Host "$dUser is a member of $group"
} Else {
# Remove or comment out the line below to get a clutterfree list.
# Write-Host "$dUser is not a member of $group"
}
}
}
You have two issues in your code:
You're creating a single string from the Get-ADUser output. Piping the output of that cmdlet through Format-Table (alias ft) and then Out-String creates one string with a tabular display of all matching account names including the table header.
If you output $dUsers in a way that makes beginning and end of a string visible you'd see something like this (the leading and trailing == marking the beginning and end):
PS> $dUsers | ForEach-Object { "==$_==" }
==samAccountName
--------------
user1
user2
user3==
Since there is no account with a username matching this string no match can be found in any group and you're getting the output you observed.
This misuse of Format-* cmdlets is a common beginner's mistake. People get a nicely formatted string output and then try to work with that. ONLY use Format-* cmdlets when you're presenting data directly to a user, NEVER when further processing of the data is required or intended.
What you actually want is not a string with a tabular display of usernames, but an array of username strings. You get that by expanding the SamAccountName property of the user objects you get from Get-ADUser.
$dUsers = Get-ADUser ... | Select-Object -Expand SamAccountName
The second issue is probably just a typo. Your condition $members -contains $dUsers won't work, since both $members and $dUsers are arrays (after fixing the first issue, that is). The -contains operator expects an array as the first operand and a single value as the second operand.
Change
$members -contains $dUsers
to
$members -contains $dUser
Depending on what PowerShell version you are on, there is a cmdlet for this use case and others.
As for
I'm Trying to loop all disabled users
Just do...
Search-ADAccount -AccountDisabled |
Select-Object -Property Name, Enabled,
#{Name = 'GroupName';Expression = {$_.DistinguishedName.Split(',')[1] -replace 'CN='}}
# Results
Name Enabled GroupName
---- ------- ---------
...
testuser2 NewTest False Users
Guest False Users
Or different cmdlet…
# Get disabled users and their group membership, display user and group name
ForEach ($TargetUser in (Get-ADUser -Filter {Enabled -eq $false}))
{
"`n" + "-"*12 + " Showing group membership for " + $TargetUser.SamAccountName
Get-ADPrincipalGroupMembership -Identity $TargetUser.SamAccountName | Select Name
}
# Results
...
------------ Showing group membership for testuser1
Domain Users
Users
------------ Showing group membership for testuser2
Domain Users
As for ...
an array of Groups
Just select or filter the DN for the group name you want using the normal comparison operators.
As for...
Unfortunately I'm not well versed in powershell.
… be sure to spend the necessary time to get ramped up on it, to limit the amount of misconceptions, confusions, errors, etc. that you are going to encounter. There are plenty of no cost / free video and text-based training / presentations all over the web.
Example:
Videos
Use tools that will write the code for you that you can later tweak as needed.
Step-By-Step: Utilizing PowerShell History Viewer in Windows Server 2012 R2
Learning PowerShell with Active Directory Administrative Center (PowerShell History Viewer)
As well as plenty of sample scripts and modules via the MS PowerShell Script / Module Gallery.
There are two commands for the AD Groups.
First I see that you want the membership of the disabled users that is easy.
#Get the dissabled users from your AD with all their attributes (properties and select)
$dUsers = Get-ADUser -Filter {Enabled -eq $false} -Properties * | Select *
#Run a loop for each user to get the group membership
Foreach ($User in $dUsers) {
$User = $User.SamAccountName
Get-ADUser $User -Properties * | Select Name, SamAccountName, MemberOf | Format-Table -Wrap # > "D:\test\$user.txt" -HideTableHeaders
}
This one can work but I don't like the output that we get.
I prefer to run the groupmembership command and check the users.
$GroupMembers = Get-ADGroupMember "groupname"| Select Name, SamAccountName
ForEach ($User in $GroupMembers)
{
$UserProperties = Get-ADUser $User.SamAccountName -Properties * | select *
If ($UserProperties.Enabled -eq $False) {
Write-Host $UserProperties.SamAccountName
}
}
Edit:
Let me know if those fits you.
Kind regards.
The first thing you should try to check is whenever you are only interested in direct memberships or indirect ones as well. Depending on the answer the options you got availabel change a bit. You probably will encounter Distinguished Names while working on this so check out what they are if you don't know (mostly a path for an object).
If it's only direct memberships using memberOf with Get-ADUser should be sufficient. The memberOf attribute contains every direct group membership of the user with the full Distinguished Name of the group.
Get-ADUser test -Properties MemberOf | Select-Object -ExpandProperty memberOf
You can match the groups you're looking for in various ways. You could get the whole Distinguished Name of those groups or you could do a partial match. It's up to you to decide how to proceed.
If you need the indirect memberships as well you might want to split up your code to make it easier for yourself. For instance you could first find the users and save them. Afterwards find all group members of those groups (You already got that with Get-ADGroupMember) and finally compare the two.
Currently for every user you build the whole list of group members again. This approach would save a few resources as you wouldn't be doing the same queries over and over again.
Finally you could also use the MemberOf approach but get the list of every direct and indirect membership of a user using an LDAP query.
$dn = (Get-ADUser example).DistinguishedName
$userGroups = Get-ADGroup -LDAPFilter ("(member:1.2.840.113556.1.4.1941:={0})" -f $dn)
This approach uses a LDAP search query. It can be quite complex, you could also only check for one one of the groups by modifying it a bit.
In the end even your current approach should work. The problem is that you're comparing the AD object against the list of SAM Accountnames. You would need to check for the SAM Accountnames as well.
if($members -contains $dUsers.SamAccountName)
if($members -contains $dUsers | Select-Object -ExpandProperty SamAccountName)
One of these should work if you change your $dUsers as well. As it currently is you end up with a giant string. You probably can check that by checking $dUsers.length. Just drop the Format-Table and Out-String.

Powershell get Multiple Value Property in List Format

Is it possible, to get a multiple string-values from an AD User property?
I have an property that contains various departments and want to get all departments, in list format.
Can I loop through this Array?
$bvsDepartments = Get-ADUser USER -Properties bvsDepartments | select bvsdepartments
output:
bvsdepartments
--------------
{Value1, Value2, Value3,...}
If you update your select with ExpandProperty this will give you an array of just the values rather than the property as an object.
$bvsDepartments = Get-ADUser USER -Properties bvsDepartments |
select -ExpandProperty bvsdepartments

AD nested group membership powershell reporting

We have following naming convention for shared resources:
sg_ShareName1_RO
sg_ShareName1_RW
sg_ShareName2_RO
sg_ShareName2_RW
I would like to get report in following format in Excel/csv:
ShareName1 ShareName2 ...
User1 RW NA
User2 NA RO
I'm fighting how to output Shared names to row in csv file instead of column.
Here is come code I've already done:
$users = GetADUser - filter {name like '*'} | sort name | select name
$sharegroups = Get-AdGroup -filter {name like 'sg_*'} | sort name
$shares = Get-AdGroup -filter {name like 'sg_*'} | sort name | foreach {$_} | select #{N='Share Name'; E={$_.Name.Replace('sg_', '').Replace('_', '').Replace('RO','').Replace('RW','')}} -Unique
Tnen to avoid trips to AD each time to check group membership first i would like to store members of each group in array
$sharegroupmembers = #{}
foreach ($group in $sharegroups)
{
$sharegroupmembers[$group.name] = Get-ADGroupMember $group.name -Recursive | select name
}
After that I'm stuck on howe to make correct projection of shares to columns, users to rows and RW/RO/NA to values based on group membership
Your number of columns is going to be the maximum number of group memeberships any user has. Those are in the values of $sharegroupmembers, so:
$shargroupmembers.values |
sort count |
select -last 1
That's how many rows you'll have, and how many share membership properties you'll need to create on your objects you're going to export.