<# .SYNOPSIS This script monitors the membership of a specified Active Directory group. It can log changes in group membership to a specified log file and update a previous state file for future comparisons. .DESCRIPTION The script retrieves the current members of a specified Active Directory group and compares them to a previously saved state. It can output changes to the console when run in monitor mode, and it can update the previous state file when requested. The script supports the following parameters: -GroupName: The name of the Active Directory group to monitor. -Monitor: Outputs changes in group membership without updating the previous state file. -Update: Updates the previous state file with the current group members. .PARAMETER GroupName The name of the Active Directory group to monitor. .PARAMETER Monitor Switch parameter that, when specified, outputs changes in group membership without updating the previous state file. .PARAMETER Update Switch parameter that, when specified, updates the previous state file with the current group members. .OUTPUTS Exit codes: 0: Successful execution (no errors). 1: Error retrieving group members (e.g., the group does not exist or there is a permission issue). 2: Changes detected in group membership when using the -Monitor parameter. .EXAMPLE .\Win - Active Directory Group monitoring.ps1 -GroupName "YourGroupName" -Monitor This command checks for changes in the specified group and outputs them to the console. .EXAMPLE .\Win - Active Directory Group monitoring.ps1 -GroupName "YourGroupName" -Update This command updates the previous state file with the current members of the specified group. .EXAMPLE .\Win - Active Directory Group monitoring.ps1 -GroupName "YourGroupName" -Monitor -Update This command checks for changes in the specified group and updates the previous state file. #> param ( [Parameter(Mandatory=$true)] [string]$GroupName, [switch]$Monitor, [switch]$Update ) # Check if either Monitor or Update is specified if (-not $Monitor -and -not $Update) { Write-Host "Error: You must specify either -Monitor or -Update." exit 1 # Exit code 1: Neither Monitor nor Update specified } # Define Toolbox path $ToolboxPath = "C:\ProgramData\TacticalRMM\toolbox\Groupmonitoring" if (!(test-path $ToolboxPath)) {mkdir $ToolboxPath} # Define the path to the log file $logFilePath = "$ToolboxPath\Log-$GroupName-$(Get-Date -Format "yyyy-MM-dd-HHmmss").txt" # Define the path to the previous state file $previousStateFilePath = "$ToolboxPath\$Groupname.json" # Function to get group members function Get-GroupMembers { param ( [string]$groupName ) try { $group = Get-ADGroup -Identity $groupName -ErrorAction Stop $members = Get-ADGroupMember -Identity $group -Recursive | Select-Object -ExpandProperty SamAccountName return $members } catch { Write-Host "Error retrieving members for group: $groupName. $_" return @() } } # Load previous state if it exists $previousState = @{} if (Test-Path $previousStateFilePath) { $previousState = Get-Content $previousStateFilePath | ConvertFrom-Json } # Initialize current state $currentState = @{} # Get current members of the specified group $currentMembers = Get-GroupMembers -groupName $GroupName if (-not $currentMembers) { Write-Host "Failed to retrieve members for group '$GroupName'." exit 1 # Exit code 1: Error retrieving group members } $currentState[$GroupName] = $currentMembers # Check if the group exists in the previous state if ($previousState -and $previousState.$GroupName) { $previousMembers = $previousState.$GroupName } else { $previousMembers = @() } # Check for added members $addedMembers = $currentState[$GroupName] | Where-Object { $_ -notin $previousMembers } # Check for removed members $removedMembers = $previousMembers | Where-Object { $_ -notin $currentState[$GroupName] } # Log changes if not in monitor mode if (-not $Monitor) { if ($addedMembers.Count -gt 0 -or $removedMembers.Count -gt 0) { $logEntry = "Changes for group '$GroupName' on $(Get-Date):`n" if ($addedMembers.Count -gt 0) { $logEntry += "Added Members: $($addedMembers -join ', ')`n" } if ($removedMembers.Count -gt 0) { $logEntry += "Removed Members: $($removedMembers -join ', ')`n" } $logEntry += "`n" Add-Content -Path $logFilePath -Value $logEntry } } # Output changes if in monitor mode if ($Monitor) { if ($addedMembers.Count -gt 0 -or $removedMembers.Count -gt 0) { Write-Host "Changes for group '$GroupName' on $(Get-Date):" if ($addedMembers.Count -gt 0) { Write-Host "Added Members: $($addedMembers -join ', ')" } if ($removedMembers.Count -gt 0) { Write-Host "Removed Members: $($removedMembers -join ', ')" } } else { Write-Host "No changes detected for group '$GroupName'." } } # Update the previous state file if -Update is specified if ($Update) { $currentState | ConvertTo-Json | Set-Content -Path $previousStateFilePath Write-Host "Previous state file updated." } # Exit codes if ($Monitor -and ($addedMembers.Count -eq 0 -and $removedMembers.Count -eq 0)) { exit 0 # Exit code 0: No changes detected } elseif ($Monitor) { exit 2 # Exit code 2: Changes detected } elseif ($Update) { exit 0 # Exit code 0: Update successful } exit 0 # Exit code 0: Successful execution