Functions/Get-ADComplianceReport.ps1
|
function Get-ADComplianceReport { <# .SYNOPSIS Checks attributes on Active Directory objects against a set of compliance rules. .DESCRIPTION Checks attributes on Active Directory objects against a set of compliance rules and provides a report. It also takes several attributes and makes them human readable. .PARAMETER UserSearchBase Specify the distinguishedName(s) of organizational units (OUs) to search for user objects. .PARAMETER UserGroupSearchBase Specify the distinguishedName(s) of organizational units (OUs) to search for group objects that have users. .PARAMETER AdminSearchBase Specify the distinguishedName(s) of organizational units (OUs) to search for admin objects. .PARAMETER AdminGroupSearchBase Specify the distinguishedName(s) of organizational units (OUs) to search for group objects that have admins. .PARAMETER ComputerSearchBase Specify the distinguishedName(s) of organizational units (OUs) to search for computer objects. .PARAMETER MSASearchBase Specify the distinguishedName(s) of organizational units (OUs) to search for Managed Service Account objects. .PARAMETER OrganizationalSearchBase Specify the distinguishedName(s) of organizational units (OUs) to search for org boxes or shared account objects. .PARAMETER ServerSearchBase Specify the distinguishedName(s) of organizational units (OUs) to search for server objects. .PARAMETER ServiceAccountSearchBase Specify the distinguishedName(s) of organizational units (OUs) to search for Service Account objects. .PARAMETER SaveADReports Will save data pulled from Active Directory to reports for each object matching their type to path in ReportFolder parameter. .PARAMETER ReportFolder Specify where you want to save reports to. If you do not specify a path and use either the SaveADReports or SaveReport switches this defaults to C:\Scripts. .PARAMETER SaveReport Will save the report in csv format. If a path isn't specified using the ReportFolder parameter it will save to C:\Scripts. .EXAMPLE C:\PS>Get-ADComplianceReport Example of how to use this cmdlet. Will default to OUs in config file. .EXAMPLE C:\PS>Get-ADComplianceReport -UserSearchBase 'OU=Example User OU,DC=wstools,DC=dev' Will search the 'OU=Example User OU,DC=wstools,DC=dev' OU for user objects and report on them. .EXAMPLE C:\PS>Get-ADComplianceReport -UserSearchBase 'OU=Example User OU,DC=wstools,DC=dev' -SaveReport Will search the 'OU=Example User OU,DC=wstools,DC=dev' OU for user objects and because the -ReportFolder parameter is not used to specify a path, it will save the report to C:\Scripts. .INPUTS System.String .OUTPUTS System.Management.Automation.PSCustomObject .COMPONENT WSTools .FUNCTIONALITY Active Directory, compliance, report, InTh, Insider Threat, remediation, security .NOTES Author: Skyler Hart Created: 2019-07-02 13:32:53 Last Edit: 2023-05-06 21:50:15 Requires: -Module ActiveDirectory .LINK https://wanderingstag.github.io #> [CmdletBinding()] param( [Parameter( Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Alias('User','Users')] [string[]]$UserSearchBase, [Parameter( Mandatory = $false, ValueFromPipelineByPropertyName = $true )] [string[]]$UserGroupSearchBase, [Parameter( Mandatory = $false, ValueFromPipelineByPropertyName = $true )] [Alias('Admin','Admins')] [string[]]$AdminSearchBase, [Parameter( Mandatory = $false, ValueFromPipelineByPropertyName = $true )] [string[]]$AdminGroupSearchBase, [Parameter( Mandatory = $false, ValueFromPipelineByPropertyName = $true )] [Alias('Computer','Computers')] [string[]]$ComputerSearchBase, [Parameter( Mandatory = $false, ValueFromPipelineByPropertyName = $true )] [Alias('MSA','MSAs','gMSA','sMSA')] [string[]]$MSASearchBase, [Parameter( Mandatory = $false, ValueFromPipelineByPropertyName = $true )] [Alias('Orgs','Organizational','Shared')] [string[]]$OrganizationalSearchBase, [Parameter( Mandatory = $false, ValueFromPipelineByPropertyName = $true )] [Alias('Servers','MemberServer','MemberServers','DomainControllers')] [string[]]$ServerSearchBase, [Parameter( Mandatory = $false, ValueFromPipelineByPropertyName = $true )] [Alias('ServiceAccounts')] [string[]]$ServiceAccountSearchBase, [switch]$SaveADReports, [string]$ReportFolder, [switch]$SaveReport ) Begin { Write-Verbose "Validating AD module installed" if ($null -eq (Get-Module -ListAvailable ActiveDir*).Path) { throw "Active Directory module not found. Active directory must be installed to use this function." } <# For testing or using locally. Make sure to comment out or remove config file section below. $AdminSearchBase = @('OU=Example,DC=wstools,DC=dev','OU=Example 2,DC=wstools,DC=dev') $AdminGroupSearchBase = @() $ComputerSearchBase = @() $MSASearchBase = @() $OrganizationalSearchBase = @() $ServerSearchBase = @() $ServiceAccountSearchBase = @() $UserSearchBase = @() $UserGroupSearchBase = @() #> if (!($AdminSearchBase -or $AdminGroupSearchBase -or $ComputerSearchBase -or $MSASearchBase -or $OrganizationalSearchBase -or $ServerSearchBase -or $ServiceAccountSearchBase -or $UserSearchBase -or $UserGroupSearchBase)) { $config = $Global:WSToolsConfig if (!([string]::IsNullOrWhiteSpace($config))) { Write-Verbose "Config file is setup. Using values in config file." $AdminSearchBase = $config.AdminOUs $AdminGroupSearchBase = $config.AdminGroupOUs $ComputerSearchBase = $config.ComputerOUs $MSASearchBase = $config.MSAOUs $OrganizationalSearchBase = $config.OrgAccountOUs $ServerSearchBase = $config.ServerOUs $ServiceAccountSearchBase = $config.ServiceAccountOUs $UserSearchBase = $config.UserOUs $UserGroupSearchBase = $config.UserGroupOUs $ReportFolder = $config.ScriptWD } } if (!($ReportFolder)) {$ReportFolder = "C:\Scripts"} $date = Get-Date $dateformatted = Get-Date -f yyyyMMdd [datetime]$crqcheckdate = "9/1/2018" # used when checking msExchExtensionAttribute18 on service accounts, if account was created after this date then a Change Request (CRQ) number is required to be in msExchExtensionAttribute18 $30 = ($date).AddDays(-(30)) $45 = ($date).AddDays(-(45)) $60 = ($date).AddDays(-(60)) $90 = ($date).AddDays(-(90)) $defaultinactivedays = $30 } Process { Write-Verbose "Beginning process block" Write-Verbose "Getting Admins from Active Directory" if ($AdminSearchBase.Count -gt 0) { [array]$Admins = foreach ($SearchBase in $AdminSearchBase) {Get-ADUser -Filter * -Properties * -SearchBase $SearchBase | Add-Member -MemberType NoteProperty -Name ObjectType -Value "Admin" -PassThru -Force} } Write-Verbose "Getting Computers from Active Directory" if ($ComputerSearchBase.Count -gt 0) { [array]$Computers = foreach ($SearchBase in $ComputerSearchBase) {Get-ADComputer -Filter * -Properties * -SearchBase $SearchBase | Add-Member -MemberType NoteProperty -Name ObjectType -Value "Computer" -PassThru -Force} } Write-Verbose "Getting Groups from Active Directory" if ($AdminGroupSearchBase.Count -gt 0 -or $UserGroupSearchBase.Count -gt 0) { [array]$Groups = foreach ($SearchBase in $AdminGroupSearchBase) {Get-ADGroup -Filter * -Properties * -SearchBase $SearchBase | Add-Member -MemberType NoteProperty -Name ObjectType -Value "Admin Group" -PassThru -Force} $Groups += foreach ($SearchBase in $UserGroupSearchBase) {Get-ADGroup -Filter * -Properties * -SearchBase $SearchBase | Add-Member -MemberType NoteProperty -Name ObjectType -Value "User Group" -PassThru -Force} } Write-Verbose "Getting Managed Service Accounts from Active Directory" if ($MSASearchBase.Count -gt 0) { [array]$ServiceAccounts = foreach ($SearchBase in $MSASearchBase) {Get-ADServiceAccount -Filter * -Properties * -SearchBase $SearchBase | Add-Member -MemberType NoteProperty -Name ObjectType -Value "Managed Service Account" -PassThru -Force} if ($env:userdnsdomain -match "area52") {$ServiceAccounts = $ServiceAccounts | Where-Object {$_.Name -like "msa.tvyx*"}} } Write-Verbose "Getting Org Boxes from Active Directory" if ($OrganizationalSearchBase.Count -gt 0) { [array]$Orgs = foreach ($SearchBase in $OrganizationalSearchBase) {Get-ADUser -Filter * -Properties * -SearchBase $SearchBase | Add-Member -MemberType NoteProperty -Name ObjectType -Value "Org Box" -PassThru -Force} } Write-Verbose "Getting Servers from Active Directory" if ($ServerSearchBase.Count -gt 0) { [array]$Servers = foreach ($SearchBase in $ServerSearchBase) {Get-ADComputer -Filter * -Properties * -SearchBase $SearchBase | Add-Member -MemberType NoteProperty -Name ObjectType -Value "Server" -PassThru -Force} } Write-Verbose "Getting Service Accounts from Active Directory" if ($ServiceAccountSearchBase.Count -gt 0) { $ServiceAccounts += foreach ($SearchBase in $ServiceAccountSearchBase) {Get-ADUser -Filter * -Properties * -SearchBase $SearchBase | Add-Member -MemberType NoteProperty -Name ObjectType -Value "Service Account" -PassThru -Force} } Write-Verbose "Getting Users from Active Directory" if ($UserSearchBase.Count -gt 0) { [array]$Users = foreach ($SearchBase in $UserSearchBase) {Get-ADUser -Filter * -Properties * -SearchBase $SearchBase | Add-Member -MemberType NoteProperty -Name ObjectType -Value "User" -PassThru -Force} } if ($SaveADReports) { Write-Verbose "Saving AD reports" if (!(Test-Path $ReportFolder)) {New-Item $ReportFolder -ItemType Directory} $Admins | Export-Csv $ReportFolder\$dateformatted`_ComplianceRAW_Admin.csv $Computers | Export-Csv $ReportFolder\$dateformatted`_ComplianceRAW_Computer.csv $Groups | Export-Csv $ReportFolder\$dateformatted`_ComplianceRAW_Group.csv $Orgs | Export-Csv $ReportFolder\$dateformatted`_ComplianceRAW_Org.csv $Servers | Export-Csv $ReportFolder\$dateformatted`_ComplianceRAW_Servers.csv $ServiceAccounts | Export-Csv $ReportFolder\$dateformatted`_ComplianceRAW_ServiceAccount.csv $Users | Export-Csv $ReportFolder\$dateformatted`_ComplianceRAW_User.csv } if ($SaveReport) { if (!(Test-Path $ReportFolder)) {New-Item $ReportFolder -ItemType Directory} } Write-Verbose "Combining Objects" [array]$Objects = $Admins + $Computers + $Groups + $Orgs + $Servers + $ServiceAccounts + $Users $Objects = $Objects | Where-Object {$null -ne $_.SamAccountName} Write-Verbose "Reformatting attributes and performing checks" $i = 0 $number = $Objects.Count $Report = foreach ($obj in $Objects) { # Progress Bar if ($number -gt "1") { $i++ $amount = ($i / $number) $perc1 = $amount.ToString("P") Write-Progress -activity "Reformatting and performing checks on object attributes" -status "Object $i of $number. Percent complete: $perc1" -PercentComplete (($i / $Objects.Count) * 100) }# if length # Clear variables Write-Verbose "Clearing variables" if ($DaysSinceChange) {Remove-Variable DaysSinceChange | Out-Null} if ($DaysSinceCreation) {Remove-Variable DaysSinceCreation | Out-Null} if ($DaysSinceLastLogon) {Remove-Variable DaysSinceLastLogon | Out-Null} if ($DaysSinceLogonTimestamp) {Remove-Variable DaysSinceLogonTimestamp | Out-Null} if ($DaysSinceModified) {Remove-Variable DaysSinceModified | Out-Null} if ($DaysSincePasswordLastSet) {Remove-Variable DaysSincePasswordLastSet | Out-Null} if ($DaysSincepwdLastSetTime) {Remove-Variable DaysSincepwdLastSetTime | Out-Null} if ($issues) {Remove-Variable Issues | Out-Null} if ($ManagerInfo) {Remove-Variable ManagerInfo | Out-Null} if ($ManagerName) {Remove-Variable ManagerName | Out-Null} if ($ManagerEmail) {Remove-Variable ManagerEmail | Out-Null} if ($members) {Remove-Variable members | Out-Null} if ($LastLogonTime) {Remove-Variable LastLogonTime | Out-Null} if ($org) {Remove-Variable org | Out-Null} if ($ProtectedObject) {Remove-Variable ProtectedObject | Out-Null} if ($pwdLastSet) {Remove-Variable pwdLastSet | Out-Null} if ($pwdLastSetTime) {Remove-Variable pwdLastSetTime | Out-Null} if ($SmartCardRequired) {Remove-Variable SmartCardRequired | Out-Null} if ($time) {Remove-Variable time | Out-Null} Write-Verbose "Object: $($obj.Name)" switch ($obj.ObjectType) { Admin { $pastdate = $45 $email = $null } {'Admin Group','User Group' -contains $_} { $pastdate = $90 $email = $obj.mail } Computer { $pastdate = $90 $email = $null } "Managed Service Account" { $pastdate = $60 $email = $null } "Org Box" { $pastdate = $90 $email = $obj.EmailAddress } Server { $pastdate = $30 $email = $null } "Service Account" { $pastdate = $60 $email = $null } User { $pastdate = $90 $email = $obj.EmailAddress } Default {$pastdate = $defaultinactivedays} } if ($obj.adminCount) {$ProtectedObject = $true} else {$ProtectedObject = $false} $DaysSinceModified = [math]::Round((-(New-TimeSpan -Start $date -End ($obj.Modified))).TotalDays) Write-Verbose " - Modified: $($obj.Modified)" Write-Verbose " - Days since modified: $($DaysSinceModified)" switch ($obj.ObjectClass) { {'Group' -contains $_} { $GroupCategory = $obj.GroupCategory $GroupScope = $obj.GroupScope $LastLogonDate = $null $members = $obj.Members $manager = $obj.ManagedBy $obj.PasswordLastSet = $null $obj.PasswordNeverExpires = $null $obj.PasswordNotRequired = $null } Default { $manager = $obj.Manager $GroupScope = $null $GroupCategory = $null Write-Verbose " - Password Last Set: $($obj.PasswordLastSet)" if ([string]::IsNullOrWhiteSpace($obj.PasswordLastSet)) { $DaysSincePasswordLastSet = $null } else {$DaysSincePasswordLastSet = [math]::Round((-(New-TimeSpan -Start $date -End $obj.PasswordLastSet)).TotalDays)} Write-Verbose " - Days since password last set: $($DaysSincePasswordLastSet)" $pwdLastSet = $obj.pwdLastSet if ([string]::IsNullOrWhiteSpace($pwdLastSet)) { $pwdLastSetTime = $null $DaysSincepwdLastSetTime = $null } else { $pwdLastSetTime = [datetime]::FromFileTime("$pwdLastSet") if ([string]::IsNullOrWhiteSpace($pwdLastSetTime)) { $DaysSincepwdLastSetTime = $null } else { $DaysSincepwdLastSetTime = [math]::Round((-(New-TimeSpan -Start $date -End $pwdLastSetTime)).TotalDays) } } Write-Verbose " - pwdLastSet: $($pwdLastSetTime)" Write-Verbose " - Days since pwdLastSet: $($DaysSincepwdLastSetTime)" if ([string]::IsNullOrWhiteSpace($obj.LastlogonDate)) { $DaysSinceLastLogon = $null } else { $DaysSinceLastLogon = [math]::Round((-(New-TimeSpan -Start $date -End $obj.LastlogonDate)).TotalDays) } Write-Verbose " - Days since last logon: $($DaysSinceLastLogon)" $time = $obj.LastLogonTimestamp $LastLogonTime = [datetime]::FromFileTime("$time") if ([string]::IsNullOrWhiteSpace($LastLogonTime)) { $DaysSinceLogonTimestamp = $null } else { $DaysSinceLogonTimestamp = [math]::Round((-(New-TimeSpan -Start $date -End $LastLogonTime)).TotalDays) } Write-Verbose " - LastLogonTime: $($LastLogonTime)" Write-Verbose " - Days since LastLogonTime: $($DaysSinceLogonTimestamp)" } } if ($null -ne $obj.o[0]) { $org = $obj.o[0] } else {$org = $null} $DaysSinceChange = [math]::Round((-(New-TimeSpan -Start $date -End ($obj.whenChanged))).TotalDays) $DaysSinceCreation = [math]::Round((-(New-TimeSpan -Start $date -End ($obj.WhenCreated))).TotalDays) if (!([string]::IsNullOrWhiteSpace($manager))) { $ManagerInfo = Get-ADObject $manager -Properties Name,mail $ManagerName = ($ManagerInfo | Select-Object Name).Name $ManagerEmail = ($ManagerInfo | Select-Object mail).mail } # # Perform checks # Write-Verbose " - Performing Checks" $inactive = $false Write-Verbose " -- Inactive" if ($obj.ObjectType -eq "Org Box" -or $obj.ObjectType -match "Group") { Write-Verbose " --- Org Box or Group. Skipping" } else { # If logon times not empty if (((!([string]::IsNullOrWhiteSpace($LastLogonDate))) -and $LastLogonDate -lt $pastdate) -or ((!([string]::IsNullOrWhiteSpace($LastLogonTime))) -and $LastLogonTime -lt $pastdate)) { Write-Verbose " --- IS inactive" $inactive = $true $DaysInactive = ($DaysSinceLastLogon,$DaysSinceLogonTimestamp | Measure-Object -Minimum).Minimum if ($DaysInactive -ge 10000) { $issues = "Inactive (never logged in)" $DaysInactive = $DaysSinceCreation } else {$issues = "Inactive"} } else {# if logon times ARE empty Write-Verbose " --- NOT inactive" if (([string]::IsNullOrWhiteSpace($LastLogonDate)) -and ([string]::IsNullOrWhiteSpace($LastLogonTime))) { $DaysInactive = "NA" $inactive = $true $issues = "Inactive (never logged in)" } else { $inactive = $false $DaysInactive = ($DaysSinceLastLogon,$DaysSinceLogonTimestamp | Measure-Object -Minimum).Minimum } } } Write-Verbose " -- Smart card required" if (($obj.ObjectType -eq "Admin" -or $Obj.ObjectType -eq "User") -and $obj.SmartCardLogonRequired -eq $false) { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "SmartCardLogonRequired not set" } else {$issues = $issues + ", SmartCardLogonRequired not set"} } Write-Verbose " -- Password checks" if ($obj.ObjectType -eq "Admin" -or $obj.ObjectType -eq "User" -or $obj.ObjectType -eq "Service Account" -or $obj.ObjectType -eq "Org Box") { if ($PasswordNeverExpires -eq $true) { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "PasswordNeverExpires set" } else {$issues = $issues + ", PasswordNeverExpires set"} } if ($PasswordNotRequired -eq $true) { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "PasswordNotRequired set" } else {$issues = $issues + ", PasswordNotRequired set"} } } if (((($obj.ObjectType -eq "Admin" -or $obj.ObjectType -eq "User") -and $SmartCardRequired -eq $false) -or $obj.ObjectType -eq "Service Account") -and $DaysSincePasswordLastSet -ge 60) { if ([string]::IsNullOrWhiteSpace($issues)) {$issues = "Password expired"} else {$issues = $issues + ", password expired"} } if ($obj.ObjectType -eq "Service Account" -and $DaysSincePasswordLastSet -lt 60 -and $DaysSincePasswordLastSet -ge 20) { if ([string]::IsNullOrWhiteSpace($issues)) {$issues = "Password expiring soon"} else {$issues = $issues + ", password expiring soon"} } if ($obj.ObjectType -eq "Computer" -and ([string]::IsNullOrWhiteSpace($pwdLastSetTime)) -and $DaysSinceCreation -gt 30) { if ([string]::IsNullOrWhiteSpace($issues)) {$issues = "Password blank (never connected to network)"} else {$issues = $issues + ", password blank (never connected to network)"} } Write-Verbose " -- Protected Object" if ($ProtectedObject -eq $true) { if (!($obj.MemberOf -match "Domain Admins" -or $obj.MemberOf -match "Domain Controller" -or $obj.MemberOf -match "Enterprise Admins" -or $obj.MemberOf -match "Protected Users" -or $obj.MemberOf -match "Schema Admins")) { if ([string]::IsNullOrWhiteSpace($issues)) {$issues = "ProtectedObject"} else {$issues = $issues + ", ProtectedObject"} } } Write-Verbose " -- Validation" $Validated = $false if ($env:userdnsdomain -match "area52" -and ($obj.ObjectType -eq "Admin" -or $obj.ObjectType -eq "Org Box" -or $obj.ObjectType -eq "Service Account")) { if ($validation) {Remove-Variable validation | Out-Null} if ($ValidationDate) {Remove-Variable ValidationDate | Out-Null} if ($ValidationDays) {Remove-Variable ValidationDays | Out-Null} if ([string]::IsNullOrWhiteSpace($obj.extensionAttribute7)) { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "Not validated" } else { $issues = $issues + ", not validated" } } else { $Validated = $true if ($obj.extensionAttribute7 -like "Acct Valid*") { $validation = $obj.extensionAttribute7 -replace "Acct Validated ","" $validation = $validation.Substring(0,8) $ValidationDate = [datetime]::ParseExact($validation, "yyyyMMdd", $null) $ValidationDays = [math]::Round((-(New-TimeSpan -Start $date -End $ValidationDate)).TotalDays) } else { [string]$validation = $obj.extensionAttribute7 $validation = $validation.Substring(0,10) $ValidationDate = [datetime]::ParseExact($validation, "yyyy-MM-dd", $null) $ValidationDays = [math]::Round((-(New-TimeSpan -Start $date -End $ValidationDate)).TotalDays) } if ($ValidationDays -ge 335 -and $ValidationDays -lt 365) { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "Validation expiring soon" } else { $issues = $issues + ", validation expiring soon" } } elseif ($ValidationDays -ge 365) { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "Validation expired" } else { $issues = $issues + ", validation expired" } } } }# validation Write-Verbose " -- Owner" if (($obj.ObjectType -eq "Group" -or $obj.ObjectType -eq "Org Box") -and ([string]::IsNullOrWhiteSpace($manager))) { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "No manager set" } else { $issues = $issues + ", no manager set" } } Write-Verbose " -- Service Account" if ($obj.ObjectType -eq "Service Account") { if ([string]::IsNullOrWhiteSpace($obj.extensionAttribute13)) { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "EA13 blank (POC field)" } else { $issues = $issues + ", EA13 blank (POC field)" } } if ([string]::IsNullOrWhiteSpace($obj.Description)) { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "Description blank" } else { $issues = $issues + ", description blank" } } if ([string]::IsNullOrWhiteSpace($obj.extensionAttribute3) -or $obj.extensionAttribute3 -notmatch "SVC") { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "extensionAttribute3 missing SVC exemption" } else { $issues = $issues + ", extensionAttribute3 missing SVC exemption" } } if ([string]::IsNullOrWhiteSpace($obj.l)) { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "l (City) missing" } else { $issues = $issues + ", l (City) missing" } } if ([string]::IsNullOrWhiteSpace($obj.msExchExtensionAttribute18)) { if ($obj.WhenCreated -ge $crqcheckdate) { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "msExchExtensionAttribute18 missing authorizing CRQ number" } else { $issues = $issues + ", msExchExtensionAttribute18 missing authorizing CRQ number" } } } if ($manager -notlike "*Organization*") { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "Owner/manager has to be an Org Box" } else { $issues = $issues + ", owner/manager has to be an Org Box" } } if ([string]::IsNullOrWhiteSpace($obj.Organization)) { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "Organization attribute empty" } else { $issues = $issues + ", Organization attribute empty" } } if ([string]::IsNullOrWhiteSpace($obj.physicalDeliveryOfficeName)) { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "Office (physicalDeliveryOfficeName) missing" } else { $issues = $issues + ", Office (physicalDeliveryOfficeName) missing" } } if ([string]::IsNullOrWhiteSpace($obj.telephoneNumber)) { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "telephoneNumber missing" } else { $issues = $issues + ", telephoneNumber missing" } } } Write-Verbose " -- Group" if ($obj.ObjectType -match "Group") { if ([string]::IsNullOrWhiteSpace($obj.Description)) { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "Description blank" } else { $issues = $issues + ", description blank" } } if ($members.Count -lt 1) { if ([string]::IsNullOrWhiteSpace($issues)) { $issues = "No members" } else { $issues = $issues + ", no members" } } if ($members.Count -gt 3) { $members = "Membership list has 3+ users" } } $memberof = $obj.MemberOf if (($memberof).Count -gt 3) { $memberof = "MemberOf more than 3 groups" } if ([string]::IsNullOrWhiteSpace($issues)) {$compliant = $true} else {$compliant = $false} [PSCustomObject]@{ Name = $obj.Name Compliant = $compliant Issues = $issues ObjectType = $obj.ObjectType Email = $email ManagerName = $ManagerName ManagerEmail = $ManagerEmail Description = $obj.Description Enabled = $obj.Enabled o = $org Organization = $obj.Organization ProtectedObject = $ProtectedObject Inactive = $inactive DaysInactive = if ($obj.ObjectType -notmatch "Group") {$DaysInactive} else {$null} LastlogonDate = if ($obj.ObjectType -notmatch "Group") {$obj.LastlogonDate} else {$null} DaysSinceLastLogon = $DaysSinceLastLogon LastLogonTime = $LastLogonTime DaysSinceLogonTime = $DaysSinceLastLogon SmartCardRequired = $SmartCardRequired PasswordLastSet = if ($obj.ObjectType -notmatch "Group") {$obj.PasswordLastSet} else {$null} DaysSincePasswordLastSet = $DaysSincePasswordLastSet pwdLastSet = $pwdLastSetTime DaysSincepwdLastSetTime = $DaysSincepwdLastSetTime PasswordNeverExpires = if ($obj.ObjectType -notmatch "Group") {$obj.PasswordNeverExpires} else {$null} PasswordNotRequired = if ($obj.ObjectType -notmatch "Group") {$obj.PasswordNotRequired} else {$null} Changed = $obj.whenChanged DaysSinceChange = $DaysSinceChange Created = $obj.WhenCreated DaysSinceCreation = $DaysSinceCreation Validated = $Validated ValidationDate = $ValidationDate DaysSinceValidation = $ValidationDays ExtensionAttribute3 = $obj.extensionAttribute3 -join ", " # for checking smartcard exemption in the context of this script, your oganization may do something different ExtensionAttribute7 = $obj.extensionAttribute7 -join ", " # for checking validation in the context of this script, your oganization may do something different ExtensionAttribute13 = $obj.extensionAttribute13 -join ", " # for checking POC email address in the context of this script, your oganization may do something different ExtensionAttribute18 = $obj.msExchExtensionAttribute18 -join ", " # for checking CRQ in the context of this script, your oganization may do something different CanonicalName = $obj.CanonicalName distinguishedName = $obj.distinguishedName MembersCount = $members.Count GroupCategory = $GroupCategory GroupScope = $GroupScope Members = $members -join ", " DisplayName = $obj.DisplayName EmployeeID = $obj.EmployeeID EmployeeType = $obj.EmployeeType MemberOf = $memberof -join ", " Modified = $obj.Modified DaysSinceModified = $DaysSinceModified ObjectClass = $obj.ObjectClass SamAccountName = $obj.SamAccountName }# new object } # report foreach obj in objects } End { if ($SaveReport) { $Report | Export-Csv $ReportFolder\$dateformatted`_ADComplianceReport.csv -NoTypeInformation } else {$Report} } } |