Public/Export-ADUserReport.ps1

function Export-ADUserReport {
    <#
    .SYNOPSIS
        Generates a comprehensive Active Directory user report in HTML or CSV format.
 
    .DESCRIPTION
        Exports AD user data with flexible filtering and multiple output formats.
        Useful for audits, compliance reviews, and management reporting.
 
        Report includes: name, title, department, email, last logon, account status,
        password last set, group memberships, and manager.
 
    .PARAMETER SearchBase
        The OU Distinguished Name to scope the search. Defaults to the entire domain.
 
    .PARAMETER Filter
        AD filter string. Defaults to all enabled users with email addresses.
 
    .PARAMETER IncludeDisabled
        Include disabled accounts in the report.
 
    .PARAMETER OutputFormat
        Output format: HTML, CSV, or Both. Defaults to HTML.
 
    .PARAMETER OutputPath
        Directory to save the report. Defaults to current directory.
 
    .PARAMETER DaysInactive
        Flag users who haven't logged in within this many days. Defaults to 90.
 
    .EXAMPLE
        Export-ADUserReport -OutputFormat HTML
 
        Generates an HTML report of all enabled users to the current directory.
 
    .EXAMPLE
        Export-ADUserReport -SearchBase "OU=Sales,DC=contoso,DC=com" -OutputFormat Both -DaysInactive 60
 
        Reports on Sales OU users, flagging those inactive for 60+ days, in both formats.
 
    .EXAMPLE
        Export-ADUserReport -IncludeDisabled -OutputPath "\\server\reports"
 
        Full user report including disabled accounts, saved to a file share.
 
    .NOTES
        Requires: ActiveDirectory module, read access to AD.
    #>

    [CmdletBinding()]
    param(
        [string]$SearchBase,

        [string]$Filter = "Enabled -eq `$true",

        [switch]$IncludeDisabled,

        [ValidateSet('HTML', 'CSV', 'Both')]
        [string]$OutputFormat = 'HTML',

        [string]$OutputPath = '.',

        [int]$DaysInactive = 90
    )

    begin {
        Import-Module ActiveDirectory -ErrorAction Stop

        if (-not (Test-Path $OutputPath)) {
            New-Item -Path $OutputPath -ItemType Directory -Force | Out-Null
        }

        $reportDate = Get-Date -Format 'yyyyMMdd-HHmmss'
        $inactiveThreshold = (Get-Date).AddDays(-$DaysInactive)

        if ($IncludeDisabled) {
            $Filter = '*'
        }
    }

    process {
        # Build Get-ADUser parameters
        $adParams = @{
            Filter     = $Filter
            Properties = @(
                'DisplayName', 'Title', 'Department', 'Company', 'EmailAddress',
                'LastLogonDate', 'PasswordLastSet', 'PasswordNeverExpires',
                'WhenCreated', 'MemberOf', 'Manager', 'Enabled', 'LockedOut',
                'HomeDirectory', 'Description'
            )
        }
        if ($SearchBase) {
            $adParams['SearchBase'] = $SearchBase
        }

        Write-Verbose "Querying Active Directory..."
        $users = Get-ADUser @adParams

        Write-Verbose "Processing $($users.Count) users..."
        $report = foreach ($user in $users) {
            $managerName = if ($user.Manager) {
                try { (Get-ADUser $user.Manager).Name } catch { $user.Manager }
            }
            else { '' }

            $groupList = ($user.MemberOf | ForEach-Object {
                try { (Get-ADGroup $_).Name } catch { $_ }
            }) -join '; '

            $isInactive = $user.LastLogonDate -and ($user.LastLogonDate -lt $inactiveThreshold)
            $neverLoggedOn = -not $user.LastLogonDate

            [PSCustomObject]@{
                SAMAccountName       = $user.SAMAccountName
                DisplayName          = $user.DisplayName
                Title                = $user.Title
                Department           = $user.Department
                Company              = $user.Company
                Email                = $user.EmailAddress
                Enabled              = $user.Enabled
                LockedOut            = $user.LockedOut
                LastLogon            = $user.LastLogonDate
                Inactive             = $isInactive
                NeverLoggedOn        = $neverLoggedOn
                PasswordLastSet      = $user.PasswordLastSet
                PasswordNeverExpires = $user.PasswordNeverExpires
                Created              = $user.WhenCreated
                Manager              = $managerName
                Groups               = $groupList
                HomeDirectory        = $user.HomeDirectory
                Description          = $user.Description
            }
        }

        # Output to requested format(s)
        if ($OutputFormat -in @('CSV', 'Both')) {
            $csvFile = Join-Path $OutputPath "AD-UserReport-$reportDate.csv"
            $report | Export-Csv -Path $csvFile -NoTypeInformation
            Write-Verbose "CSV saved: $csvFile"
        }

        if ($OutputFormat -in @('HTML', 'Both')) {
            $htmlFile = Join-Path $OutputPath "AD-UserReport-$reportDate.html"
            $htmlReport = _New-HtmlReport -Title "Active Directory User Report" -Data $report -GeneratedDate (Get-Date)
            $htmlReport | Out-File -FilePath $htmlFile -Encoding UTF8
            Write-Verbose "HTML saved: $htmlFile"
        }

        # Return objects to the pipeline
        $report
    }
}