Providers/AD/Private/New-ADTestCSVReport.ps1
|
function New-ADTestCSVReport { [CmdletBinding(SupportsShouldProcess = $true)] [OutputType([hashtable])] <# .SYNOPSIS Generates CSV reports from AD test data .DESCRIPTION Creates one or more CSV files from the provided test data, with separate files for each object type (users, devices, grou } } } }ervice accounts). Suitable for spreadsheet analysis and data import/export operations. .PARAMETER ReportData The report data hashtable containing all collected AD test information .PARAMETER OutputPath Base path for CSV files. Individual CSV files will be created with suffixes .PARAMETER IncludeDetails Include detailed object properties in the CSV output .PARAMETER IncludeGroupMembers Include group membership information in separate CSV files .EXAMPLE New-ADTestCSVReport -ReportData $data -OutputPath "C:\Reports\test" -IncludeDetails This creates files like: - C:\Reports\test_summary.csv - C:\Reports\test_users.csv - C:\Reports\test_devices.csv - C:\Reports\test_groups.csv - C:\Reports\test_serviceaccounts.csv .NOTES Author: Jeffrey Stuhr Version: 1.0.0 Last Updated: 2025-08-03 #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'Colour-coded console progress is intentional; results are returned as objects.')] [CmdletBinding()] param( [Parameter(Mandatory = $true)] [PSCustomObject]$ReportData, [Parameter(Mandatory = $true)] [string]$OutputPath ) begin { Write-Verbose "Starting CSV report generation" # For CSV reports, create a folder based on the output path # If OutputPath is "C:\temp\report.csv", create folder "C:\temp\report" and place CSVs inside $baseFileName = [System.IO.Path]::GetFileNameWithoutExtension($OutputPath) $parentDirectory = Split-Path $OutputPath -Parent if (-not $parentDirectory) { $parentDirectory = "." } # Create the report folder $baseDirectory = Join-Path $parentDirectory $baseFileName if (-not (Test-Path $baseDirectory)) { try { New-Item -Path $baseDirectory -ItemType Directory -Force | Out-Null Write-Host "Created CSV report folder: $baseDirectory" -ForegroundColor Yellow } catch { throw "Cannot create CSV report directory: $baseDirectory" } } $createdFiles = @() } process { try { Write-TestMessage -Message "Generating CSV reports: $OutputPath" -Type Info # Create summary CSV $summaryPath = Join-Path $baseDirectory "$baseFileName`_summary.csv" $summaryData = @( [PSCustomObject]@{ Category = "Organizational Units" Count = $ReportData.Summary.TotalOUs Description = "Test OU structure" } [PSCustomObject]@{ Category = "Users" Count = $ReportData.Summary.TotalUsers Description = "Test user accounts" } [PSCustomObject]@{ Category = "Service Accounts" Count = $ReportData.Summary.TotalServiceAccounts Description = "Test service accounts" } [PSCustomObject]@{ Category = "Devices" Count = $ReportData.Summary.TotalDevices Description = "Test device accounts" } [PSCustomObject]@{ Category = "Groups" Count = $ReportData.Summary.TotalGroups Description = "Test security groups" }, [PSCustomObject]@{ Category = "Group Members" Count = $ReportData.Summary.TotalGroupMembers Description = "Total group memberships" } ) $summaryData | Export-Csv -Path $summaryPath -NoTypeInformation -Encoding UTF8 $createdFiles += $summaryPath Write-Host "Summary CSV saved to: $summaryPath" -ForegroundColor Green # Always create detailed CSVs (this is what users expect to see) # Organizational Units CSV if ($ReportData.TestOUs.Count -gt 0) { $ouPath = Join-Path $baseDirectory "$baseFileName`_organizationalunits.csv" $ouData = @() foreach ($ou in $ReportData.TestOUs) { $ouData += [PSCustomObject]@{ Name = $ou.Name DistinguishedName = $ou.DistinguishedName Description = $ou.Description ProtectedFromAccidentalDeletion = $ou.ProtectedFromAccidentalDeletion Created = if ($ou.whenCreated) { $ou.whenCreated.ToString('yyyy-MM-dd HH:mm:ss') } else { '' } } } $ouData | Export-Csv -Path $ouPath -NoTypeInformation -Encoding UTF8 $createdFiles += $ouPath Write-Host "OUs CSV saved to: $ouPath" -ForegroundColor Green } # Users CSV if ($ReportData.TestUsers.Count -gt 0) { $usersPath = Join-Path $baseDirectory "$baseFileName`_users.csv" $userData = @() foreach ($user in $ReportData.TestUsers) { $userData += [PSCustomObject]@{ Name = $user.Name DisplayName = $user.DisplayName SamAccountName = $user.SamAccountName UserPrincipalName = $user.UserPrincipalName EmailAddress = $user.EmailAddress GivenName = $user.GivenName Surname = $user.Surname Department = $user.Department Title = $user.Title Manager = $user.Manager Description = $user.Description OfficePhone = $user.OfficePhone MobilePhone = $user.MobilePhone Office = $user.Office StreetAddress = $user.StreetAddress EmployeeID = $user.EmployeeID EmployeeType = $user.EmployeeType Enabled = $user.Enabled PasswordNeverExpires = $user.PasswordNeverExpires CannotChangePassword = $user.CannotChangePassword AccountExpirationDate = if ($user.AccountExpirationDate) { $user.AccountExpirationDate.ToString('yyyy-MM-dd HH:mm:ss') } else { '' } BadLogonCount = $user.BadLogonCount DistinguishedName = $user.DistinguishedName Created = if ($user.whenCreated) { $user.whenCreated.ToString('yyyy-MM-dd HH:mm:ss') } else { '' } Modified = if ($user.whenChanged) { $user.whenChanged.ToString('yyyy-MM-dd HH:mm:ss') } else { '' } LastLogon = if ($user.LastLogonDate) { $user.LastLogonDate.ToString('yyyy-MM-dd HH:mm:ss') } else { '' } PasswordLastSet = if ($user.PasswordLastSet) { $user.PasswordLastSet.ToString('yyyy-MM-dd HH:mm:ss') } else { '' } } } $userData | Export-Csv -Path $usersPath -NoTypeInformation -Encoding UTF8 $createdFiles += $usersPath Write-Host "Users CSV saved to: $usersPath" -ForegroundColor Green } # Service Accounts CSV if ($ReportData.TestServiceAccounts.Count -gt 0) { $serviceAccountsPath = Join-Path $baseDirectory "$baseFileName`_serviceaccounts.csv" $serviceAccountData = @() foreach ($serviceAccount in $ReportData.TestServiceAccounts) { $serviceAccountData += [PSCustomObject]@{ Name = $serviceAccount.Name DisplayName = $serviceAccount.DisplayName SamAccountName = $serviceAccount.SamAccountName UserPrincipalName = $serviceAccount.UserPrincipalName EmailAddress = $serviceAccount.EmailAddress Description = $serviceAccount.Description ServicePrincipalNames = if ($serviceAccount.ServicePrincipalNames) { $serviceAccount.ServicePrincipalNames -join "; " } else { '' } Manager = $serviceAccount.Manager Enabled = $serviceAccount.Enabled PasswordNeverExpires = $serviceAccount.PasswordNeverExpires CannotChangePassword = $serviceAccount.CannotChangePassword PasswordNotRequired = $serviceAccount.PasswordNotRequired SmartcardLogonRequired = $serviceAccount.SmartcardLogonRequired TrustedForDelegation = $serviceAccount.TrustedForDelegation AccountNotDelegated = $serviceAccount.AccountNotDelegated UseDESKeyOnly = $serviceAccount.UseDESKeyOnly DoesNotRequirePreAuth = $serviceAccount.DoesNotRequirePreAuth DistinguishedName = $serviceAccount.DistinguishedName Created = if ($serviceAccount.whenCreated) { $serviceAccount.whenCreated.ToString('yyyy-MM-dd HH:mm:ss') } else { '' } Modified = if ($serviceAccount.whenChanged) { $serviceAccount.whenChanged.ToString('yyyy-MM-dd HH:mm:ss') } else { '' } LastLogon = if ($serviceAccount.LastLogonDate) { $serviceAccount.LastLogonDate.ToString('yyyy-MM-dd HH:mm:ss') } else { '' } PasswordLastSet = if ($serviceAccount.PasswordLastSet) { $serviceAccount.PasswordLastSet.ToString('yyyy-MM-dd HH:mm:ss') } else { '' } AccountType = "ServiceAccount" } } $serviceAccountData | Export-Csv -Path $serviceAccountsPath -NoTypeInformation -Encoding UTF8 $createdFiles += $serviceAccountsPath Write-Host "Service Accounts CSV saved to: $serviceAccountsPath" -ForegroundColor Green } # Devices CSV if ($ReportData.TestDevices.Count -gt 0) { $devicesPath = Join-Path $baseDirectory "$baseFileName`_devices.csv" $deviceData = @() foreach ($device in $ReportData.TestDevices) { $deviceData += [PSCustomObject]@{ Name = $device.Name DNSHostName = $device.DNSHostName SamAccountName = $device.SamAccountName OperatingSystem = $device.OperatingSystem OperatingSystemVersion = $device.OperatingSystemVersion OperatingSystemServicePack = $device.OperatingSystemServicePack Description = $device.Description Location = $device.Location ManagedBy = $device.ManagedBy Enabled = $device.Enabled TrustedForDelegation = $device.TrustedForDelegation ServicePrincipalNames = if ($device.ServicePrincipalNames) { $device.ServicePrincipalNames -join "; " } else { '' } IPv4Address = $device.IPv4Address IPv6Address = $device.IPv6Address DistinguishedName = $device.DistinguishedName Created = if ($device.whenCreated) { $device.whenCreated.ToString('yyyy-MM-dd HH:mm:ss') } else { '' } Modified = if ($device.whenChanged) { $device.whenChanged.ToString('yyyy-MM-dd HH:mm:ss') } else { '' } LastLogon = if ($device.LastLogonDate) { $device.LastLogonDate.ToString('yyyy-MM-dd HH:mm:ss') } else { '' } PasswordLastSet = if ($device.PasswordLastSet) { $device.PasswordLastSet.ToString('yyyy-MM-dd HH:mm:ss') } else { '' } } } $deviceData | Export-Csv -Path $devicesPath -NoTypeInformation -Encoding UTF8 $createdFiles += $devicesPath Write-Host "Devices CSV saved to: $devicesPath" -ForegroundColor Green } # Groups CSV if ($ReportData.TestGroups.Count -gt 0) { $groupsPath = Join-Path $baseDirectory "$baseFileName`_groups.csv" $groupData = @() foreach ($group in $ReportData.TestGroups) { $groupData += [PSCustomObject]@{ Name = $group.Name DisplayName = $group.DisplayName SamAccountName = $group.SamAccountName Description = $group.Description GroupScope = $group.GroupScope GroupCategory = $group.GroupCategory ManagedBy = $group.ManagedBy Mail = $group.Mail HomePage = $group.HomePage Info = $group.Info MemberCount = $group.MemberCount Members = if ($group.Members) { ($group.Members | ForEach-Object { $_.Name }) -join "; " } else { "" } DistinguishedName = $group.DistinguishedName Created = if ($group.whenCreated) { $group.whenCreated.ToString('yyyy-MM-dd HH:mm:ss') } else { '' } Modified = if ($group.whenChanged) { $group.whenChanged.ToString('yyyy-MM-dd HH:mm:ss') } else { '' } } } $groupData | Export-Csv -Path $groupsPath -NoTypeInformation -Encoding UTF8 $createdFiles += $groupsPath Write-Host "Groups CSV saved to: $groupsPath" -ForegroundColor Green # Group Members CSV (always created when group data is available) $groupMembersPath = Join-Path $baseDirectory "$baseFileName`_groupmembers.csv" $memberData = @() foreach ($group in $ReportData.TestGroups) { if ($group.Members) { foreach ($member in $group.Members) { $memberData += [PSCustomObject]@{ GroupName = $group.Name GroupSamAccountName = $group.SamAccountName MemberName = $member.Name MemberSamAccountName = $member.SamAccountName MemberObjectClass = $member.objectClass MemberDistinguishedName = $member.DistinguishedName } } } } if ($memberData.Count -gt 0) { $memberData | Export-Csv -Path $groupMembersPath -NoTypeInformation -Encoding UTF8 $createdFiles += $groupMembersPath Write-Host "Group Members CSV saved to: $groupMembersPath" -ForegroundColor Green } } # Create a master file listing all generated CSVs $masterPath = Join-Path $baseDirectory "$baseFileName`_manifest.csv" $manifestData = @() foreach ($file in $createdFiles) { $fileInfo = Get-Item $file $manifestData += [PSCustomObject]@{ FileName = $fileInfo.Name FullPath = $fileInfo.FullName SizeKB = [math]::Round($fileInfo.Length / 1KB, 2) Created = $fileInfo.CreationTime.ToString('yyyy-MM-dd HH:mm:ss') Type = switch -Wildcard ($fileInfo.Name) { "*summary*" { "Summary" } "*users*" { "Users" } "*serviceaccounts*" { "Service Accounts" } "*devices*" { "Devices" } "*groups*" { "Groups" } "*groupmembers*" { "Group Members" } "*organizationalunits*" { "Organizational Units" } default { "Unknown" } } } } $manifestData | Export-Csv -Path $masterPath -NoTypeInformation -Encoding UTF8 Write-Host "CSV manifest saved to: $masterPath" -ForegroundColor Green } catch { Write-Error "Failed to generate CSV reports: $($_.Exception.Message)" -ErrorAction Stop } } end { Write-Verbose "Completed CSV report generation. Created $($createdFiles.Count) files." return @{ CreatedFiles = $createdFiles ManifestFile = $masterPath TotalFiles = $createdFiles.Count + 1 # +1 for manifest } } } |