Forum Discussion
Jul 14, 2022
Blogpost - Report on changed Active Directory groups using PowerShell
Wrote a blog post on how to monitor Active Directory admin groups and how to log/report changes on them. The script below monitors the groups you specify and emails them to an admin address if there are changes.
(More details here https://powershellisfun.com/2022/07/13/report-on-changed-active-directory-groups-using-powershell/ )
#Set Logs folder
$logs = 'c:\scripts\logs'
#Create Logs folder it it doesn't exist
if (-not (Test-Path -Path $logs -PathType Any)) {
    New-Item -Path $logs -ItemType Directory | Out-Null
}
#Start Transcript logging to $logs\run.log
Start-Transcript -Path "$($logs)\run.log" -Append
#Configure groups to monitor
$admingroups = @(
    "Account Operators",
    "Administrators",
    "Backup Operators",
    "Domain Admins",
    "DNSAdmins",
    "Enterprise Admins",
    "Group Policy Creator Owners",
    "Schema Admins",
    "Server Operators"
)
#rename previous currentmembers.csv to previousmembers.csv and rename the old
#previousmembers.csv to one with a time-stamp for archiving
if (Test-Path -Path "$($logs)\previousmembers.csv" -ErrorAction SilentlyContinue) {
    #Set date format variable
    $date = Get-Date -Format 'dd-MM-yyyy-HHMM'
    Write-Host ("- Renaming previousmembers.csv to {0}_previousmembers.csv" -f $date) -ForegroundColor Green
    Move-Item -Path "$($logs)\previousmembers.csv" -Destination "$($logs)\$($date)_previousmembers.csv" -Confirm:$false -Force:$true
}
if (Test-Path -Path "$($logs)\currentmembers.csv" -ErrorAction SilentlyContinue) {
    Write-Host ("- Renaming currentmembers.csv to previousmembers.csv") -ForegroundColor Green
    Move-Item -Path "$($logs)\currentmembers.csv" -Destination "$($logs)\previousmembers.csv" -Confirm:$false -Force:$true
}
#Retrieve all direct members of the admingroups,
#store them in the members variable and output
#them to currentmembers.csv
$members = foreach ($admingroup in $admingroups) {
    Write-Host ("- Checking {0}" -f $admingroup) -ForegroundColor Green
    try {
        $admingroupmembers = Get-ADGroupMember -Identity $admingroup -Recursive -ErrorAction Stop | Sort-Object SamAccountName
    }
    catch {
        Write-Warning ("Members of {0} can't be retrieved, skipping..." -f $admingroup)
        $admingroupmembers = $null
    }
    if ($null -ne $admingroupmembers) {
        foreach ($admingroupmember in $admingroupmembers) {
            Write-Host ("  - Adding {0} to list" -f $admingroupmember.SamAccountName) -ForegroundColor Green
            [PSCustomObject]@{
                Group  = $admingroup
                Member = $admingroupmember.SamAccountName
            }
        }
    }
}
#Save found members to currentmembers.csv and create previousmembers.csv if not present (First Run)
Write-Host ("- Exporting results to currentmembers.csv") -ForegroundColor Green
$members | export-csv -Path "$($logs)\currentmembers.csv" -NoTypeInformation -Encoding UTF8 -Delimiter ';'
if (-not (Test-Path "$($logs)\previousmembers.csv")) {
    $members | export-csv -Path "$($logs)\previousmembers.csv" -NoTypeInformation -Encoding UTF8 -Delimiter ';'
}
#Compare currentmembers.csv to the #previousmembers.csv
$CurrentMembers = Import-Csv -Path "$($logs)\currentmembers.csv" -Delimiter ';'
$PreviousMembers = Import-Csv -Path "$($logs)\previousmembers.csv" -Delimiter ';'
Write-Host ("- Comparing current members to the previous members") -ForegroundColor Green
$compare = Compare-Object -ReferenceObject $PreviousMembers -DifferenceObject $CurrentMembers -Property Group, Member
if ($null -ne $compare) {
    $differencetotal = foreach ($change in $compare) {
        if ($change.SideIndicator -match ">") {
            $action = 'Added'
        }
        if ($change.SideIndicator -match "<") {
            $action = 'Removed'
        }
        [PSCustomObject]@{
            Date   = $date
            Group  = $change.Group
            Action = $action
            Member = $change.Member
        }
    }
    #Save output to file
    $differencetotal | Sort-Object group | Out-File "$($logs)\$($date)_changes.txt"
    #Send email with changes to admin email address
    Write-Host ("- Emailing detected changes") -ForegroundColor Green
    $body = Get-Content "$($logs)\$($date)_changes.txt" | Out-String
    $options = @{
        Body        = $body
        Erroraction = 'Stop'
        From        = 'email address removed for privacy reasons'
        Priority    = 'High'
        Subject     = "Admin group change detected"
        SmtpServer  = 'emailserver.domain.local'
        To          = 'email address removed for privacy reasons'     
    }
    
    try {
        Send-MailMessage @options
    }
    catch {
        Write-Warning ("- Error sending email, please check the email options")
    }
}
else {
    Write-Host ("No changes detected") -ForegroundColor Green
}
Stop-Transcript
2 Replies
- SchnittlauchIron ContributorWould love to see this script github 🙂
- It's mentioned at the end of the blogpost 🙂 But here it is: https://github.com/HarmVeenstra/Powershellisfun/tree/main/Active%20Directory%20Admin%20Group%20Change%20Report