Here is the issue I am facing. I am looking through a group variable. It pulls the information but it doesn't display it line by line. Instead, it will present the last groups info sometimes before the group members and then sometimes after. It seems to be dropping the process into a subprocess then continuing to the next line which might process faster. I know I am missing something simple. Here is the code:
foreach ($Groups in $Groups) {
Write-Host "---------- Group Info ----------" -ForegroundColor Yellow
$TempGroup = $Groups
$GroupInfo = Get-ADGroup -Filter "name -like '$TempGroup'" -Properties *
$GroupInfo | select Name,GroupScope,GroupCategory,mail,Created,Modified,DistinguishedName,Description | sort name
write-host "---------- Members ----------" -ForegroundColor Green
Get-ADGroupMember -Identity $GroupInfo.samaccountname -Recursive | select name,samaccountname,description | sort name | ft -AutoSize
write-host "---------- Nested Groups ----------" -ForegroundColor Green
Get-ADPrincipalGroupMembership -Identity $GroupInfo.samaccountname | select name,GroupScope,GroupCategory | sort name | ft -AutoSize | Wait-Job
}
Groups is an array.
Mixing Write-Host with default output from uncaught objects can give you strange results. Write-Host writes directly to the host (console), while the returned objects are sent down the pipeline until it reaches Out-Default (hidden cmdlet) which formats the objects and outputs them to the console (default output).
Pipe the objects directly to Out-Host to avoid this delay. Try:
foreach ($Group in $Groups) {
Write-Host "---------- Group Info ----------" -ForegroundColor Yellow
$TempGroup = $Group
$GroupInfo = Get-ADGroup -Filter "name -like '$TempGroup'" -Properties *
$GroupInfo | select Name,GroupScope,GroupCategory,mail,Created,Modified,DistinguishedName,Description | sort name | Out-Host
write-host "---------- Members ----------" -ForegroundColor Green
Get-ADGroupMember -Identity $GroupInfo.samaccountname -Recursive | select name,samaccountname,description | sort name | ft -AutoSize | Out-Host
write-host "---------- Nested Groups ----------" -ForegroundColor Green
Get-ADPrincipalGroupMembership -Identity $GroupInfo.samaccountname | select name,GroupScope,GroupCategory | sort name | ft -AutoSize | Out-Host
}
Also...
Wait-Job does nothing here because it never recieved a job-object from the cmdlets earlier in the pipeline.
You're using the same variable for the current object and the array in your foreach-loop. I can't remember if PowerShell understands your referring to the current item inside the loop, but at least it makes your code hard to read.
I'm not shure, but I think foreach($Groups in $Groups) could be a problem,
You should use foreach($Group in Groups){
}
Or do it in more Powershell syntax:
$Groups | Foreach{
Write-Host "---------- Group Info ----------" -ForegroundColor Yellow
$TempGroup = $_
$GroupInfo = Get-ADGroup -Filter "name -like '$TempGroup'" -Properties *
$GroupInfo | select Name,GroupScope,GroupCategory,mail,Created,Modified,DistinguishedName,Description | sort name
write-host "---------- Members ----------" -ForegroundColor Green
Get-ADGroupMember -Identity $GroupInfo.samaccountname -Recursive | select name,samaccountname,description | sort name | ft -AutoSize
write-host "---------- Nested Groups ----------" -ForegroundColor Green
Get-ADPrincipalGroupMembership -Identity $GroupInfo.samaccountname | select name,GroupScope,GroupCategory | sort name | ft -AutoSize | Wait-Job
}
Related
Hope all is well.
Trying to see if this possible.
Task: I have list of AD group that I need find members of each group. Only get the list active users.
Issue: I wanted to see if I can put the name of the group as Column name and Group Members under each column. Not sure if this possible. So far. I was only able to use Write-Output - Group and add extra line in way to difference each group.
$data = Import-Csv -Path C:\Source\Listofusers.csv
$results = Foreach ($datauser in $data)
{
$getadgroupmember = Get-ADGroupMember -Identity $datauser.ADGroups -Recursive | ? {$_.objectclass -eq "user"}
write-output "`n"
write-output $datauser.ADGroups
write-output "-----------------------------------------------------------------"
foreach ($activeanddisabledusers in $getadgroupmember)
{
Get-ADUser -Identity $activeanddisabledusers -Properties enabled | Where-Object {$_.Enabled -eq 'true'} | Select-Object -ExpandProperty SamAccountName}
}
My code:
$searchOU = "OU=a,OU=b,OU=c,OU=d,OU=e,DC=f,DC=g,DC=com"
Get-ADGroup -Filter 'GroupCategory -eq "Security"' -SearchBase $searchOU | sort name | ForEach- Object{
$group = $_
Get-ADGroupMember -Identity $group | Get-ADUser | Where-Object { $_.Enabled -eq $false} | ForEach-Object{
$user = $_
$uname = $user.Name
$gname = $group.Name
Write-Host "Removing $uname from $gname" -Foreground Yellow
Remove-ADGroupMember -Identity $group -Member $user -Confirm:$false #-whatif
}
}
It runs, but it's dog slow. Any suggestions on ways to make it run faster?
You need to remember that Get-ADGroupMember can return users, groups, and computers, not just user objects..
If you want to search for user objects only, you need to add a Where-Object clause there.
Unfortunately, while Get-ADUser has a -Filter parameter that enables you to find disabled users much more quickly than filtering afterwards on the collection of users, using a filter while piping user DN's to it will totally ignore the pipeline and collect all users that are disabled..
So, in this case, we're stuck with appending a Where-Object clause.
You could change your code to rule out all objects from Get-ADGroupMember that are not uders:
$searchOU = "OU=a,OU=b,OU=c,OU=d,OU=e,DC=f,DC=g,DC=com"
Get-ADGroup -Filter "GroupCategory -eq 'Security'" -SearchBase $searchOU | Sort-Object Name | ForEach-Object {
$group = $_
Get-ADGroupMember -Identity $group | Where-Object { $_.objectClass -eq 'user' } |
Get-ADUser | Where-Object { $_.Enabled -eq $false} | ForEach-Object {
Write-Host "Removing $($_.Name) from $($group.Name)" -Foreground Yellow
Remove-ADGroupMember -Identity $group -Member $_ -Confirm:$false #-whatif
}
}
The above removes one disabled user at a time and for each of them writes a line on the console.
You could make it work faster if you can cope with getting a different output on screen like this:
$searchOU = "OU=a,OU=b,OU=c,OU=d,OU=e,DC=f,DC=g,DC=com"
$result = foreach ($group in (Get-ADGroup -Filter "GroupCategory -eq 'Security'" -SearchBase $searchOU)) {
$users = Get-ADGroupMember -Identity $group | Where-Object { $_.objectClass -eq 'user' } |
Get-ADUser | Where-Object { $_.Enabled -eq $false}
if ($users) {
# the Remove-ADGroupMember cmdlet can take an array of users to remove at once
Remove-ADGroupMember -Identity $group -Member $users -Confirm:$false #-whatif
# output an object that gets collected in variable $result
[PsCustomObject]#{Group = $group.Name; RemovedUsers = ($users.Name -join '; ')}
}
}
# if you like, output to console as table
$result | Sort-Object Group | Format-Table -AutoSize -Wrap
# or write to CSV file
$result | Export-Csv -Path 'D:\Test\RemovedUsers.csv' -NoTypeInformation
I am having an issue with the output from one property as a comma separated value instead of a list in the out-gridview. Is there a way to have a value be added to the output as a list instead of a single line?
.'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1'
Connect-ExchangeServer -Auto -AllowClobber
do {
Write-Host
Write-Host
Write-Host
$name = Read-Host "What is the user's first name or letter?"
Write-Host
Write-Host
Write-Host
$list = Get-ADUser -Filter * | ? {$_.SamAccountName -match $name} |
select #{N="Highlight a User & Press Ctrl+C then Ctrl+V"; E={$_.SamAccountName}} |
sort SamAccountName |
Out-String
Write-Host -ForegroundColor Green $list
$box = Read-Host "Copy and paste the mailbox you want to see?"
$user = $box
$mailbox= Get-Mailbox -Identity $user | Get-MailboxStatistics |
Sort totalitemsize -desc |
select #{Name="User"; Expression={$_.DisplayName}},
#{Expression={"{0:N2}" -f($_.TotalItemSize.Value.ToMb()/1024)};label=”Mailbox Size in GB”},
#{Expression={"{0:N0}" -f($_.TotalItemSize.Value.ToMb())};label=”Mailbox Size in MB”},
#{Name="Message Count"; Expression={"{0:N0}" -f($_.itemcount)}},
#{Name="Database"; Expression={$_.DatabaseName}}
$folders= Get-MailboxFolderStatistics $user |
? {$_.ItemsInFolder -gt 0} |
Sort ItemsInFolder -Descending |
Select Name,
#{N="Items in Folder"; E={"{0:N0}" -f($_.ItemsInFolder)}},
#{N=”Folder Size in MB”;E={"{0:N0}" -f($_.FolderSize.ToMb())}}
$object= [PSCustomObject]#{
User = $mailbox.'User'
'Mailbox Size in MB'= $mailbox.'Mailbox Size in MB'
'Message Count' = $mailbox.'Message Count'
Database = $mailbox.Database
Name = $folders.Name
}
$object | Out-GridView
Write-Host
Write-Host
Write-Host
$runagain = Read-Host "Would you like to get another user's folder size?" | Out-String
Write-Host
Write-Host
}
while($runagain -like "y*")
Any help to get the $folders.Name to show as a list within the same out-Gridview would be great.
Thank you
You're probably looking for:
Name = $($folders.Name -join [Environment]::Newline)
This way you are not using an object anymore but are manually creating a list by joining the elements with a new line.
I'm trying to list only unique HomeDrive for all users in a Universal Security group and remove nested groups errors.
Thanks for your help.
Denis
I've tried .TrimEnd(':'), can't seem to figure out where to put it
$Group = "Universal Security group"
$HomeDrive = Get-ADGroupMember $Group | `
ForEach-Object {
$UserName = $_.Name
Try {
#$ErrorActionPreference = "Stop"
Get-ADUser $UserName -Properties HomeDrive | Select HomeDrive
}
Catch {
Write-Host "Found a nested Group."
}
} | Sort-Object -Property 'HomeDrive' -Unique | Format-Table -HideTableHeaders | Out-String
Write-Host "$HomeDrive" -BackgroundColor DarkRed
The script does work but some users have their homedrives listed as only F while most are listed as F:. Basically making a lot of double entries and I do want the output to be only F. Also it generates 7 spaces after the :, That's why I have the background color.
Something like this:
$group = "Universal Security group"
$homeDrives = Get-ADGroupMember $Group |
ForEach-Object {
if ($_.ObjectClass -eq "User")
{
$user = Get-ADUser $_.Name -Properties "HomeDrive"
$homeDrive = $user.HomeDrive.Trim().TrimEnd(":")
return $homeDrive
}
} | Sort-Object -Unique
foreach ($homeDrive in $homeDrives)
{
Write-Host "Found home drive: $homeDrive" -BackgroundColor DarkRed
}
Bear with me on my first question on any online forum ever. =]
My intent is to use PowerShell to create a csv with the following information:
Group Name (only print groups whose name match text string "O365")*
What users are a member of this group.
What are the user emails for each of these members
Currently, My script is as follows.
Get-ADGroup -filter {name -like "O365*"} -properties GroupCategory |
Select-Object -ExpandProperty name |
get-adgroupmember |
where {$_.objectclass -eq 'user'} |
Get-ADUSer -properties Displayname,Description,Mail |
Select Name,Displayname,Mail
This result provides me with:
1 column for Displayname
1 column for Mail
I feel as though I have missed the answer time and time again after researching this for a while. Most people seem content to do this similar task without filtering the ADGroup cmdlet, but that would take too long for me.
As a newbie, I am excited to hear from anyone who'll take the time to answer.
Thank you.
So you want the users that are the member of a group with a name matching "O365* And they need to be displayed as
Group.Name | User.DisplayName | User.Mail
Simply looking at the question one could think the following code would do the trick and it works but there is a catch ......
cls
$ErrorActionPreference = "stop"
#$VerbosePreference = "Continue"
#$DebugPreference = "Continue"
Write-Verbose "Retrieving the ADGroups"
$Groups = Get-ADGroup -filter {name -like "O365*"}
Write-Debug ($Groups | Select Name | Format-Table | Out-String)
$UserList = #()
Foreach ($Group in $Groups) {
Write-Verbose "Processing Group $Group"
$GroupMembers = $Group | Get-ADGroupMember
Write-Debug "GroupMembers: $($GroupMembers | Select Name | Format-Table | Out-String)"
Foreach ($GroupMember in $GroupMembers) {
Write-Verbose "Processing GroupMember $GroupMember"
Write-Debug "GroupMember $($GroupMember | Out-String)"
if (!($GroupMember.objectClass -eq "user")) {
Write-Warning "GroupMember $($GroupMember) is not of type 'User', Skipping"
Continue
}
else {
Try {
$UserList += ($GroupMember | Get-ADUSer -properties Mail | Select #{N="Group"; E={$Group.Name}}, Name, Mail)
Write-Verbose "user $GroupMember has been added to the list."
}
Catch {
Write-Warning "An error ocurd while adding user $GroupMember to the list."
Continue
}
}
}
}
$UserList
If the o365 groups contain other groups then the members of these subgroups will not be included.
Output Example
WARNING: GroupMember CN=subgroup,OU=Custom,DC=DOMAIN,DC=TLD is not of type 'User', Skipping
Group Name Mail
----- ---- ----
o365-SubscriptionA User U. UserLand User#Domain.tld
o365-SubscriptionA User2 U2. UserLand User2#Domain.tld
o365-SubscriptionB User U. UserLand User#Domain.tld