My goal is to dump a CSV of our AD groups, their members, and whether those member objects are enabled, but I'm running into a strange (probably self-inflicted) issue, wherein a Foreach-Object loop is behaving unexpectedly.
The output almost works. It dumps a CSV file. The file has rows for each group, populated with the correct group-related data, and the right number of rows, following the number of group members. However, group member properties on those rows is repeated, showing the same user data over and over for each groupmember result, apparently following the properties of the last returned object from Get-ADGroupMember.
To try to diagnose the issue, I added the line Write-Host $GroupMember.Name -ForegroundColor Gray
. This is how I knew the entries in the CSV were the last-returned results for each group. Confusingly, the console correctly echoes each group member's display name.
I'm assuming there's some kind of logic error at work here, but I have had no luck finding it. Any help would be appreciated!
clear
Import-Module ActiveDirectory
# CONFIG ========================================
# Plant Number OU to scan. Used in $CSV and in Get-ADComputer's search base.
$PlantNumber = "1234"
# FQDN of DC you want to query against. Used by the Get-AD* commands.
$ServerName = "server.com"
# Output directory for the CSV. Default is [Environment]::GetFolderPath("Desktop"). Used in $CSV. NOTE: If setting up as an automated task, change this to a more sensible place!
$OutputDir = [Environment]::GetFolderPath("Desktop")
# CSV Output string. Default is "$OutputDir\$PlantNumber"+"-ComputersByOS_"+"$(get-date -f yyyy-MM-dd).csv" (+'s used due to underscores in name)
$CSV = "$OutputDir\$PlantNumber"+"GroupMembers_"+"$(get-date -f yyyy-MM-dd).csv"
# Create empty array for storing collated results
$collectionTable = @()
# Get AD groups, return limited properties
Get-AdGroup -filter * -Property Name, SamAccountName, Description, GroupScope -SearchBase "OU=Security Groups,OU=$PlantNumber,OU=Plants,DC=SERVER,DC=COM" -server $ServerName | Select SamAccountName, Description, GroupScope | Foreach-Object {
Write-Host "Querying" $_.SamAccountName "..."
#Initialize $collectionRow, providing the columns we want to collate
$collectionRow = "" | Select GroupName, GroupScope, GroupDesc, MemberObjectClass, MemberName, MemberDisplayName, Enabled
# Populate Group-level collectionRow properties
$collectionRow.GroupName = $_.SamAccountName
$collectionRow.GroupDesc = $_.Description
$collectionRow.GroupScope = $_.GroupScope
# Process group members
Get-ADGroupMember -Identity ($collectionRow.GroupName) -Server $ServerName -Recursive | ForEach-Object {
$GroupMember = $_
# Echo member name to console
Write-Host $GroupMember.Name -ForegroundColor Gray
$collectionRow.MemberName = $GroupMember.SamAccountName
$collectionRow.MemberDisplayName = $GroupMember.name
$collectionRow.MemberObjectClass = $GroupMember.ObjectClass
# If the member object is a user, collect some additional data
If ($collectionRow.MemberObjectClass -eq "user") {
Try {
$collectionRow.Enabled = (Get-ADUser $GroupMember.SamAccountName -Property Enabled -ErrorAction Stop).Enabled
If ($collectionRow.Enabled -eq "TRUE") {$collectionTable += $collectionRow}
}
Catch {
$collectionRow.Enabled = "ERROR"
$collectionTable += $collectionRow
}
}
}
}
Write-Host "`n"
# Attempt to save results to CSV. If an error occurs, alert the user and try again.
$ExportSuccess = 'false'
while ($ExportSuccess -eq 'false') {
Try
{
# Export results to $CSV
$collectionTable| Export-csv $CSV -NoTypeInformation -ErrorAction Stop
# If the above command is successful, the rest of the Try section will execute. If not, Catch is triggered instead.
$ExportSuccess = 'true'
Write-Host "`nProcessing complete. Results output to"$CSV
}
Catch
{
Write-Host "Error writing to"$CSV"!" -ForegroundColor Yellow
Read-Host -Prompt "Ensure the file is not open, then press any key to try again"
}
}