Add 12 AI-generated PowerShell scripts with documentation
⚠️ IMPORTANT: These scripts are AI-GENERATED and UNTESTED Exchange Scripts (5): - Get-MailboxPermissions.ps1: Audit delegate access permissions - Get-InactiveMailboxes.ps1: Identify stale mailboxes - Compare-MailboxDatabases.ps1: Database health comparison - Export-DistributionGroups.ps1: Distribution group inventory - Get-MailflowStats.ps1: Transport log analysis Active Directory Scripts (3): - Get-ADUserLastLogon.ps1: True LastLogon across all DCs - Export-OUStructure.ps1: OU hierarchy with GPO links - Compare-ADGroupMemberships.ps1: Compare user group memberships System Maintenance Scripts (4): - Get-ServerInventory.ps1: Hardware/software inventory report - Monitor-DiskSpace.ps1: Disk space monitoring with alerts - Backup-ExchangeCertificates.ps1: Certificate backup to PFX - Test-ExchangeHealth.ps1: Aggregated Exchange health checks Documentation: - Updated CLAUDE.md with AI-generated scripts section - Added AI-GENERATED-SCRIPTS.md with warnings and testing guide All scripts include prominent warnings and follow established patterns from existing scripts. Require thorough testing before production use. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
201
ActiveDirectory/Export-OUStructure.ps1
Normal file
201
ActiveDirectory/Export-OUStructure.ps1
Normal file
@ -0,0 +1,201 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Export Active Directory OU structure with GPO links
|
||||
|
||||
.DESCRIPTION
|
||||
Documents the complete OU hierarchy including GPO links, inheritance settings,
|
||||
and description. Useful for documentation, disaster recovery, or comparing
|
||||
environments.
|
||||
|
||||
.PARAMETER OutputFolder
|
||||
Destination folder for reports. Default: .\OU-Structure-<date>
|
||||
|
||||
.PARAMETER IncludeGPODetails
|
||||
Include detailed GPO information (default: $true)
|
||||
|
||||
.PARAMETER SearchBase
|
||||
Optional starting point for OU export (default: domain root)
|
||||
|
||||
.NOTES
|
||||
⚠️ AI-GENERATED SCRIPT - UNTESTED
|
||||
This script was generated by Claude AI and has not been tested in production.
|
||||
Review and test thoroughly in a non-production environment before use.
|
||||
|
||||
- Requires Active Directory PowerShell module
|
||||
- Run with appropriate AD permissions
|
||||
- Exports to both CSV (detailed) and TXT (tree view)
|
||||
|
||||
.EXAMPLE
|
||||
.\Export-OUStructure.ps1
|
||||
|
||||
.EXAMPLE
|
||||
.\Export-OUStructure.ps1 -SearchBase "OU=Departments,DC=domain,DC=com"
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$OutputFolder = (Join-Path -Path (Get-Location) -ChildPath ("OU-Structure-" + (Get-Date -Format "yyyyMMdd-HHmm"))),
|
||||
[bool]$IncludeGPODetails = $true,
|
||||
[string]$SearchBase = ""
|
||||
)
|
||||
|
||||
function NowTag { (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") }
|
||||
|
||||
Write-Host "[$(NowTag)] ⚠️ AI-GENERATED SCRIPT - UNTESTED" -ForegroundColor Yellow
|
||||
Write-Host "[$(NowTag)] Exporting OU structure..." -ForegroundColor Green
|
||||
|
||||
# Import AD module
|
||||
try {
|
||||
Import-Module ActiveDirectory -ErrorAction Stop
|
||||
} catch {
|
||||
Write-Host "[$(NowTag)] ERROR: Active Directory module not available" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Create output folder
|
||||
New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null
|
||||
|
||||
# Get domain info
|
||||
$domain = Get-ADDomain
|
||||
if (-not $SearchBase) {
|
||||
$SearchBase = $domain.DistinguishedName
|
||||
}
|
||||
|
||||
Write-Host "[$(NowTag)] Domain: $($domain.DNSRoot)"
|
||||
Write-Host "[$(NowTag)] Search Base: $SearchBase"
|
||||
|
||||
# Get all OUs
|
||||
Write-Host "[$(NowTag)] Retrieving organizational units..."
|
||||
$ouParams = @{
|
||||
Filter = '*'
|
||||
SearchBase = $SearchBase
|
||||
Properties = @('Description', 'gPLink', 'gPOptions', 'ProtectedFromAccidentalDeletion', 'WhenCreated', 'WhenChanged')
|
||||
}
|
||||
|
||||
$ous = Get-ADOrganizationalUnit @ouParams | Sort-Object DistinguishedName
|
||||
|
||||
$ouCount = ($ous | Measure-Object).Count
|
||||
Write-Host "[$(NowTag)] Found $ouCount organizational unit(s)"
|
||||
|
||||
# Build GPO name lookup if requested
|
||||
$gpoLookup = @{}
|
||||
if ($IncludeGPODetails) {
|
||||
Write-Host "[$(NowTag)] Building GPO lookup table..."
|
||||
try {
|
||||
Import-Module GroupPolicy -ErrorAction Stop
|
||||
$gpos = Get-GPO -All -ErrorAction SilentlyContinue
|
||||
foreach ($gpo in $gpos) {
|
||||
$gpoLookup[$gpo.Id.ToString()] = $gpo.DisplayName
|
||||
}
|
||||
Write-Host "[$(NowTag)] Found $($gpos.Count) GPO(s)"
|
||||
} catch {
|
||||
Write-Host "[$(NowTag)] WARNING: Could not load GroupPolicy module - GPO names will show as GUIDs" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
|
||||
# Process OUs
|
||||
$ouDetails = @()
|
||||
$treeLines = @()
|
||||
|
||||
foreach ($ou in $ous) {
|
||||
# Calculate depth for tree view
|
||||
$depth = ($ou.DistinguishedName -split ',OU=').Count - 1
|
||||
$indent = " " * $depth
|
||||
|
||||
# Parse GPO links
|
||||
$gpoLinks = @()
|
||||
$gpoNames = @()
|
||||
|
||||
if ($ou.gPLink) {
|
||||
# gPLink format: [LDAP://cn={GUID},cn=policies,cn=system,DC=domain,DC=com;0]
|
||||
$links = $ou.gPLink -split '\]\[' -replace '^\[' -replace '\]$'
|
||||
|
||||
foreach ($link in $links) {
|
||||
if ($link -match '\{([^\}]+)\}') {
|
||||
$gpoGuid = $matches[1]
|
||||
$gpoName = if ($gpoLookup.ContainsKey($gpoGuid)) {
|
||||
$gpoLookup[$gpoGuid]
|
||||
} else {
|
||||
$gpoGuid
|
||||
}
|
||||
|
||||
# Parse link order and enforcement
|
||||
$linkOrder = if ($link -match ';(\d+)') { $matches[1] } else { "0" }
|
||||
$enforced = $linkOrder -band 1 # Bit 0 indicates enforcement
|
||||
$disabled = $linkOrder -band 2 # Bit 1 indicates disabled
|
||||
|
||||
$gpoNames += $gpoName
|
||||
$gpoLinks += [PSCustomObject]@{
|
||||
OU = $ou.Name
|
||||
GPOName = $gpoName
|
||||
GPOGUID = $gpoGuid
|
||||
LinkOrder = $linkOrder
|
||||
Enforced = ($enforced -eq 1)
|
||||
Disabled = ($disabled -eq 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# GPO inheritance blocked?
|
||||
$inheritanceBlocked = ($ou.gPOptions -eq 1)
|
||||
|
||||
# Tree view line
|
||||
$protectedMark = if ($ou.ProtectedFromAccidentalDeletion) { "[P]" } else { "" }
|
||||
$inheritMark = if ($inheritanceBlocked) { "[BLOCKED]" } else { "" }
|
||||
$gpoMark = if ($gpoNames.Count -gt 0) { " (GPOs: $($gpoNames -join ', '))" } else { "" }
|
||||
|
||||
$treeLines += "$indent$($ou.Name) $protectedMark$inheritMark$gpoMark"
|
||||
|
||||
# Detailed record
|
||||
$ouDetails += [PSCustomObject]@{
|
||||
Name = $ou.Name
|
||||
DistinguishedName = $ou.DistinguishedName
|
||||
Description = $ou.Description
|
||||
ProtectedFromAccidentalDeletion = $ou.ProtectedFromAccidentalDeletion
|
||||
GPOInheritanceBlocked = $inheritanceBlocked
|
||||
LinkedGPOs = ($gpoNames -join "; ")
|
||||
LinkedGPOCount = $gpoNames.Count
|
||||
WhenCreated = $ou.WhenCreated
|
||||
WhenChanged = $ou.WhenChanged
|
||||
}
|
||||
}
|
||||
|
||||
# Export detailed CSV
|
||||
$csvFile = Join-Path $OutputFolder "OU-Structure.csv"
|
||||
$ouDetails | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $csvFile
|
||||
Write-Host "[$(NowTag)] OU details exported: $csvFile" -ForegroundColor Green
|
||||
|
||||
# Export GPO links if available
|
||||
if ($IncludeGPODetails -and $gpoLinks.Count -gt 0) {
|
||||
$gpoLinksFile = Join-Path $OutputFolder "OU-GPO-Links.csv"
|
||||
$gpoLinks | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $gpoLinksFile
|
||||
Write-Host "[$(NowTag)] GPO links exported: $gpoLinksFile" -ForegroundColor Green
|
||||
}
|
||||
|
||||
# Export tree view
|
||||
$treeFile = Join-Path $OutputFolder "OU-Tree.txt"
|
||||
$treeHeader = @"
|
||||
Active Directory OU Structure
|
||||
Domain: $($domain.DNSRoot)
|
||||
Search Base: $SearchBase
|
||||
Generated: $(Get-Date)
|
||||
|
||||
Legend:
|
||||
[P] = Protected from Accidental Deletion
|
||||
[BLOCKED] = GPO Inheritance Blocked
|
||||
|
||||
"@
|
||||
|
||||
$treeHeader | Out-File -FilePath $treeFile -Encoding UTF8
|
||||
$treeLines | Out-File -FilePath $treeFile -Encoding UTF8 -Append
|
||||
Write-Host "[$(NowTag)] Tree view exported: $treeFile" -ForegroundColor Green
|
||||
|
||||
# Summary
|
||||
Write-Host "`nOU STRUCTURE SUMMARY:" -ForegroundColor Cyan
|
||||
Write-Host " Total OUs: $ouCount"
|
||||
Write-Host " Protected OUs: $(($ouDetails | Where-Object ProtectedFromAccidentalDeletion).Count)"
|
||||
Write-Host " OUs with GPO Inheritance Blocked: $(($ouDetails | Where-Object GPOInheritanceBlocked).Count)"
|
||||
Write-Host " OUs with Linked GPOs: $(($ouDetails | Where-Object { $_.LinkedGPOCount -gt 0 }).Count)"
|
||||
|
||||
Write-Host "`n[$(NowTag)] Export complete! Output folder: $OutputFolder"
|
||||
Reference in New Issue
Block a user