From e67b03f5e3da7dddbafe13d6ccc7a532226aab0c Mon Sep 17 00:00:00 2001 From: Hubert Cornet Date: Tue, 5 Aug 2025 10:11:24 +0200 Subject: [PATCH] =?UTF-8?q?T=C3=A9l=C3=A9verser=20les=20fichiers=20vers=20?= =?UTF-8?q?"/"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ADHTMLReports.ps1 | 1732 +++++++++++++++++++++++++++++++++++ Audit-v3.ps1 | 1372 +++++++++++++++++++++++++++ Audit.ps1 | 1658 +++++++++++++++++++++++++++++++++ Get-AdComputerInventory.ps1 | 50 + creation-automatique.ps1 | 409 +++++++++ 5 files changed, 5221 insertions(+) create mode 100644 ADHTMLReports.ps1 create mode 100644 Audit-v3.ps1 create mode 100644 Audit.ps1 create mode 100644 Get-AdComputerInventory.ps1 create mode 100644 creation-automatique.ps1 diff --git a/ADHTMLReports.ps1 b/ADHTMLReports.ps1 new file mode 100644 index 0000000..e377565 --- /dev/null +++ b/ADHTMLReports.ps1 @@ -0,0 +1,1732 @@ +<# +.SYNOPSIS + Generate graphed report for all Active Directory objects. + +.DESCRIPTION + Generate graphed report for all Active Directory objects. + +.PARAMETER CompanyLogo + Enter URL or UNC path to your desired Company Logo for generated report. + + -CompanyLogo "\\Server01\Admin\Files\CompanyLogo.png" + +.PARAMETER RightLogo + Enter URL or UNC path to your desired right-side logo for generated report. + + -RightLogo "https://www.psmpartners.com/wp-content/uploads/2017/10/porcaro-stolarek-mete.png" + +.PARAMETER ReportTitle + Enter desired title for generated report. + + -ReportTitle "Active Directory Report" + +.PARAMETER Days + Users that have not logged in [X] amount of days or more. + + -Days "30" + +.PARAMETER UserCreatedDays + Users that have been created within [X] amount of days. + + -UserCreatedDays "7" + +.PARAMETER DaysUntilPWExpireINT + Users password expires within [X] amount of days + + -DaysUntilPWExpireINT "7" + +.PARAMETER ADModNumber + Active Directory Objects that have been modified within [X] amount of days. + + -ADModNumber "3" + +.NOTES + Version: 1.0.3 + Author: Bradley Wyatt + Date: 12/4/2018 + Modified: JBear 12/5/2018 + Bradley Wyatt 12/8/2018 + jporgand 12/6/2018 +#> + +param ( + + #Company logo that will be displayed on the left, can be URL or UNC + [Parameter(ValueFromPipeline = $true, HelpMessage = "Enter URL or UNC path to Company Logo")] + [String]$CompanyLogo = "http://thelazyadministrator.com/wp-content/uploads/2018/06/logo-2-e1529684959389.png", + #Logo that will be on the right side, UNC or URL + + [Parameter(ValueFromPipeline = $true, HelpMessage = "Enter URL or UNC path for Side Logo")] + [String]$RightLogo = "http://thelazyadministrator.com/wp-content/uploads/2018/06/amd.png", + #Title of generated report + + [Parameter(ValueFromPipeline = $true, HelpMessage = "Enter desired title for report")] + [String]$ReportTitle = "Active Directory Report", + #Location the report will be saved to + + [Parameter(ValueFromPipeline = $true, HelpMessage = "Enter desired directory path to save; Default: C:\Automation\")] + [String]$ReportSavePath = "C:\Lab\", + #Find users that have not logged in X Amount of days, this sets the days + + [Parameter(ValueFromPipeline = $true, HelpMessage = "Users that have not logged on in more than [X] days. amount of days; Default: 30")] + $Days = 30, + #Get users who have been created in X amount of days and less + + [Parameter(ValueFromPipeline = $true, HelpMessage = "Users that have been created within [X] amount of days; Default: 7")] + $UserCreatedDays = 7, + #Get users whos passwords expire in less than X amount of days + + [Parameter(ValueFromPipeline = $true, HelpMessage = "Users password expires within [X] amount of days; Default: 7")] + $DaysUntilPWExpireINT = 7, + #Get AD Objects that have been modified in X days and newer + + [Parameter(ValueFromPipeline = $true, HelpMessage = "AD Objects that have been modified within [X] amount of days; Default: 3")] + $ADModNumber = 3 + + #CSS template located C:\Program Files\WindowsPowerShell\Modules\ReportHTML\1.4.1.1\ + #Default template is orange and named "Sample" +) + +$DomainAdmin = "Admins du domaine" +$EntrepriseAdmin = "Administrateurs de l`'entreprise" + +Write-Host "Gathering Report Customization..." -ForegroundColor White +Write-Host "__________________________________" -ForegroundColor White +(Write-Host -NoNewline "Company Logo (left): " -ForegroundColor Yellow), (Write-Host $CompanyLogo -ForegroundColor White) +(Write-Host -NoNewline "Company Logo (right): " -ForegroundColor Yellow), (Write-Host $RightLogo -ForegroundColor White) +(Write-Host -NoNewline "Report Title: " -ForegroundColor Yellow), (Write-Host $ReportTitle -ForegroundColor White) +(Write-Host -NoNewline "Report Save Path: " -ForegroundColor Yellow), (Write-Host $ReportSavePath -ForegroundColor White) +(Write-Host -NoNewline "Amount of Days from Last User Logon Report: " -ForegroundColor Yellow), (Write-Host $Days -ForegroundColor White) +(Write-Host -NoNewline "Amount of Days for New User Creation Report: " -ForegroundColor Yellow), (Write-Host $UserCreatedDays -ForegroundColor White) +(Write-Host -NoNewline "Amount of Days for User Password Expiration Report: " -ForegroundColor Yellow), (Write-Host $DaysUntilPWExpireINT -ForegroundColor White) +(Write-Host -NoNewline "Amount of Days for Newly Modified AD Objects Report: " -ForegroundColor Yellow), (Write-Host $ADModNumber -ForegroundColor White) +Write-Host "__________________________________" -ForegroundColor White + +function LastLogonConvert ($ftDate) { + + $Date = [DateTime]::FromFileTime($ftDate) + + if ($Date -lt (Get-Date '1/1/1900') -or $date -eq 0 -or $date -eq $null) { + + "Never" + } + + else { + + $Date + } + +} #End function LastLogonConvert + +#Check for ReportHTML Module +$Mod = Get-Module -ListAvailable -Name "ReportHTML" + +If ($null -eq $Mod) { + + Write-Host "ReportHTML Module is not present, attempting to install it" + + Install-Module -Name ReportHTML -Force + Import-Module ReportHTML -ErrorAction SilentlyContinue +} + +#Array of default Security Groups +$DefaultSGs = @( + + "Access Control Assistance Operators" + "Account Operators" + "Administrators" + "Allowed RODC Password Replication Group" + "Backup Operators" + "Certificate Service DCOM Access" + "Cert Publishers" + "Cloneable Domain Controllers" + "Cryptographic Operators" + "Denied RODC Password Replication Group" + "Distributed COM Users" + "DnsUpdateProxy" + "DnsAdmins" + "Domain Admins" + "Domain Computers" + "Domain Controllers" + "Domain Guests" + "Domain Users" + "Enterprise Admins" + "Enterprise Key Admins" + "Enterprise Read-only Domain Controllers" + "Event Log Readers" + "Group Policy Creator Owners" + "Guests" + "Hyper-V Administrators" + "IIS_IUSRS" + "Incoming Forest Trust Builders" + "Key Admins" + "Network Configuration Operators" + "Performance Log Users" + "Performance Monitor Users" + "Print Operators" + "Pre-Windows 2000 Compatible Access" + "Protected Users" + "RAS and IAS Servers" + "RDS Endpoint Servers" + "RDS Management Servers" + "RDS Remote Access Servers" + "Read-only Domain Controllers" + "Remote Desktop Users" + "Remote Management Users" + "Replicator" + "Schema Admins" + "Server Operators" + "Storage Replica Administrators" + "System Managed Accounts Group" + "Terminal Server License Servers" + "Users" + "Windows Authorization Access Group" + "WinRMRemoteWMIUsers" +) + +$Table = New-Object 'System.Collections.Generic.List[System.Object]' +$OUTable = New-Object 'System.Collections.Generic.List[System.Object]' +$UserTable = New-Object 'System.Collections.Generic.List[System.Object]' +$GroupTypetable = New-Object 'System.Collections.Generic.List[System.Object]' +$DefaultGrouptable = New-Object 'System.Collections.Generic.List[System.Object]' +$EnabledDisabledUsersTable = New-Object 'System.Collections.Generic.List[System.Object]' +$DomainAdminTable = New-Object 'System.Collections.Generic.List[System.Object]' +$ExpiringAccountsTable = New-Object 'System.Collections.Generic.List[System.Object]' +$CompanyInfoTable = New-Object 'System.Collections.Generic.List[System.Object]' +$securityeventtable = New-Object 'System.Collections.Generic.List[System.Object]' +$DomainTable = New-Object 'System.Collections.Generic.List[System.Object]' +$OUGPOTable = New-Object 'System.Collections.Generic.List[System.Object]' +$GroupMembershipTable = New-Object 'System.Collections.Generic.List[System.Object]' +$PasswordExpirationTable = New-Object 'System.Collections.Generic.List[System.Object]' +$PasswordExpireSoonTable = New-Object 'System.Collections.Generic.List[System.Object]' +$userphaventloggedonrecentlytable = New-Object 'System.Collections.Generic.List[System.Object]' +$EnterpriseAdminTable = New-Object 'System.Collections.Generic.List[System.Object]' +$NewCreatedUsersTable = New-Object 'System.Collections.Generic.List[System.Object]' +$GroupProtectionTable = New-Object 'System.Collections.Generic.List[System.Object]' +$OUProtectionTable = New-Object 'System.Collections.Generic.List[System.Object]' +$GPOTable = New-Object 'System.Collections.Generic.List[System.Object]' +$ADObjectTable = New-Object 'System.Collections.Generic.List[System.Object]' +$ProtectedUsersTable = New-Object 'System.Collections.Generic.List[System.Object]' +$ComputersTable = New-Object 'System.Collections.Generic.List[System.Object]' +$ComputerProtectedTable = New-Object 'System.Collections.Generic.List[System.Object]' +$ComputersEnabledTable = New-Object 'System.Collections.Generic.List[System.Object]' +$DefaultComputersinDefaultOUTable = New-Object 'System.Collections.Generic.List[System.Object]' +$DefaultUsersinDefaultOUTable = New-Object 'System.Collections.Generic.List[System.Object]' +$TOPUserTable = New-Object 'System.Collections.Generic.List[System.Object]' +$TOPGroupsTable = New-Object 'System.Collections.Generic.List[System.Object]' +$TOPComputersTable = New-Object 'System.Collections.Generic.List[System.Object]' +$GraphComputerOS = New-Object 'System.Collections.Generic.List[System.Object]' + +#Get all users right away. Instead of doing several lookups, we will use this object to look up all the information needed. +$AllUsers = Get-ADUser -Filter * -Properties * + +$GPOs = Get-GPO -All | Select-Object DisplayName, GPOStatus, ModificationTime, @{ Label = "ComputerVersion"; Expression = { $_.computer.dsversion } }, @{ Label = "UserVersion"; Expression = { $_.user.dsversion } } + +<########################### + Dashboard +############################> + +Write-Host "Working on Dashboard Report..." -ForegroundColor Green + +$dte = (Get-Date).AddDays(- $ADModNumber) + +$ADObjs = Get-ADObject -Filter { whenchanged -gt $dte -and ObjectClass -ne "domainDNS" -and ObjectClass -ne "rIDManager" -and ObjectClass -ne "rIDSet" } -Properties * + +foreach ($ADObj in $ADObjs) { + + if ($ADObj.ObjectClass -eq "GroupPolicyContainer") { + + $Name = $ADObj.DisplayName + } + + else { + + $Name = $ADObj.Name + } + + $obj = [PSCustomObject]@{ + + 'Name' = $Name + 'Object Type' = $ADObj.ObjectClass + 'When Changed' = $ADObj.WhenChanged + } + + $ADObjectTable.Add($obj) +} +if (($ADObjectTable).Count -eq 0) { + + $Obj = [PSCustomObject]@{ + + Information = 'Information: No AD Objects have been modified recently' + } + + $ADObjectTable.Add($obj) +} + + +$ADRecycleBinStatus = (Get-ADOptionalFeature -Filter 'name -like "Recycle Bin Feature"').EnabledScopes + +if ($ADRecycleBinStatus.Count -lt 1) { + + $ADRecycleBin = "Disabled" +} + +else { + + $ADRecycleBin = "Enabled" +} + +#Company Information +$ADInfo = Get-ADDomain +$ForestObj = Get-ADForest +$DomainControllerobj = Get-ADDomain +$Forest = $ADInfo.Forest +$InfrastructureMaster = $DomainControllerobj.InfrastructureMaster +$RIDMaster = $DomainControllerobj.RIDMaster +$PDCEmulator = $DomainControllerobj.PDCEmulator +$DomainNamingMaster = $ForestObj.DomainNamingMaster +$SchemaMaster = $ForestObj.SchemaMaster + +$obj = [PSCustomObject]@{ + + 'Domain' = $Forest + 'AD Recycle Bin' = $ADRecycleBin + 'Infrastructure Master' = $InfrastructureMaster + 'RID Master' = $RIDMaster + 'PDC Emulator' = $PDCEmulator + 'Domain Naming Master' = $DomainNamingMaster + 'Schema Master' = $SchemaMaster +} + +$CompanyInfoTable.Add($obj) + +if (($CompanyInfoTable).Count -eq 0) { + + $Obj = [PSCustomObject]@{ + + Information = 'Information: Could not get items for table' + } + $CompanyInfoTable.Add($obj) +} + +#Get newly created users +$When = ((Get-Date).AddDays(- $UserCreatedDays)).Date +$NewUsers = $AllUsers | Where-Object { $_.whenCreated -ge $When } + +foreach ($Newuser in $Newusers) { + + $obj = [PSCustomObject]@{ + + 'Name' = $Newuser.Name + 'Enabled' = $Newuser.Enabled + 'Creation Date' = $Newuser.whenCreated + } + + $NewCreatedUsersTable.Add($obj) +} +if (($NewCreatedUsersTable).Count -eq 0) { + + $Obj = [PSCustomObject]@{ + + Information = 'Information: No new users have been recently created' + } + $NewCreatedUsersTable.Add($obj) +} + + + +#Get Domain Admins +$DomainAdminMembers = Get-ADGroupMember $DomainAdmin + +foreach ($DomainAdminMember in $DomainAdminMembers) { + + $Name = $DomainAdminMember.Name + $Type = $DomainAdminMember.ObjectClass + $Enabled = ($AllUsers | Where-Object { $_.Name -eq $Name }).Enabled + + $obj = [PSCustomObject]@{ + + 'Name' = $Name + 'Enabled' = $Enabled + 'Type' = $Type + } + + $DomainAdminTable.Add($obj) +} + +if (($DomainAdminTable).Count -eq 0) { + + $Obj = [PSCustomObject]@{ + + Information = 'Information: No Domain Admin Members were found' + } + $DomainAdminTable.Add($obj) +} + + +#Get Enterprise Admins +$EnterpriseAdminsMembers = Get-ADGroupMember $EntrepriseAdmin -Server $SchemaMaster + +foreach ($EnterpriseAdminsMember in $EnterpriseAdminsMembers) { + + $Name = $EnterpriseAdminsMember.Name + $Type = $EnterpriseAdminsMember.ObjectClass + $Enabled = ($AllUsers | Where-Object { $_.Name -eq $Name }).Enabled + + $obj = [PSCustomObject]@{ + + 'Name' = $Name + 'Enabled' = $Enabled + 'Type' = $Type + } + + $EnterpriseAdminTable.Add($obj) +} + +if (($EnterpriseAdminTable).Count -eq 0) { + + $Obj = [PSCustomObject]@{ + + Information = 'Information: Enterprise Admin members were found' + } + $EnterpriseAdminTable.Add($obj) +} + +$DefaultComputersOU = (Get-ADDomain).computerscontainer +$DefaultComputers = Get-ADComputer -Filter * -Properties * -SearchBase "$DefaultComputersOU" + +foreach ($DefaultComputer in $DefaultComputers) { + + $obj = [PSCustomObject]@{ + + 'Name' = $DefaultComputer.Name + 'Enabled' = $DefaultComputer.Enabled + 'Operating System' = $DefaultComputer.OperatingSystem + 'Modified Date' = $DefaultComputer.Modified + 'Password Last Set' = $DefaultComputer.PasswordLastSet + 'Protect from Deletion' = $DefaultComputer.ProtectedFromAccidentalDeletion + } + + $DefaultComputersinDefaultOUTable.Add($obj) +} + +if (($DefaultComputersinDefaultOUTable).Count -eq 0) { + + $Obj = [PSCustomObject]@{ + + Information = 'Information: No computers were found in the Default OU' + } + $DefaultComputersinDefaultOUTable.Add($obj) +} + +$DefaultUsersOU = (Get-ADDomain).UsersContainer +$DefaultUsers = $Allusers | Where-Object { $_.DistinguishedName -like "*$($DefaultUsersOU)" } | Select-Object Name, UserPrincipalName, Enabled, ProtectedFromAccidentalDeletion, EmailAddress, @{ Name = 'lastlogon'; Expression = { LastLogonConvert $_.lastlogon } }, DistinguishedName + +foreach ($DefaultUser in $DefaultUsers) { + + $obj = [PSCustomObject]@{ + + 'Name' = $DefaultUser.Name + 'UserPrincipalName' = $DefaultUser.UserPrincipalName + 'Enabled' = $DefaultUser.Enabled + 'Protected from Deletion' = $DefaultUser.ProtectedFromAccidentalDeletion + 'Last Logon' = $DefaultUser.LastLogon + 'Email Address' = $DefaultUser.EmailAddress + } + + $DefaultUsersinDefaultOUTable.Add($obj) +} +if (($DefaultUsersinDefaultOUTable).Count -eq 0) { + + $Obj = [PSCustomObject]@{ + + Information = 'Information: No Users were found in the default OU' + } + $DefaultUsersinDefaultOUTable.Add($obj) +} + + +#Expiring Accounts +$LooseUsers = Search-ADAccount -AccountExpiring -UsersOnly + +foreach ($LooseUser in $LooseUsers) { + + $NameLoose = $LooseUser.Name + $UPNLoose = $LooseUser.UserPrincipalName + $ExpirationDate = $LooseUser.AccountExpirationDate + $enabled = $LooseUser.Enabled + + $obj = [PSCustomObject]@{ + + 'Name' = $NameLoose + 'UserPrincipalName' = $UPNLoose + 'Expiration Date' = $ExpirationDate + 'Enabled' = $enabled + } + + $ExpiringAccountsTable.Add($obj) +} + +if (($ExpiringAccountsTable).Count -eq 0) { + + $Obj = [PSCustomObject]@{ + + Information = 'Information: No Users were found to expire soon' + } + $ExpiringAccountsTable.Add($obj) +} + +#Security Logs +$SecurityLogs = Get-EventLog -Newest 7 -LogName "Security" | Where-Object { $_.Message -like "*An account*" } + +foreach ($SecurityLog in $SecurityLogs) { + + $TimeGenerated = $SecurityLog.TimeGenerated + $EntryType = $SecurityLog.EntryType + $Recipient = $SecurityLog.Message + + $obj = [PSCustomObject]@{ + + 'Time' = $TimeGenerated + 'Type' = $EntryType + 'Message' = $Recipient + } + + $SecurityEventTable.Add($obj) +} + +if (($SecurityEventTable).Count -eq 0) { + + $Obj = [PSCustomObject]@{ + + Information = 'Information: No logon security events were found' + } + $SecurityEventTable.Add($obj) +} + +#Tenant Domain +$Domains = Get-ADForest | Select-Object -ExpandProperty upnsuffixes | ForEach-Object { + + $obj = [PSCustomObject]@{ + + 'UPN Suffixes' = $_ + Valid = "True" + } + + $DomainTable.Add($obj) +} +if (($DomainTable).Count -eq 0) { + + $Obj = [PSCustomObject]@{ + + Information = 'Information: No UPN Suffixes were found' + } + $DomainTable.Add($obj) +} + +Write-Host "Done!" -ForegroundColor White + +<########################### + + Groups + +############################> + +Write-Host "Working on Groups Report..." -ForegroundColor Green + +#Get groups and sort in alphabetical order +$Groups = Get-ADGroup -Filter * -Properties * +$SecurityCount = 0 +$MailSecurityCount = 0 +$CustomGroup = 0 +$DefaultGroup = 0 +$Groupswithmemebrship = 0 +$Groupswithnomembership = 0 +$GroupsProtected = 0 +$GroupsNotProtected = 0 + +foreach ($Group in $Groups) { + + $DefaultADGroup = 'False' + $Type = New-Object 'System.Collections.Generic.List[System.Object]' + $Gemail = (Get-ADGroup $Group -Properties mail).mail + + if (($group.GroupCategory -eq "Security") -and ($Gemail -ne $Null)) { + + $MailSecurityCount++ + } + + if (($group.GroupCategory -eq "Security") -and (($Gemail) -eq $Null)) { + + $SecurityCount++ + } + + if ($Group.ProtectedFromAccidentalDeletion -eq $True) { + + $GroupsProtected++ + } + + else { + + $GroupsNotProtected++ + } + + if ($DefaultSGs -contains $Group.Name) { + + $DefaultADGroup = "True" + $DefaultGroup++ + } + + else { + + $CustomGroup++ + } + + if ($group.GroupCategory -eq "Distribution") { + + $Type = "Distribution Group" + } + + if (($group.GroupCategory -eq "Security") -and (($Gemail) -eq $Null)) { + + $Type = "Security Group" + } + + if (($group.GroupCategory -eq "Security") -and (($Gemail) -ne $Null)) { + + $Type = "Mail-Enabled Security Group" + } + + if ($Group.Name -ne "Domain Users") { + + $Users = (Get-ADGroupMember -Identity $Group | Sort-Object DisplayName | Select-Object -ExpandProperty Name) -join ", " + + if (!($Users)) { + + $Groupswithnomembership++ + } + + else { + + $Groupswithmemebrship++ + + } + } + + else { + + $Users = "Skipped Domain Users Membership" + } + + $OwnerDN = Get-ADGroup -Filter { name -eq $Group.Name } -Properties managedBy | Select-Object -ExpandProperty ManagedBy + Try { + $Manager = Get-ADUser -Filter { distinguishedname -like $OwnerDN } | Select-Object -ExpandProperty Name + } + Catch { + write-host -ForegroundColor Yellow "Cannot resolve the manager, " $Manager " on the group " $group.name + } + + #$Manager = $AllUsers | Where-Object { $_.distinguishedname -eq $OwnerDN } | Select-Object -ExpandProperty Name + + $obj = [PSCustomObject]@{ + + 'Name' = $Group.name + 'Type' = $Type + 'Members' = $users + 'Managed By' = $Manager + 'E-mail Address' = $GEmail + 'Protected from Deletion' = $Group.ProtectedFromAccidentalDeletion + 'Default AD Group' = $DefaultADGroup + } + + $table.Add($obj) +} + +if (($table).Count -eq 0) { + + $Obj = [PSCustomObject]@{ + + Information = 'Information: No Groups were found' + } + $table.Add($obj) +} +#TOP groups table +$obj1 = [PSCustomObject]@{ + + 'Total Groups' = $Groups.Count + 'Mail-Enabled Security Groups' = $MailSecurityCount + 'Security Groups' = $SecurityCount + 'Distribution Groups' = $DistroCount +} + +$TOPGroupsTable.Add($obj1) + +$obj1 = [PSCustomObject]@{ + + 'Name' = 'Mail-Enabled Security Groups' + 'Count' = $MailSecurityCount +} + +$GroupTypetable.Add($obj1) + +$obj1 = [PSCustomObject]@{ + + 'Name' = 'Security Groups' + 'Count' = $SecurityCount +} + +$GroupTypetable.Add($obj1) +$DistroCount = ($Groups | Where-Object { $_.GroupCategory -eq "Distribution" }).Count + +$obj1 = [PSCustomObject]@{ + + 'Name' = 'Distribution Groups' + 'Count' = $DistroCount +} + +$GroupTypetable.Add($obj1) + +#Default Group Pie Chart +$obj1 = [PSCustomObject]@{ + + 'Name' = 'Default Groups' + 'Count' = $DefaultGroup +} + +$DefaultGrouptable.Add($obj1) + +$obj1 = [PSCustomObject]@{ + + 'Name' = 'Custom Groups' + 'Count' = $CustomGroup +} + +$DefaultGrouptable.Add($obj1) + +#Group Protection Pie Chart +$obj1 = [PSCustomObject]@{ + + 'Name' = 'Protected' + 'Count' = $GroupsProtected +} + +$GroupProtectionTable.Add($obj1) + +$obj1 = [PSCustomObject]@{ + + 'Name' = 'Not Protected' + 'Count' = $GroupsNotProtected +} + +$GroupProtectionTable.Add($obj1) + +#Groups with membership vs no membership pie chart +$objmem = [PSCustomObject]@{ + + 'Name' = 'With Members' + 'Count' = $Groupswithmemebrship +} + +$GroupMembershipTable.Add($objmem) + +$objmem = [PSCustomObject]@{ + + 'Name' = 'No Members' + 'Count' = $Groupswithnomembership +} + +$GroupMembershipTable.Add($objmem) + +Write-Host "Done!" -ForegroundColor White + +<########################### + + Organizational Units + +############################> + +Write-Host "Working on Organizational Units Report..." -ForegroundColor Green + +#Get all OUs' +$OUs = Get-ADOrganizationalUnit -Filter * -Properties * +$OUwithLinked = 0 +$OUwithnoLink = 0 +$OUProtected = 0 +$OUNotProtected = 0 + +foreach ($OU in $OUs) { + + $LinkedGPOs = New-Object 'System.Collections.Generic.List[System.Object]' + + if (($OU.linkedgrouppolicyobjects).length -lt 1) { + + $LinkedGPOs = "None" + $OUwithnoLink++ + } + + else { + + $OUwithLinked++ + $GPOslinks = $OU.linkedgrouppolicyobjects + + foreach ($GPOlink in $GPOslinks) { + + $Split1 = $GPOlink -split "{" | Select-Object -Last 1 + $Split2 = $Split1 -split "}" | Select-Object -First 1 + $LinkedGPOs.Add((Get-GPO -Guid $Split2 -ErrorAction SilentlyContinue).DisplayName) + } + } + + if ($OU.ProtectedFromAccidentalDeletion -eq $True) { + + $OUProtected++ + } + + else { + + $OUNotProtected++ + } + + $LinkedGPOs = $LinkedGPOs -join ", " + $obj = [PSCustomObject]@{ + + 'Name' = $OU.Name + 'Linked GPOs' = $LinkedGPOs + 'Modified Date' = $OU.WhenChanged + 'Protected from Deletion' = $OU.ProtectedFromAccidentalDeletion + } + + $OUTable.Add($obj) +} + +if (($OUTable).Count -eq 0) { + + $Obj = [PSCustomObject]@{ + + Information = 'Information: No OUs were found' + } + $OUTable.Add($obj) +} + +#OUs with no GPO Linked +$obj1 = [PSCustomObject]@{ + + 'Name' = "OUs with no GPO's linked" + 'Count' = $OUwithnoLink +} + +$OUGPOTable.Add($obj1) + +$obj2 = [PSCustomObject]@{ + + 'Name' = "OUs with GPO's linked" + 'Count' = $OUwithLinked +} + +$OUGPOTable.Add($obj2) + +#OUs Protected Pie Chart +$obj1 = [PSCustomObject]@{ + + 'Name' = "Protected" + 'Count' = $OUProtected +} + +$OUProtectionTable.Add($obj1) + +$obj2 = [PSCustomObject]@{ + + 'Name' = "Not Protected" + 'Count' = $OUNotProtected +} + +$OUProtectionTable.Add($obj2) + +Write-Host "Done!" -ForegroundColor White + +<########################### + + USERS + +############################> + +Write-Host "Working on Users Report..." -ForegroundColor Green + +$UserEnabled = 0 +$UserDisabled = 0 +$UserPasswordExpires = 0 +$UserPasswordNeverExpires = 0 +$ProtectedUsers = 0 +$NonProtectedUsers = 0 + +$UsersWIthPasswordsExpiringInUnderAWeek = 0 +$UsersNotLoggedInOver30Days = 0 +$AccountsExpiringSoon = 0 + + +#Get users that haven't logged on in X amount of days, var is set at start of script +$userphaventloggedonrecentlytable = New-Object 'System.Collections.Generic.List[System.Object]' +foreach ($User in $AllUsers) { + + $AttVar = $User | Select-Object Enabled, PasswordExpired, PasswordLastSet, PasswordNeverExpires, PasswordNotRequired, Name, SamAccountName, EmailAddress, AccountExpirationDate, @{ Name = 'lastlogon'; Expression = { LastLogonConvert $_.lastlogon } }, DistinguishedName + $maxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.Days + + if ((($AttVar.PasswordNeverExpires) -eq $False) -and (($AttVar.Enabled) -ne $false)) { + + #Get Password last set date + $passwordSetDate = ($User | ForEach-Object { $_.PasswordLastSet }) + + if ($null -eq $passwordSetDate) { + + $daystoexpire = "User has never logged on" + } + + else { + + #Check for Fine Grained Passwords + $PasswordPol = (Get-ADUserResultantPasswordPolicy $user) + + if (($PasswordPol) -ne $null) { + + $maxPasswordAge = ($PasswordPol).MaxPasswordAge + } + + $expireson = $passwordsetdate.AddDays($maxPasswordAge) + $today = (Get-Date) + + #Gets the count on how many days until the password expires and stores it in the $daystoexpire var + $daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days + } + } + + else { + + $daystoexpire = "N/A" + } + + if (($User.Enabled -eq $True) -and ($AttVar.LastLogon -lt ((Get-Date).AddDays(- $Days))) -and ($User.LastLogon -ne $NULL)) { + + $obj = [PSCustomObject]@{ + + 'Name' = $User.Name + 'UserPrincipalName' = $User.UserPrincipalName + 'Enabled' = $AttVar.Enabled + 'Protected from Deletion' = $User.ProtectedFromAccidentalDeletion + 'Last Logon' = $AttVar.lastlogon + 'Password Never Expires' = $AttVar.PasswordNeverExpires + 'Days Until Password Expires' = $daystoexpire + } + + $userphaventloggedonrecentlytable.Add($obj) + } + + #Items for protected vs non protected users + if ($User.ProtectedFromAccidentalDeletion -eq $False) { + + $NonProtectedUsers++ + } + + else { + + $ProtectedUsers++ + } + + #Items for the enabled vs disabled users pie chart + if (($AttVar.PasswordNeverExpires) -ne $false) { + + $UserPasswordNeverExpires++ + } + + else { + + $UserPasswordExpires++ + } + + #Items for password expiration pie chart + if (($AttVar.Enabled) -ne $false) { + + $UserEnabled++ + } + + else { + + $UserDisabled++ + } + + $Name = $User.Name + $UPN = $User.UserPrincipalName + $Enabled = $AttVar.Enabled + $EmailAddress = $AttVar.EmailAddress + $AccountExpiration = $AttVar.AccountExpirationDate + $PasswordExpired = $AttVar.PasswordExpired + $PasswordLastSet = $AttVar.PasswordLastSet + $PasswordNeverExpires = $AttVar.PasswordNeverExpires + $daysUntilPWExpire = $daystoexpire + + $obj = [PSCustomObject]@{ + + 'Name' = $Name + 'UserPrincipalName' = $UPN + 'Enabled' = $Enabled + 'Protected from Deletion' = $User.ProtectedFromAccidentalDeletion + 'Last Logon' = $LastLogon + 'Email Address' = $EmailAddress + 'Account Expiration' = $AccountExpiration + 'Change Password Next Logon' = $PasswordExpired + 'Password Last Set' = $PasswordLastSet + 'Password Never Expires' = $PasswordNeverExpires + 'Days Until Password Expires' = $daystoexpire + } + + $usertable.Add($obj) + + if ($daystoexpire -lt $DaysUntilPWExpireINT) { + + $obj = [PSCustomObject]@{ + + 'Name' = $Name + 'Days Until Password Expires' = $daystoexpire + } + + $PasswordExpireSoonTable.Add($obj) + } +} +if (($userphaventloggedonrecentlytable).Count -eq 0) { + $userphaventloggedonrecentlytable = [PSCustomObject]@{ + + Information = "Information: No Users were found to have not logged on in $Days days or more" + } +} +if (($PasswordExpireSoonTable).Count -eq 0) { + + $Obj = [PSCustomObject]@{ + + Information = 'Information: No users were found to have passwords expiring soon' + } + $PasswordExpireSoonTable.Add($obj) +} + + +if (($usertable).Count -eq 0) { + + $Obj = [PSCustomObject]@{ + + Information = 'Information: No users were found' + } + $usertable.Add($obj) +} + +#Data for users enabled vs disabled pie graph +$objULic = [PSCustomObject]@{ + + 'Name' = 'Enabled' + 'Count' = $UserEnabled +} + +$EnabledDisabledUsersTable.Add($objULic) + +$objULic = [PSCustomObject]@{ + + 'Name' = 'Disabled' + 'Count' = $UserDisabled +} + +$EnabledDisabledUsersTable.Add($objULic) + +#Data for users password expires pie graph +$objULic = [PSCustomObject]@{ + + 'Name' = 'Password Expires' + 'Count' = $UserPasswordExpires +} + +$PasswordExpirationTable.Add($objULic) + +$objULic = [PSCustomObject]@{ + + 'Name' = 'Password Never Expires' + 'Count' = $UserPasswordNeverExpires +} + +$PasswordExpirationTable.Add($objULic) + +#Data for protected users pie graph +$objULic = [PSCustomObject]@{ + + 'Name' = 'Protected' + 'Count' = $ProtectedUsers +} + +$ProtectedUsersTable.Add($objULic) + +$objULic = [PSCustomObject]@{ + + 'Name' = 'Not Protected' + 'Count' = $NonProtectedUsers +} + +$ProtectedUsersTable.Add($objULic) +if ($null -ne (($userphaventloggedonrecentlytable).Information)) { + $UHLONXD = "0" + +} +Else { + $UHLONXD = $userphaventloggedonrecentlytable.Count + +} +#TOP User table +If ($null -eq (($ExpiringAccountsTable).Information)) { + + $objULic = [PSCustomObject]@{ + 'Total Users' = $AllUsers.Count + "Users with Passwords Expiring in less than $DaysUntilPWExpireINT days" = $PasswordExpireSoonTable.Count + 'Expiring Accounts' = $ExpiringAccountsTable.Count + "Users Haven't Logged on in $Days Days or more" = $UHLONXD + } + + $TOPUserTable.Add($objULic) + + +} +Else { + + $objULic = [PSCustomObject]@{ + 'Total Users' = $AllUsers.Count + "Users with Passwords Expiring in less than $DaysUntilPWExpireINT days" = $PasswordExpireSoonTable.Count + 'Expiring Accounts' = "0" + "Users Haven't Logged on in $Days Days or more" = $UHLONXD + } + $TOPUserTable.Add($objULic) +} + +Write-Host "Done!" -ForegroundColor White +<########################### + + Group Policy + +############################> +Write-Host "Working on Group Policy Report..." -ForegroundColor Green + +$GPOTable = New-Object 'System.Collections.Generic.List[System.Object]' + +foreach ($GPO in $GPOs) { + + $obj = [PSCustomObject]@{ + + 'Name' = $GPO.DisplayName + 'Status' = $GPO.GpoStatus + 'Modified Date' = $GPO.ModificationTime + 'User Version' = $GPO.UserVersion + 'Computer Version' = $GPO.ComputerVersion + } + + $GPOTable.Add($obj) +} +if (($GPOTable).Count -eq 0) { + + $Obj = [PSCustomObject]@{ + + Information = 'Information: No Group Policy Obejects were found' + } + $GPOTable.Add($obj) +} +Write-Host "Done!" -ForegroundColor White +<########################### + + Computers + +############################> +Write-Host "Working on Computers Report..." -ForegroundColor Green + +$Computers = Get-ADComputer -Filter * -Properties * +$ComputersProtected = 0 +$ComputersNotProtected = 0 +$ComputerEnabled = 0 +$ComputerDisabled = 0 +#Only search for versions of windows that exist in the Environment +$WindowsRegex = "(Windows (Server )?(\d+|XP)?( R2)?).*" +$OsVersions = $Computers | Select-Object OperatingSystem -unique | ForEach-Object { + if ($_.OperatingSystem -match $WindowsRegex ) { + return $matches[1] + } + elseif ($_.OperatingSystem -ne $null) { + return $_.OperatingSystem + } +} | Select-Object -unique | Sort-Object + +$OsObj = [PSCustomObject]@{} + +$OsVersions | ForEach-Object { + + $OsObj | Add-Member -Name $_ -Value 0 -Type NoteProperty + +} + +foreach ($Computer in $Computers) { + + if ($Computer.ProtectedFromAccidentalDeletion -eq $True) { + + $ComputersProtected++ + } + + else { + + $ComputersNotProtected++ + } + + if ($Computer.Enabled -eq $True) { + + $ComputerEnabled++ + } + + else { + + $ComputerDisabled++ + } + + $obj = [PSCustomObject]@{ + + 'Name' = $Computer.Name + 'Enabled' = $Computer.Enabled + 'Operating System' = $Computer.OperatingSystem + 'Modified Date' = $Computer.Modified + 'Password Last Set' = $Computer.PasswordLastSet + 'Protect from Deletion' = $Computer.ProtectedFromAccidentalDeletion + } + + $ComputersTable.Add($obj) + + if ($Computer.OperatingSystem -match $WindowsRegex) { + $OsObj."$($matches[1])"++ + } + +} + +if (($ComputersTable).Count -eq 0) { + + $Obj = [PSCustomObject]@{ + + Information = 'Information: No computers were found' + } + $ComputersTable.Add($obj) +} + +#Pie chart breaking down OS for computer obj +$OsObj.PSObject.Properties | ForEach-Object { + $GraphComputerOS.Add([PSCustomObject]@{'Name' = $_.Name; "Count" = $_.Value }) +} + +#Data for TOP Computers data table +$OsObj | Add-Member -Name 'Total Computers' -Value $Computers.Count -Type NoteProperty + +$TOPComputersTable.Add($OsObj) + + +#Data for protected Computers pie graph +$objULic = [PSCustomObject]@{ + + 'Name' = 'Protected' + 'Count' = $ComputerProtected +} + +$ComputerProtectedTable.Add($objULic) + +$objULic = [PSCustomObject]@{ + + 'Name' = 'Not Protected' + 'Count' = $ComputersNotProtected +} + +$ComputerProtectedTable.Add($objULic) + +#Data for enabled/vs Computers pie graph +$objULic = [PSCustomObject]@{ + + 'Name' = 'Enabled' + 'Count' = $ComputerEnabled +} + +$ComputersEnabledTable.Add($objULic) + +$objULic = [PSCustomObject]@{ + + 'Name' = 'Disabled' + 'Count' = $ComputerDisabled +} + +$ComputersEnabledTable.Add($objULic) + +Write-Host "Done!" -ForegroundColor White + +$tabarray = @('Dashboard', 'Groups', 'Organizational Units', 'Users', 'Group Policy', 'Computers') + +Write-Host "Compiling Report..." -ForegroundColor Green + +##--OU Protection PIE CHART--## +#Basic Properties +$PO12 = Get-HTMLPieChartObject +$PO12.Title = "Organizational Units Protected from Deletion" +$PO12.Size.Height = 250 +$PO12.Size.width = 250 +$PO12.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PO12.ChartStyle.ColorSchemeName = "ColorScheme3" + +#There are 8 generated schemes, randomly generated at runtime +$PO12.ChartStyle.ColorSchemeName = "Generated3" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PO12.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PO12.DataDefinition.DataNameColumnName = 'Name' +$PO12.DataDefinition.DataValueColumnName = 'Count' + +##--Computer OS Breakdown PIE CHART--## +$PieObjectComputerObjOS = Get-HTMLPieChartObject +$PieObjectComputerObjOS.Title = "Computer Operating Systems" + +#These file exist in the module directoy, There are 4 schemes by default +$PieObjectComputerObjOS.ChartStyle.ColorSchemeName = "ColorScheme3" + +#There are 8 generated schemes, randomly generated at runtime +$PieObjectComputerObjOS.ChartStyle.ColorSchemeName = "Generated3" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PieObjectComputerObjOS.ChartStyle.ColorSchemeName = 'Random' + +##--Computers Protection PIE CHART--## +#Basic Properties +$PieObjectComputersProtected = Get-HTMLPieChartObject +$PieObjectComputersProtected.Title = "Computers Protected from Deletion" +$PieObjectComputersProtected.Size.Height = 250 +$PieObjectComputersProtected.Size.width = 250 +$PieObjectComputersProtected.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PieObjectComputersProtected.ChartStyle.ColorSchemeName = "ColorScheme3" + +#There are 8 generated schemes, randomly generated at runtime +$PieObjectComputersProtected.ChartStyle.ColorSchemeName = "Generated3" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PieObjectComputersProtected.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PieObjectComputersProtected.DataDefinition.DataNameColumnName = 'Name' +$PieObjectComputersProtected.DataDefinition.DataValueColumnName = 'Count' + +##--Computers Enabled PIE CHART--## +#Basic Properties +$PieObjectComputersEnabled = Get-HTMLPieChartObject +$PieObjectComputersEnabled.Title = "Computers Enabled vs Disabled" +$PieObjectComputersEnabled.Size.Height = 250 +$PieObjectComputersEnabled.Size.width = 250 +$PieObjectComputersEnabled.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PieObjectComputersEnabled.ChartStyle.ColorSchemeName = "ColorScheme3" + +#There are 8 generated schemes, randomly generated at runtime +$PieObjectComputersEnabled.ChartStyle.ColorSchemeName = "Generated3" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PieObjectComputersEnabled.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PieObjectComputersEnabled.DataDefinition.DataNameColumnName = 'Name' +$PieObjectComputersEnabled.DataDefinition.DataValueColumnName = 'Count' + +##--USERS Protection PIE CHART--## +#Basic Properties +$PieObjectProtectedUsers = Get-HTMLPieChartObject +$PieObjectProtectedUsers.Title = "Users Protected from Deletion" +$PieObjectProtectedUsers.Size.Height = 250 +$PieObjectProtectedUsers.Size.width = 250 +$PieObjectProtectedUsers.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PieObjectProtectedUsers.ChartStyle.ColorSchemeName = "ColorScheme3" + +#There are 8 generated schemes, randomly generated at runtime +$PieObjectProtectedUsers.ChartStyle.ColorSchemeName = "Generated3" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PieObjectProtectedUsers.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PieObjectProtectedUsers.DataDefinition.DataNameColumnName = 'Name' +$PieObjectProtectedUsers.DataDefinition.DataValueColumnName = 'Count' + +#Basic Properties +$PieObjectOUGPOLinks = Get-HTMLPieChartObject +$PieObjectOUGPOLinks.Title = "OU GPO Links" +$PieObjectOUGPOLinks.Size.Height = 250 +$PieObjectOUGPOLinks.Size.width = 250 +$PieObjectOUGPOLinks.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PieObjectOUGPOLinks.ChartStyle.ColorSchemeName = "ColorScheme4" + +#There are 8 generated schemes, randomly generated at runtime +$PieObjectOUGPOLinks.ChartStyle.ColorSchemeName = "Generated5" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PieObjectOUGPOLinks.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PieObjectOUGPOLinks.DataDefinition.DataNameColumnName = 'Name' +$PieObjectOUGPOLinks.DataDefinition.DataValueColumnName = 'Count' + +#Basic Properties +$PieObject4 = Get-HTMLPieChartObject +$PieObject4.Title = "Office 365 Unassigned Licenses" +$PieObject4.Size.Height = 250 +$PieObject4.Size.width = 250 +$PieObject4.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PieObject4.ChartStyle.ColorSchemeName = "ColorScheme4" + +#There are 8 generated schemes, randomly generated at runtime +$PieObject4.ChartStyle.ColorSchemeName = "Generated4" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PieObject4.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PieObject4.DataDefinition.DataNameColumnName = 'Name' +$PieObject4.DataDefinition.DataValueColumnName = 'Unassigned Licenses' + +#Basic Properties +$PieObjectGroupType = Get-HTMLPieChartObject +$PieObjectGroupType.Title = "Group Types" +$PieObjectGroupType.Size.Height = 250 +$PieObjectGroupType.Size.width = 250 +$PieObjectGroupType.ChartStyle.ChartType = 'doughnut' + +#Pie Chart Groups with members vs no members +$PieObjectGroupMembersType = Get-HTMLPieChartObject +$PieObjectGroupMembersType.Title = "Group Membership" +$PieObjectGroupMembersType.Size.Height = 250 +$PieObjectGroupMembersType.Size.width = 250 +$PieObjectGroupMembersType.ChartStyle.ChartType = 'doughnut' +$PieObjectGroupMembersType.ChartStyle.ColorSchemeName = "ColorScheme4" +$PieObjectGroupMembersType.ChartStyle.ColorSchemeName = "Generated8" +$PieObjectGroupMembersType.ChartStyle.ColorSchemeName = 'Random' +$PieObjectGroupMembersType.DataDefinition.DataNameColumnName = 'Name' +$PieObjectGroupMembersType.DataDefinition.DataValueColumnName = 'Count' + +#Basic Properties +$PieObjectGroupType2 = Get-HTMLPieChartObject +$PieObjectGroupType2.Title = "Custom vs Default Groups" +$PieObjectGroupType2.Size.Height = 250 +$PieObjectGroupType2.Size.width = 250 +$PieObjectGroupType2.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PieObjectGroupType.ChartStyle.ColorSchemeName = "ColorScheme4" + +#There are 8 generated schemes, randomly generated at runtime +$PieObjectGroupType.ChartStyle.ColorSchemeName = "Generated8" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PieObjectGroupType.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PieObjectGroupType.DataDefinition.DataNameColumnName = 'Name' +$PieObjectGroupType.DataDefinition.DataValueColumnName = 'Count' + +##--Enabled users vs Disabled Users PIE CHART--## +#Basic Properties +$EnabledDisabledUsersPieObject = Get-HTMLPieChartObject +$EnabledDisabledUsersPieObject.Title = "Enabled vs Disabled Users" +$EnabledDisabledUsersPieObject.Size.Height = 250 +$EnabledDisabledUsersPieObject.Size.width = 250 +$EnabledDisabledUsersPieObject.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$EnabledDisabledUsersPieObject.ChartStyle.ColorSchemeName = "ColorScheme3" + +#There are 8 generated schemes, randomly generated at runtime +$EnabledDisabledUsersPieObject.ChartStyle.ColorSchemeName = "Generated3" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$EnabledDisabledUsersPieObject.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$EnabledDisabledUsersPieObject.DataDefinition.DataNameColumnName = 'Name' +$EnabledDisabledUsersPieObject.DataDefinition.DataValueColumnName = 'Count' + +##--PasswordNeverExpires PIE CHART--## +#Basic Properties +$PWExpiresUsersTable = Get-HTMLPieChartObject +$PWExpiresUsersTable.Title = "Password Expiration" +$PWExpiresUsersTable.Size.Height = 250 +$PWExpiresUsersTable.Size.Width = 250 +$PWExpiresUsersTable.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PWExpiresUsersTable.ChartStyle.ColorSchemeName = "ColorScheme3" + +#There are 8 generated schemes, randomly generated at runtime +$PWExpiresUsersTable.ChartStyle.ColorSchemeName = "Generated3" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PWExpiresUsersTable.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PWExpiresUsersTable.DataDefinition.DataNameColumnName = 'Name' +$PWExpiresUsersTable.DataDefinition.DataValueColumnName = 'Count' + +##--Group Protection PIE CHART--## +#Basic Properties +$PieObjectGroupProtection = Get-HTMLPieChartObject +$PieObjectGroupProtection.Title = "Groups Protected from Deletion" +$PieObjectGroupProtection.Size.Height = 250 +$PieObjectGroupProtection.Size.width = 250 +$PieObjectGroupProtection.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PieObjectGroupProtection.ChartStyle.ColorSchemeName = "ColorScheme3" + +#There are 8 generated schemes, randomly generated at runtime +$PieObjectGroupProtection.ChartStyle.ColorSchemeName = "Generated3" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PieObjectGroupProtection.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PieObjectGroupProtection.DataDefinition.DataNameColumnName = 'Name' +$PieObjectGroupProtection.DataDefinition.DataValueColumnName = 'Count' + +#Dashboard Report +$FinalReport = New-Object 'System.Collections.Generic.List[System.Object]' +$FinalReport.Add($(Get-HTMLOpenPage -TitleText $ReportTitle -LeftLogoString $CompanyLogo -RightLogoString $RightLogo)) +$FinalReport.Add($(Get-HTMLTabHeader -TabNames $tabarray)) +$FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[0] -TabHeading ("Report: " + (Get-Date -Format MM-dd-yyyy)))) +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Company Information")) +$FinalReport.Add($(Get-HTMLContentTable $CompanyInfoTable)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Groups")) +$FinalReport.Add($(Get-HTMLColumn1of2)) +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText 'Domain Administrators')) +$FinalReport.Add($(Get-HTMLContentDataTable $DomainAdminTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumn2of2)) +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText 'Enterprise Administrators')) +$FinalReport.Add($(Get-HTMLContentDataTable $EnterpriseAdminTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Objects in Default OUs")) +$FinalReport.Add($(Get-HTMLColumn1of2)) +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText 'Computers')) +$FinalReport.Add($(Get-HTMLContentDataTable $DefaultComputersinDefaultOUTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumn2of2)) +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText 'Users')) +$FinalReport.Add($(Get-HTMLContentDataTable $DefaultUsersinDefaultOUTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "AD Objects Modified in Last $ADModNumber Days")) +$FinalReport.Add($(Get-HTMLContentDataTable $ADObjectTable)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Expiring Items")) +$FinalReport.Add($(Get-HTMLColumn1of2)) +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Users with Passwords Expiring in less than $DaysUntilPWExpireINT days")) +$FinalReport.Add($(Get-HTMLContentDataTable $PasswordExpireSoonTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumn2of2)) +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText 'Accounts Expiring Soon')) +$FinalReport.Add($(Get-HTMLContentDataTable $ExpiringAccountsTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Accounts")) +$FinalReport.Add($(Get-HTMLColumn1of2)) +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Users Haven't Logged on in $Days Days or more")) +$FinalReport.Add($(Get-HTMLContentDataTable $userphaventloggedonrecentlytable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumn2of2)) +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Accounts Created in $UserCreatedDays Days or Less")) +$FinalReport.Add($(Get-HTMLContentDataTable $NewCreatedUsersTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Security Logs")) +$FinalReport.Add($(Get-HTMLContentDataTable $securityeventtable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "UPN Suffixes")) +$FinalReport.Add($(Get-HTMLContentTable $DomainTable)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLTabContentClose)) + +#Groups Report +$FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[1] -TabHeading ("Report: " + (Get-Date -Format MM-dd-yyyy)))) +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Groups Overivew")) +$FinalReport.Add($(Get-HTMLContentTable $TOPGroupsTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Active Directory Groups")) +$FinalReport.Add($(Get-HTMLContentDataTable $Table -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumn1of2)) + +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText 'Domain Administrators')) +$FinalReport.Add($(Get-HTMLContentDataTable $DomainAdminTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumn2of2)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText 'Enterprise Administrators')) +$FinalReport.Add($(Get-HTMLContentDataTable $EnterpriseAdminTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Active Directory Groups Chart")) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 1 -ColumnCount 4)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectGroupType -DataSet $GroupTypetable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 2 -ColumnCount 4)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectGroupType2 -DataSet $DefaultGrouptable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 3 -ColumnCount 4)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectGroupMembersType -DataSet $GroupMembershipTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 4 -ColumnCount 4)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectGroupProtection -DataSet $GroupProtectionTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLTabContentClose)) + +#Organizational Unit Report +$FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[2] -TabHeading ("Report: " + (Get-Date -Format MM-dd-yyyy)))) +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Organizational Units")) +$FinalReport.Add($(Get-HTMLContentDataTable $OUTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Organizational Units Charts")) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 1 -ColumnCount 2)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectOUGPOLinks -DataSet $OUGPOTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 2 -ColumnCount 2)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PO12 -DataSet $OUProtectionTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentclose)) +$FinalReport.Add($(Get-HTMLTabContentClose)) + +#Users Report +$FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[3] -TabHeading ("Report: " + (Get-Date -Format MM-dd-yyyy)))) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Users Overivew")) +$FinalReport.Add($(Get-HTMLContentTable $TOPUserTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Active Directory Users")) +$FinalReport.Add($(Get-HTMLContentDataTable $UserTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Expiring Items")) +$FinalReport.Add($(Get-HTMLColumn1of2)) +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Users with Passwords Expiring in less than $DaysUntilPWExpireINT days")) +$FinalReport.Add($(Get-HTMLContentDataTable $PasswordExpireSoonTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumn2of2)) +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText 'Accounts Expiring Soon')) +$FinalReport.Add($(Get-HTMLContentDataTable $ExpiringAccountsTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Accounts")) +$FinalReport.Add($(Get-HTMLColumn1of2)) +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Users Haven't Logged on in $Days Days or more")) +$FinalReport.Add($(Get-HTMLContentDataTable $userphaventloggedonrecentlytable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumn2of2)) + +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Accounts Created in $UserCreatedDays Days or Less")) +$FinalReport.Add($(Get-HTMLContentDataTable $NewCreatedUsersTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Users Charts")) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 1 -ColumnCount 3)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $EnabledDisabledUsersPieObject -DataSet $EnabledDisabledUsersTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 2 -ColumnCount 3)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PWExpiresUsersTable -DataSet $PasswordExpirationTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 3 -ColumnCount 3)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectProtectedUsers -DataSet $ProtectedUsersTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLTabContentClose)) + +#GPO Report +$FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[4] -TabHeading ("Report: " + (Get-Date -Format MM-dd-yyyy)))) +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Group Policies")) +$FinalReport.Add($(Get-HTMLContentDataTable $GPOTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLTabContentClose)) + +#Computers Report +$FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[5] -TabHeading ("Report: " + (Get-Date -Format MM-dd-yyyy)))) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Computers Overivew")) +$FinalReport.Add($(Get-HTMLContentTable $TOPComputersTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Computers")) +$FinalReport.Add($(Get-HTMLContentDataTable $ComputersTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Computers Charts")) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 1 -ColumnCount 2)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectComputersProtected -DataSet $ComputerProtectedTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 2 -ColumnCount 2)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectComputersEnabled -DataSet $ComputersEnabledTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentclose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Computers Operating System Breakdown")) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectComputerObjOS -DataSet $GraphComputerOS)) +$FinalReport.Add($(Get-HTMLContentclose)) + +$FinalReport.Add($(Get-HTMLTabContentClose)) +$FinalReport.Add($(Get-HTMLClosePage)) + +$Day = (Get-Date).Day +$Month = (Get-Date).Month +$Year = (Get-Date).Year +$ReportName = ("$Day - $Month - $Year - AD Report") + +Save-HTMLReport -ReportContent $FinalReport -ShowReport -ReportName $ReportName -ReportPath $ReportSavePath diff --git a/Audit-v3.ps1 b/Audit-v3.ps1 new file mode 100644 index 0000000..0408449 --- /dev/null +++ b/Audit-v3.ps1 @@ -0,0 +1,1372 @@ +<# + .NOTES + Author : phillips321.co.uk + Creation Date: 16/08/2018 + Script Name : ADAudit.ps1 + .SYNOPSIS + PowerShell Script to perform a quick AD audit + .DESCRIPTION + o Compatibility : + * PowerShell v2.0 (PowerShell 5.0 needed if you intend to use DSInternals PowerShell module) + * Tested on Windows Server 2008R2/2012/2012R2/2016/2019/2022 + * All languages (you may need to adjust $AdministratorTranslation variable) + o Changelog : + [x] Version 5.4 - 16/08/2022 + * Added nessus output tags for LAPS + * Added nessus output for GPO issues + [ ] Version 5.3 - 07/03/2022 + * Added SamAccountName to Get-PrivilegedGroupMembership output + * Swapped some write-host to write-both so it's captured in the consolelog.txt + [ ] Version 5.2 - 28/01/2022 + * Enhanced Get-LAPSStatus + * Added news checks (AD services + Windows Update + NTP source + Computer/User container + RODC + Locked accounts + Password Quality + SYSVOL & NETLOGON share presence) + * Added support for WS 2022 + * Fix OS version difference check for WS 2008 + * Fix Write-Progress not disappearing when done + [ ] Version 5.1 + * Added check for newly created users and groups + * Added check for replication mechanism + * Added check for Recycle Bin + * Fix ProtectedUsers for WS 2008 + [ ] Version 5.0 + * Make the script compatible with other language than English + * Fix the cpassword search in GPO + * Fix Get-ACL bad syntax error + * Fix Get-DNSZoneInsecure for WS 2008 + [ ] Version 4.9 + * Bug fix in checking password comlexity + [ ] Version 4.8 + * Added checks for vista, win7 and 2008 old operating systems + * Added insecure DNS zone checks + [ ] Version 4.7 + * Added powershel-v2 suport and fixed array issue + [ ] Version 4.6 + * Fixed potential division by zero + [ ] Version 4.5 + * PR to resolve count issue when count = 1 + [ ] Version 4.4 + * Reinstated nessus fix and put output in a list for findings + * Changed Get-AdminSDHolders with Get-PrivilegedGroupAccounts + [ ] Version 4.3 + * Temp fix with nessus output + [ ] Version 4.2 + * Bug fix on cpassword count + [ ] Version 4.1 + * Loads of fixes + * Works with Powershellv2 again now + * Filtered out disabled accounts + * Improved domain trusts checking + * OUperms improvements and filtering + * Check for w2k + * Fixed typos/spelling and various other fixes + [ ] Version 4.0 + * Added XML output for import to CheckSecCanopy + [ ] Version 3.5 + * Added KB more references for internal use + [ ] Version 3.4 + * Added KB references for internal use + [ ] Version 3.3 + * Added a greater level of accuracy to Inactive Accounts (thanks exceedio) + [ ] Version 3.2 + * Added search for DCs not owned by Domain Admins group + [ ] Version 3.1 + * Added progress to functions that have count + * Added check for transitive trusts + [ ] Version 3.0 + * Added ability to choose functions before runtime + * Cleaned up get-ouperms output + [ ] Version 2.5 + * Bug fixes to version check for 2012R2 or greater specific checks + [ ] Version 2.4 + * Forked project + * Added Get-OUPerms, Get-LAPSStatus, Get-AdminSDHolders, Get-ProtectedUsers and Get-AuthenticationPoliciesAndSilos functions + * Also added FineGrainedPasswordPolicies to Get-PasswordPolicy and changed order slightly + [ ] Version 2.3 + * Added more useful user output to .txt files (Cheers DK) + [ ] Version 2.2 + * Minor typo fix + [ ] Version 2.1 + * Added check for null sessions + [ ] Version 2.0 + * Multiple Additions and knocked off lots of the todo list + [ ] Version 1.9 + * Fixed bug, that used Administrator account name instead of UID 500 and a bug with inactive accounts timespan + [ ] Version 1.8 + * Added check for last time 'Administrator' account logged on + [ ] Version 1.6 + * Added Get-FunctionalLevel and krbtgt password last changed check + [ ] Version 1.5 + * Added Get-HostDetails to output simple info like username, hostname, etc... + [ ] Version 1.4 + * Added Get-WinVersion version to assist with some checks (SMBv1 currently) + [ ] Version 1.3 + * Added XML output for GPO (for offline processing using grouper https://github.com/l0ss/Grouper/blob/master/grouper.psm1) + [ ] Version 1.2 + * Added check for modules + [ ] Version 1.1 + * Fixed bug where SYSVOL research returns empty + [ ] Version 1.0 + * First release + .EXAMPLE + PS> ADAudit.ps1 -installdeps -all + Install external features and launch all checks + .EXAMPLE + PS> ADAudit.ps1 -all + Launch all checks (but do not install external modules) + .EXAMPLE + PS> ADAudit.ps1 -installdeps + Installs optionnal features (DSInternals) + .EXAMPLE + PS> ADAudit.ps1 -hostdetails -domainaudit + Retrieves hostname and other useful audit info + Retrieves information about the AD such as functional level +#> +[CmdletBinding()] +Param ( + [switch]$installdeps = $false, + [switch]$hostdetails = $false, + [switch]$domainaudit = $false, + [switch]$trusts = $false, + [switch]$accounts = $false, + [switch]$passwordpolicy = $false, + [switch]$ntds = $false, + [switch]$oldboxes = $false, + [switch]$gpo = $false, + [switch]$ouperms = $false, + [switch]$laps = $false, + [switch]$authpolsilos = $false, + [switch]$insecurednszone = $false, + [switch]$recentchanges = $false, + [switch]$all = $false +) +$versionnum = "v5.4" +$AdministratorTranslation = @("Administrator","Administrateur","Administrador")#If missing put the default Administrator name for your own language here + +Function Get-Variables(){#Retrieve group names and OS version + $script:OSVersion = (Get-Itemproperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ProductName).ProductName + $script:Administrators = (Get-ADGroup -Identity S-1-5-32-544).SamAccountName + $script:Users = (Get-ADGroup -Identity S-1-5-32-545).SamAccountName + $script:DomainAdminsSID = ((Get-ADDomain -Current LoggedOnUser).domainsid.value)+"-512" + $script:DomainUsersSID = ((Get-ADDomain -Current LoggedOnUser).domainsid.value)+"-513" + $script:DomainControllersSID = ((Get-ADDomain -Current LoggedOnUser).domainsid.value)+"-516" + $script:SchemaAdminsSID = ((Get-ADDomain -Current LoggedOnUser).domainsid.value)+"-518" + $script:EnterpriseAdminsSID = ((Get-ADDomain -Current LoggedOnUser).domainsid.value)+"-519" + $script:EveryOneSID = New-Object System.Security.Principal.SecurityIdentifier "S-1-1-0" + $script:EntrepriseDomainControllersSID = New-Object System.Security.Principal.SecurityIdentifier "S-1-5-9" + $script:AuthenticatedUsersSID = New-Object System.Security.Principal.SecurityIdentifier "S-1-5-11" + $script:SystemSID = New-Object System.Security.Principal.SecurityIdentifier "S-1-5-18" + $script:LocalServiceSID = New-Object System.Security.Principal.SecurityIdentifier "S-1-5-19" + $script:DomainAdmins = (Get-ADGroup -Identity $DomainAdminsSID).SamAccountName + $script:DomainUsers = (Get-ADGroup -Identity $DomainUsersSID).SamAccountName + $script:DomainControllers = (Get-ADGroup -Identity $DomainControllersSID).SamAccountName + $script:SchemaAdmins = (Get-ADGroup -Identity $SchemaAdminsSID).SamAccountName + $script:EnterpriseAdmins = (Get-ADGroup -Identity $EnterpriseAdminsSID).SamAccountName + $script:EveryOne = $EveryOneSID.Translate([System.Security.Principal.NTAccount]).Value + $script:EntrepriseDomainControllers = $EntrepriseDomainControllersSID.Translate([System.Security.Principal.NTAccount]).Value + $script:AuthenticatedUsers = $AuthenticatedUsersSID.Translate([System.Security.Principal.NTAccount]).Value + $script:System = $SystemSID.Translate([System.Security.Principal.NTAccount]).Value + $script:LocalService = $LocalServiceSID.Translate([System.Security.Principal.NTAccount]).Value + Write-Both " [+] Administrators : $Administrators" + Write-Both " [+] Users : $Users" + Write-Both " [+] Domain Admins : $DomainAdmins" + Write-Both " [+] Domain Users : $DomainUsers" + Write-Both " [+] Domain Controllers : $DomainControllers" + Write-Both " [+] Schema Admins : $SchemaAdmins" + Write-Both " [+] Enterprise Admins : $EnterpriseAdmins" + Write-Both " [+] Every One : $EveryOne" + Write-Both " [+] Entreprise Domain Controllers: $EntrepriseDomainControllers" + Write-Both " [+] Authenticated Users : $AuthenticatedUsers" + Write-Both " [+] System : $System" + Write-Both " [+] Local Service : $LocalService" +} +Function Write-Both(){#Writes to console screen and output file + Write-Host "$args" + Add-Content -Path "$outputdir\consolelog.txt" -Value "$args" +} +Function Write-Nessus-Header(){#Creates nessus XML file header + Add-Content -Path "$outputdir\adaudit.nessus" -Value "" + Add-Content -Path "$outputdir\adaudit.nessus" -Value "" + Add-Content -Path "$outputdir\adaudit.nessus" -Value "" +} +Function Write-Nessus-Finding( [string]$pluginname, [string]$pluginid, [string]$pluginexample){ + Add-Content -Path "$outputdir\adaudit.nessus" -Value "" + Add-Content -Path "$outputdir\adaudit.nessus" -Value "There's an issue with $pluginname" + Add-Content -Path "$outputdir\adaudit.nessus" -Value "remoteLow" + Add-Content -Path "$outputdir\adaudit.nessus" -Value "CCS Recommends fixing the issues with $pluginname on the host" + Add-Content -Path "$outputdir\adaudit.nessus" -Value "There's an issue with the $pluginname settings on the host" + Add-Content -Path "$outputdir\adaudit.nessus" -Value "$pluginexample" +} +Function Write-Nessus-Footer(){ + Add-Content -Path "$outputdir\adaudit.nessus" -Value "" +} +Function Get-DNSZoneInsecure{#Check DNS zones allowing insecure updates + if($OSVersion -notlike "Windows Server 2008*"){ + $count = 0 + $progresscount = 0 + $insecurezones = Get-DnsServerZone | Where-Object {$_.DynamicUpdate -like '*nonsecure*'} + $totalcount = ($insecurezones | Measure-Object | Select-Object Count).count + if($totalcount -gt 0){ + foreach($insecurezone in $insecurezones ){ + Add-Content -Path "$outputdir\insecure_dns_zones.txt" -Value "The DNS Zone $($insecurezone.ZoneName) allows insecure updates ($($insecurezone.DynamicUpdate))" + } + Write-Both " [!] There were $totalcount DNS zones configured to allow insecure updates (KB842)" + Write-Nessus-Finding "InsecureDNSZone" "KB842" ([System.IO.File]::ReadAllText("$outputdir\insecure_dns_zones.txt")) + } + }else{ + Write-Both " [-] Not Windows 2012 or above, skipping Get-DNSZoneInsecure check." + } +} +Function Get-OUPerms{#Check for non-standard perms for authenticated users, domain users, users and everyone groups + $count = 0 + $progresscount = 0 + $objects = (Get-ADObject -Filter *) + $totalcount = ($objects | Measure-Object | Select-Object Count).count + foreach($object in $objects){ + if($totalcount -eq 0){ break } + $progresscount++ + Write-Progress -Activity "Searching for non standard permissions for authenticated users..." -Status "Currently identifed $count" -PercentComplete ($progresscount / $totalcount*100) + if($OSVersion -like "Windows Server 2019*" -or $OSVersion -like "Windows Server 2022*"){ + $output = (Get-Acl "Microsoft.ActiveDirectory.Management.dll\ActiveDirectory:://RootDSE/$object").Access | Where-Object {($_.IdentityReference -eq "$AuthenticatedUsers") -or ($_.IdentityReference -eq "$EveryOne") -or ($_.IdentityReference -like "*\$DomainUsers") -or ($_.IdentityReference -eq "BUILTIN\$Users")} | Where-Object {($_.ActiveDirectoryRights -ne 'GenericRead') -and ($_.ActiveDirectoryRights -ne 'GenericExecute') -and ($_.ActiveDirectoryRights -ne 'ExtendedRight') -and ($_.ActiveDirectoryRights -ne 'ReadControl') -and ($_.ActiveDirectoryRights -ne 'ReadProperty') -and ($_.ActiveDirectoryRights -ne 'ListObject') -and ($_.ActiveDirectoryRights -ne 'ListChildren') -and ($_.ActiveDirectoryRights -ne 'ListChildren, ReadProperty, ListObject') -and ($_.ActiveDirectoryRights -ne 'ReadProperty, GenericExecute') -and ($_.AccessControlType -ne 'Deny')} + }else{ + $output = (Get-Acl AD:$object).Access | Where-Object {($_.IdentityReference -eq "$AuthenticatedUsers") -or ($_.IdentityReference -eq "$EveryOne") -or ($_.IdentityReference -like "*\$DomainUsers") -or ($_.IdentityReference -eq "BUILTIN\$Users")} | Where-Object {($_.ActiveDirectoryRights -ne 'GenericRead') -and ($_.ActiveDirectoryRights -ne 'GenericExecute') -and ($_.ActiveDirectoryRights -ne 'ExtendedRight') -and ($_.ActiveDirectoryRights -ne 'ReadControl') -and ($_.ActiveDirectoryRights -ne 'ReadProperty') -and ($_.ActiveDirectoryRights -ne 'ListObject') -and ($_.ActiveDirectoryRights -ne 'ListChildren') -and ($_.ActiveDirectoryRights -ne 'ListChildren, ReadProperty, ListObject') -and ($_.ActiveDirectoryRights -ne 'ReadProperty, GenericExecute') -and ($_.AccessControlType -ne 'Deny')} + } + if($output -ne $null){ + $count++ + Add-Content -Path "$outputdir\ou_permissions.txt" -Value "OU: $object" + Add-Content -Path "$outputdir\ou_permissions.txt" -Value "[!] Rights: $($output.IdentityReference) $($output.ActiveDirectoryRights) $($output.AccessControlType)" + } + } + Write-Progress -Activity "Searching for non standard permissions for authenticated users..." -Status "Ready" -Completed + if($count -gt 0){ + Write-Both " [!] Issue identified, see $outputdir\ou_permissions.txt" + Write-Nessus-Finding "OUPermissions" "KB551" ([System.IO.File]::ReadAllText("$outputdir\ou_permissions.txt")) + } +} +Function Get-LAPSStatus{#Check for presence of LAPS in domain + try{ + Get-ADObject "CN=ms-Mcs-AdmPwd,CN=Schema,CN=Configuration,$((Get-ADDomain).DistinguishedName)" -ErrorAction Stop | Out-Null + Write-Both " [+] LAPS Installed in domain" + } + catch{ + Write-Both " [!] LAPS Not Installed in domain (KB258)" + Write-Nessus-Finding "LAPSMissing" "KB258" "LAPS Not Installed in domain" + } + if(Get-Module -ListAvailable -Name AdmPwd.PS){ + Import-Module AdmPwd.PS + $count = 0 + $missingComputers = (Get-ADComputer -Filter {ms-Mcs-AdmPwd -notlike "*"}).Name + $totalcount = ($missingComputers | Measure-Object | Select-Object Count).count + if($totalcount -gt 0){ + $missingComputers | Add-Content -Path $outputdir\laps_missing-computers.txt + Write-Both " [!] Some computers/servers don't have LAPS password set, see $outputdir\laps_missing-computers.txt" + Write-Nessus-Finding "LAPSMissingorExpired" "KB258" ([System.IO.File]::ReadAllText("$outputdir\laps_missing-computers.txt")) + } + $count = 0 + $computersList = (Get-ADComputer -Filter {ms-Mcs-AdmPwdExpirationTime -like "*"} -Properties ms-Mcs-AdmPwdExpirationTime | select Name,ms-Mcs-AdmPwdExpirationTime) + foreach($computer in $computersList ){ + $expiration = [datetime]::FromFileTime($computer.'ms-Mcs-AdmPwdExpirationTime') + $today = Get-Date + if($expiration -lt $today){ + $count++ + "$($computer.Name) password is expired since $expiration" | Add-Content -Path $outputdir\laps_expired-passwords.txt + } + } + if($count -gt 0){ + Write-Both " [!] Some computers/servers have LAPS password expired, see $outputdir\laps_expired-passwords.txt" + Write-Nessus-Finding "LAPSMissingorExpired" "KB258" ([System.IO.File]::ReadAllText("$outputdir\laps_expired-passwords.txt")) + } + Get-ADOrganizationalUnit -Filter * | Find-AdmPwdExtendedRights -PipelineVariable OU | foreach{ + $_.ExtendedRightHolders | foreach{ + if($_ -ne $System){ + "$_ can read password attribute of $($Ou.ObjectDN)" | Add-Content -Path $outputdir\laps_read-extendedrights.txt + } + } + } + Write-Both " [!] LAPS extended rights exported, see $outputdir\laps_read-extendedrights.txt" + Write-Nessus-Finding "LAPSMissingorExpired" "KB258" ([System.IO.File]::ReadAllText("$outputdir\laps_read-extendedrights.txt")) + + }else{ + Write-Both " [!] LAPS PowerShell module is not installed, can't run LAPS checks on this DC" + } +} +Function Get-PrivilegedGroupAccounts{#Lists users in Admininstrators, DA and EA groups + [array]$privilegedusers = @() + $privilegedusers += Get-ADGroupMember $Administrators -Recursive + $privilegedusers += Get-ADGroupMember $DomainAdmins -Recursive + $privilegedusers += Get-ADGroupMember $EnterpriseAdmins -Recursive + $privusersunique = $privilegedusers | Sort-Object -Unique + $count = 0 + $totalcount = ($privilegedusers | Measure-Object | Select-Object Count).count + foreach($account in $privusersunique){ + if($totalcount -eq 0){ break } + Write-Progress -Activity "Searching for users who are in privileged groups..." -Status "Currently identifed $count" -PercentComplete ($count / $totalcount*100) + Add-Content -Path "$outputdir\accounts_userPrivileged.txt" -Value "$($account.SamAccountName) ($($account.Name))" + $count++ + } + Write-Progress -Activity "Searching for users who are in privileged groups..." -Status "Ready" -Completed + if($count -gt 0){ + Write-Both " [!] There are $count accounts in privileged groups, see accounts_userPrivileged.txt (KB426)" + Write-Nessus-Finding "AdminSDHolders" "KB426" ([System.IO.File]::ReadAllText("$outputdir\accounts_userPrivileged.txt")) + } +} +Function Get-ProtectedUsers{#Lists users in "Protected Users" group (2012R2 and above) + $DomainLevel = (Get-ADDomain).domainMode + if($DomainLevel -eq "Windows2012Domain" -or $DomainLevel -eq "Windows2012R2Domain" -or $DomainLevel -eq "Windows2016Domain"){#Checking for 2012 or above domain functional level + $ProtectedUsersSID = ((Get-ADDomain -Current LoggedOnUser).domainsid.value)+"-525" + $ProtectedUsers = (Get-ADGroup -Identity $ProtectedUsersSID).SamAccountName + $count = 0 + $protectedaccounts = (Get-ADGroup $ProtectedUsers -Properties members).Members + $totalcount = ($protectedaccounts | Measure-Object | Select-Object Count).count + foreach($members in $protectedaccounts){ + if($totalcount -eq 0){ break } + Write-Progress -Activity "Searching for protected users..." -Status "Currently identifed $count" -PercentComplete ($count / $totalcount*100) + $account = Get-ADObject $members -Properties SamAccountName + Add-Content -Path "$outputdir\accounts_protectedusers.txt" -Value "$($account.SamAccountName) ($($account.Name))" + $count++ + } + Write-Progress -Activity "Searching for protected users..." -Status "Ready" -Completed + if($count -gt 0){ + Write-Both " [!] There are $count accounts in the 'Protected Users' group, see accounts_protectedusers.txt" + Write-Nessus-Finding "ProtectedUsers" "KB549" ([System.IO.File]::ReadAllText("$outputdir\accounts_protectedusers.txt")) + } + } + else {Write-Both " [-] Not Windows 2012 Domain Functional level or above, skipping Get-ProtectedUsers check."} +} +Function Get-AuthenticationPoliciesAndSilos {#Lists any authentication policies and silos (2012R2 and above) + if([single](Get-WinVersion) -ge [single]6.3){#NT6.2 or greater detected so running this script + $count = 0 + foreach($policy in Get-ADAuthenticationPolicy -Filter *){ + Write-Both " [!] Found $policy Authentication Policy" + $count++ + } + if($count -lt 1){ + Write-Both " [!] There were no AD Authentication Policies found in the domain" + } + $count = 0 + foreach($policysilo in Get-ADAuthenticationPolicySilo -Filter *){ + Write-Both " [!] Found $policysilo Authentication Policy Silo" + $count++ + } + if($count -lt 1){ + Write-Both " [!] There were no AD Authentication Policy Silos found in the domain" + } + } +} +Function Get-MachineAccountQuota{#Get number of machines a user can add to a domain + $MachineAccountQuota = (Get-ADDomain | select -ExpandProperty DistinguishedName | Get-ADObject -Property 'ms-DS-MachineAccountQuota' | select -ExpandProperty ms-DS-MachineAccountQuota) + if($MachineAccountQuota -gt 0){ + Write-Both " [!] Domain users can add $MachineAccountQuota devices to the domain! (KB251)" + Write-Nessus-Finding "DomainAccountQuota" "KB251" "Domain users can add $MachineAccountQuota devices to the domain" + } +} +Function Get-PasswordPolicy{ + Write-Both " [+] Checking default password policy" + if(!(Get-ADDefaultDomainPasswordPolicy).ComplexityEnabled){ + Write-Both " [!] Password Complexity not enabled (KB262)" + Write-Nessus-Finding "PasswordComplexity" "KB262" "Password Complexity not enabled" + } + if((Get-ADDefaultDomainPasswordPolicy).LockoutThreshold -lt 5){ + Write-Both " [!] Lockout threshold is less than 5, currently set to $((Get-ADDefaultDomainPasswordPolicy).LockoutThreshold) (KB263)" + Write-Nessus-Finding "LockoutThreshold" "KB263" "Lockout threshold is less than 5, currently set to $((Get-ADDefaultDomainPasswordPolicy).LockoutThreshold)" + } + if((Get-ADDefaultDomainPasswordPolicy).MinPasswordLength -lt 14){ + Write-Both " [!] Minimum password length is less than 14, currently set to $((Get-ADDefaultDomainPasswordPolicy).MinPasswordLength) (KB262)" + Write-Nessus-Finding "PasswordLength" "KB262" "Minimum password length is less than 14, currently set to $((Get-ADDefaultDomainPasswordPolicy).MinPasswordLength)" + } + if((Get-ADDefaultDomainPasswordPolicy).ReversibleEncryptionEnabled){ + Write-Both " [!] Reversible encryption is enabled" + } + if((Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge -eq "00:00:00"){ + Write-Both " [!] Passwords do not expire (KB254)" + Write-Nessus-Finding "PasswordsDoNotExpire" "KB254" "Passwords do not expire" + } + if((Get-ADDefaultDomainPasswordPolicy).PasswordHistoryCount -lt 12){ + Write-Both " [!] Passwords history is less than 12, currently set to $((Get-ADDefaultDomainPasswordPolicy).PasswordHistoryCount) (KB262)" + Write-Nessus-Finding "PasswordHistory" "KB262" "Passwords history is less than 12, currently set to $((Get-ADDefaultDomainPasswordPolicy).PasswordHistoryCount)" + } + if((Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\Lsa).NoLmHash -eq 0){ + Write-Both " [!] LM Hashes are stored! (KB510)" + Write-Nessus-Finding "LMHashesAreStored" "KB510" "LM Hashes are stored" + } + Write-Both " [-] Finished checking default password policy" + Write-Both " [+] Checking fine-grained password policies if they exist" + foreach($finegrainedpolicy in Get-ADFineGrainedPasswordPolicy -Filter *){ + $finegrainedpolicyappliesto=$finegrainedpolicy.AppliesTo + Write-Both " [!] Policy: $finegrainedpolicy" + Write-Both " [!] AppliesTo: $($finegrainedpolicyappliesto)" + if(!($finegrainedpolicy).PasswordComplexity){ + Write-Both " [!] Password Complexity not enabled (KB262)" + Write-Nessus-Finding "PasswordComplexity" "KB262" "Password Complexity not enabled for $finegrainedpolicy" + } + if(($finegrainedpolicy).LockoutThreshold -lt 5){ + Write-Both " [!] Lockout threshold is less than 5, currently set to $($finegrainedpolicy).LockoutThreshold) (KB263)" + Write-Nessus-Finding "LockoutThreshold" "KB263" " Lockout threshold for $finegrainedpolicy is less than 5, currently set to $(($finegrainedpolicy).LockoutThreshold)" + } + if(($finegrainedpolicy).MinPasswordLength -lt 14){ + Write-Both " [!] Minimum password length is less than 14, currently set to $(($finegrainedpolicy).MinPasswordLength) (KB262)" + Write-Nessus-Finding "PasswordLength" "KB262" "Minimum password length for $finegrainedpolicy is less than 14, currently set to $(($finegrainedpolicy).MinPasswordLength)" + } + if(($finegrainedpolicy).ReversibleEncryptionEnabled){ + Write-Both " [!] Reversible encryption is enabled" + } + if(($finegrainedpolicy).MaxPasswordAge -eq "00:00:00"){ + Write-Both " [!] Passwords do not expire (KB254)" + } + if(($finegrainedpolicy).PasswordHistoryCount -lt 12){ + Write-Both " [!] Passwords history is less than 12, currently set to $(($finegrainedpolicy).PasswordHistoryCount) (KB262)" + Write-Nessus-Finding "PasswordHistory" "KB262" "Passwords history for $finegrainedpolicy is less than 12, currently set to $(($finegrainedpolicy).PasswordHistoryCount)" + } + } + Write-Both " [-] Finished checking fine-grained password policy" +} +Function Get-NULLSessions{ + if((Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\Lsa).RestrictAnonymous -eq 0){ + Write-Both " [!] RestrictAnonymous is set to 0! (KB81)" + Write-Nessus-Finding "NullSessions" "KB81" " RestrictAnonymous is set to 0" + } + if((Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\Lsa).RestrictAnonymousSam -eq 0){ + Write-Both " [!] RestrictAnonymousSam is set to 0! (KB81)" + Write-Nessus-Finding "NullSessions" "KB81" " RestrictAnonymous is set to 0" + } + if((Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\Lsa).everyoneincludesanonymous -eq 1){ + Write-Both " [!] EveryoneIncludesAnonymous is set to 1! (KB81)" + Write-Nessus-Finding "NullSessions" "KB81" "EveryoneIncludesAnonymous is set to 1" + } +} +Function Get-DomainTrusts{#Lists domain trusts if they are bad + foreach($trust in (Get-ADObject -Filter {objectClass -eq "trustedDomain"} -Properties TrustPartner,TrustDirection,trustType,trustAttributes)){ + if($trust.TrustDirection -eq 2){ + if($trust.TrustAttributes -eq 1 -or $trust.TrustAttributes -eq 4){#1 means trust is non-transitive, 4 is external so we check for anything but that + Write-Both " [!] The domain $($trust.Name) is trusted by $env:UserDomain! (KB250)" + Write-Nessus-Finding "DomainTrusts" "KB250" "The domain $($trust.Name) is trusted by $env:UserDomain." + }else{ + Write-Both " [!] The domain $($trust.Name) is trusted by $env:UserDomain and it is Transitive! (KB250)" + Write-Nessus-Finding "DomainTrusts" "KB250" "The domain $($trust.Name) is trusted by $env:UserDomain and it is Transitive!" + } + } + if($trust.TrustDirection -eq 3){ + if($trust.TrustAttributes -eq 1 -or $trust.TrustAttributes -eq 4){#1 means trust is non-transitive, 4 is external so we check for anything but that + Write-Both " [!] The domain $($trust.Name) is trusted by $env:UserDomain! (KB250)" + Write-Nessus-Finding "DomainTrusts" "KB250" "The domain $($trust.Name) is trusted by $env:UserDomain." + }else{ + Write-Both " [!] The domain $($trust.Name) is trusted by $env:UserDomain and it is Transitive! (KB250)" + Write-Nessus-Finding "DomainTrusts" "KB250" "The domain $($trust.Name) is trusted by $env:UserDomain and it is Transitive!" + } + } + } +} +Function Get-WinVersion{ + $WinVersion = [single]([string][environment]::OSVersion.Version.Major + "." + [string][environment]::OSVersion.Version.Minor) + return [single]$WinVersion +} +Function Get-SMB1Support{#Check if server supports SMBv1 + if([single](Get-WinVersion) -le [single]6.1){#NT6.1 or less detected so checking reg key + if(!(Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters).SMB1 -eq 0){ + Write-Both " [!] SMBv1 is not disabled (KB290)" + Write-Nessus-Finding "SMBv1Support" "KB290" "SMBv1 is enabled" + } + }elseif([single](Get-WinVersion) -ge [single]6.2){#NT6.2 or greater detected so using powershell function + if((Get-SmbServerConfiguration).EnableSMB1Protocol){ + Write-Both " [!] SMBv1 is enabled! (KB290)" + Write-Nessus-Finding "SMBv1Support" "KB290" "SMBv1 is enabled" + } + } +} +Function Get-UserPasswordNotChangedRecently{#Reports users that haven't changed passwords in more than 90 days + $count = 0 + $DaysAgo = (Get-Date).AddDays(-90) + $accountsoldpasswords = Get-ADUser -Filter {PwdLastSet -lt $DaysAgo -and Enabled -eq "true"} -Properties PasswordLastSet + $totalcount = ($accountsoldpasswords | Measure-Object | Select-Object Count).count + foreach($account in $accountsoldpasswords){ + if($totalcount -eq 0){ break } + Write-Progress -Activity "Searching for passwords older than 90days..." -Status "Currently identifed $count" -PercentComplete ($count / $totalcount*100) + if($account.PasswordLastSet){ + $datelastchanged = $account.PasswordLastSet + }else{ + $datelastchanged = "Never" + } + Add-Content -Path "$outputdir\accounts_with_old_passwords.txt" -Value "User $($account.SamAccountName) ($($account.Name)) has not changed their password since $datelastchanged" + $count++ + } + Write-Progress -Activity "Searching for passwords older than 90days..." -Status "Ready" -Completed + if($count -gt 0){ + Write-Both " [!] $count accounts with passwords older than 90days, see accounts_with_old_passwords.txt (KB550)" + Write-Nessus-Finding "AccountsWithOldPasswords" "KB550" ([System.IO.File]::ReadAllText("$outputdir\accounts_with_old_passwords.txt")) + } + $krbtgtPasswordDate = (Get-ADUser -Filter {SamAccountName -eq "krbtgt"} -Properties PasswordLastSet).PasswordLastSet + if($krbtgtPasswordDate -lt (Get-Date).AddDays(-180)){ + Write-Both " [!] krbtgt password not changed since $krbtgtPasswordDate! (KB253)" + Write-Nessus-Finding "krbtgtPasswordNotChanged" "KB253" "krbtgt password not changed since $krbtgtPasswordDate" + } +} +Function Get-GPOtoFile{#Outputs complete GPO report + if(Test-Path "$outputdir\GPOReport.html"){ Remove-Item "$outputdir\GPOReport.html" -Recurse } + Get-GPOReport -All -ReportType HTML -Path "$outputdir\GPOReport.html" + Write-Both " [+] GPO Report saved to GPOReport.html" + if(Test-Path "$outputdir\GPOReport.xml"){ Remove-Item "$outputdir\GPOReport.xml" -Recurse } + Get-GPOReport -All -ReportType XML -Path "$outputdir\GPOReport.xml" + Write-Both " [+] GPO Report saved to GPOReport.xml, now run Grouper offline using the following command (KB499)" + Write-Both " [+] PS>Import-Module Grouper.psm1 ; Invoke-AuditGPOReport -Path C:\GPOReport.xml -Level 3" +} +Function Get-GPOsPerOU{#Lists all OUs and which GPOs apply to them + $count = 0 + $ousgpos = @(Get-ADOrganizationalUnit -Filter *) + $totalcount = ($ousgpos | Measure-Object | Select-Object Count).count + foreach($ouobject in $ousgpos){ + if($totalcount -eq 0){ break } + Write-Progress -Activity "Identifying which GPOs apply to which OUs..." -Status "Currently identifed $count OUs" -PercentComplete ($count / $totalcount*100) + $combinedgpos = ($(((Get-GPInheritance -Target $ouobject).InheritedGpoLinks) | select DisplayName) | ForEach-Object { $_.DisplayName }) -join ',' + Add-Content -Path "$outputdir\ous_inheritedGPOs.txt" -Value "$($ouobject.Name) Inherits these GPOs: $combinedgpos" + $count++ + } + Write-Progress -Activity "Identifying which GPOs apply to which OUs..." -Status "Ready" -Completed + Write-Both " [+] Inherited GPOs saved to ous_inheritedGPOs.txt" +} +Function Get-NTDSdit{#Dumps NTDS.dit, SYSTEM and SAM for password cracking + if(Test-Path "$outputdir\ntds.dit"){ Remove-Item "$outputdir\ntds.dit" -Recurse } + $outputdirntds = '\"' + $outputdir + '\ntds.dit\"' + $command = "ntdsutil `"ac in ntds`" `"ifm`" `"cr fu $outputdirntds `" q q" + $hide = cmd.exe /c "$command" 2>&1 + Write-Both " [+] NTDS.dit, SYSTEM & SAM saved to output folder" + Write-Both " [+] Use secretsdump.py -system registry/SYSTEM -ntds Active\ Directory/ntds.dit LOCAL -outputfile customer" +} +Function Get-SYSVOLXMLS{#Finds XML files in SYSVOL (thanks --> https://github.com/PowerShellMafia/PowerSploit/blob/master/Exfiltration/Get-GPPPassword.ps1) + $XMLFiles = Get-ChildItem -Path "\\$Env:USERDNSDOMAIN\SYSVOL" -Recurse -ErrorAction SilentlyContinue -Include 'Groups.xml','Services.xml','Scheduledtasks.xml','DataSources.xml','Printers.xml','Drives.xml' + $count = 0 + if($XMLFiles){ + $progresscount = 0 + $totalcount = ($XMLFiles | Measure-Object | Select-Object Count).count + foreach($File in $XMLFiles){ + if($totalcount -eq 0){ break } + $progresscount++ + Write-Progress -Activity "Searching SYSVOL *.xmls for cpassword..." -Status "Currently searched through $count" -PercentComplete ($progresscount / $totalcount*100) + $Filename = Split-Path $File -Leaf + $Distinguishedname = (Split-Path (Split-Path (Split-Path( Split-Path (Split-Path $File -Parent) -Parent ) -Parent ) -Parent) -Leaf).Substring(1).TrimEnd('}') + [xml]$Xml = Get-Content ($File) + if($Xml.innerxml -like "*cpassword*" -and $Xml.innerxml -notlike '*cpassword=""*'){ + if(!(Test-Path "$outputdir\sysvol")){ New-Item -ItemType Directory -Path "$outputdir\sysvol" | Out-Null } + Write-Both " [!] cpassword found in file, copying to output folder (KB329)" + Write-Both " $File" + Copy-Item -Path $File -Destination $outputdir\sysvol\$Distinguishedname.$Filename + $count++ + } + } + Write-Progress -Activity "Searching SYSVOL *.xmls for cpassword..." -Status "Ready" -Completed + } + if($count -eq 0){ + Write-Both " ...cpassword not found in the $($XMLFiles.count) XML files found." + }else{ + $GPOxml = (Get-Content "$outputdir\sysvol\*.xml" -ErrorAction SilentlyContinue) + $GPOxml = $GPOxml -Replace "<", "<" + $GPOxml = $GPOxml -Replace ">", ">" + Write-Nessus-Finding "GPOPasswordStorage" "KB329" "$GPOxml" + } +} +Function Get-InactiveAccounts{#Lists accounts not used in past 180 days plus some checks for admin accounts + $count = 0 + $progresscount = 0 + $inactiveaccounts = Search-ADaccount -AccountInactive -Timespan (New-TimeSpan -Days 180) -UsersOnly | Where-Object {$_.Enabled -eq $true} + $totalcount = ($inactiveaccounts | Measure-Object | Select-Object Count).count + foreach($account in $inactiveaccounts){ + if($totalcount -eq 0){ break } + $progresscount++ + Write-Progress -Activity "Searching for inactive users..." -Status "Currently identifed $count" -PercentComplete ($progresscount / $totalcount*100) + if($account.Enabled){ + if($account.LastLogonDate){ + $userlastused = $account.LastLogonDate + }else{ + $userlastused = "Never" + } + Add-Content -Path "$outputdir\accounts_inactive.txt" -Value "User $($account.SamAccountName) ($($account.Name)) has not logged on since $userlastused" + $count++ + } + } + Write-Progress -Activity "Searching for inactive users..." -Status "Ready" -Completed + if($count -gt 0){ + Write-Both " [!] $count inactive user accounts(180days), see accounts_inactive.txt (KB500)" + Write-Nessus-Finding "InactiveAccounts" "KB500" ([System.IO.File]::ReadAllText("$outputdir\accounts_inactive.txt")) + } +} +Function Get-AdminAccountChecks{#Checks if Administrator account has been renamed, replaced and is no longer used. + $AdministratorSID = ((Get-ADDomain -Current LoggedOnUser).domainsid.value)+"-500" + $AdministratorSAMAccountName = (Get-ADUser -Filter {SID -eq $AdministratorSID} -Properties SamAccountName).SamAccountName + $AdministratorName = (Get-ADUser -Filter {SID -eq $AdministratorSID} -Properties SamAccountName).Name + if($AdministratorTranslation -contains $AdministratorSAMAccountName){ + Write-Both " [!] Local Administrator account (UID500) has not been renamed (KB309)" + Write-Nessus-Finding "AdminAccountRenamed" "KB309" "Local Administrator account (UID500) has not been renamed" + }else{ + $count = 0 + foreach($AdminName in $AdministratorTranslation){ + if((Get-ADUser -Filter {SamAccountName -eq $AdminName})) { $count++ } + } + if($count -eq 0){ + Write-Both " [!] Local Administrator account renamed to $AdministratorSAMAccountName ($($AdministratorName)), but a dummy account not made in it's place! (KB309)" + Write-Nessus-Finding "AdminAccountRenamed" "KB309" "Local Admin account renamed to $AdministratorSAMAccountName ($($AdministratorName)), but a dummy account not made in it's place" + } + } + $AdministratorLastLogonDate = (Get-ADUser -Filter {SID -eq $AdministratorSID} -Properties LastLogonDate).LastLogonDate + if($AdministratorLastLogonDate -gt (Get-Date).AddDays(-180)){ + Write-Both " [!] UID500 (LocalAdministrator) account is still used, last used $AdministratorLastLogonDate! (KB309)" + Write-Nessus-Finding "AdminAccountRenamed" "KB309" "UID500 (LocalAdmini) account is still used, last used $AdministratorLastLogonDate" + } +} +Function Get-DisabledAccounts{#Lists disabled accounts + $disabledaccounts = Search-ADaccount -AccountDisabled -UsersOnly + $count = 0 + $totalcount = ($disabledaccounts | Measure-Object | Select-Object Count).count + foreach($account in $disabledaccounts){ + if($totalcount -eq 0){ break } + Write-Progress -Activity "Searching for disabled users..." -Status "Currently identifed $count" -PercentComplete ($count / $totalcount*100) + Add-Content -Path "$outputdir\accounts_disabled.txt" -Value "Account $($account.SamAccountName) ($($account.Name)) is disabled" + $count++ + } + Write-Progress -Activity "Searching for disabled users..." -Status "Ready" -Completed + if($count -gt 0){ + Write-Both " [!] $count disabled user accounts, see accounts_disabled.txt (KB501)" + Write-Nessus-Finding "DisabledAccounts" "KB501" ([System.IO.File]::ReadAllText("$outputdir\accounts_disabled.txt")) + } +} +Function Get-LockedAccounts{#Lists locked accounts + $lockedAccounts = Get-ADUser -Filter * -Properties LockedOut | Where-Object {$_.LockedOut -eq $true} + $count = 0 + $totalcount = ($lockedAccounts | Measure-Object | Select-Object Count).Count + foreach($account in $lockedAccounts){ + if($totalcount -eq 0){ break } + Write-Progress -Activity "Searching for locked users..." -Status "Currently identifed $count" -PercentComplete ($count / $totalcount*100) + Add-Content -Path "$outputdir\accounts_locked.txt" -Value "Account $($account.SamAccountName) ($($account.Name)) is locked" + $count++ + } + Write-Progress -Activity "Searching for locked users..." -Status "Ready" -Completed + if($count -gt 0){ + Write-Both " [!] $count locked user accounts, see accounts_locked.txt" + } +} +Function Get-AccountPassDontExpire{#Lists accounts who's passwords dont expire + $count = 0 + $nonexpiringpasswords = Search-ADAccount -PasswordNeverExpires -UsersOnly | Where-Object {$_.Enabled -eq $true} + $totalcount = ($nonexpiringpasswords | Measure-Object | Select-Object Count).count + foreach($account in $nonexpiringpasswords){ + if($totalcount -eq 0){ break } + Write-Progress -Activity "Searching for users with passwords that dont expire..." -Status "Currently identifed $count" -PercentComplete ($count / $totalcount*100) + Add-Content -Path "$outputdir\accounts_passdontexpire.txt" -Value "$($account.SamAccountName) ($($account.Name))" + $count++ + } + Write-Progress -Activity "Searching for users with passwords that dont expire..." -Status "Ready" -Completed + if($count -gt 0){ + Write-Both " [!] There are $count accounts that don't expire, see accounts_passdontexpire.txt (KB254)" + Write-Nessus-Finding "AccountsThatDontExpire" "KB254" ([System.IO.File]::ReadAllText("$outputdir\accounts_passdontexpire.txt")) + } +} +Function Get-OldBoxes{#Lists 2000/2003/XP/Vista/7/2008 machines + $count = 0 + $oldboxes = Get-ADComputer -Filter {OperatingSystem -Like "*2003*" -and Enabled -eq "true" -or OperatingSystem -Like "*XP*" -and Enabled -eq "true" -or OperatingSystem -Like "*2000*" -and Enabled -eq "true" -or OperatingSystem -like '*Windows 7*' -and Enabled -eq "true" -or OperatingSystem -like '*vista*' -and Enabled -eq "true" -or OperatingSystem -like '*2008*' -and Enabled -eq "true"} -Property OperatingSystem + $totalcount = ($oldboxes | Measure-Object | Select-Object Count).count + foreach($machine in $oldboxes){ + if($totalcount -eq 0){ break } + Write-Progress -Activity "Searching for 2000/2003/XP/Vista/7/2008 devices joined to the domain..." -Status "Currently identifed $count" -PercentComplete ($count / $totalcount*100) + Add-Content -Path "$outputdir\machines_old.txt" -Value "$($machine.Name), $($machine.OperatingSystem), $($machine.OperatingSystemServicePack), $($machine.OperatingSystemVersio), $($machine.IPv4Address)" + $count++ + } + Write-Progress -Activity "Searching for 2000/2003/XP/Vista/7/2008 devices joined to the domain..." -Status "Ready" -Completed + if($count -gt 0){ + Write-Both " [!] We found $count machines running 2000/2003/XP/Vista/7/2008! see machines_old.txt (KB3/37/38/KB259)" + Write-Nessus-Finding "OldBoxes" "KB259" ([System.IO.File]::ReadAllText("$outputdir\machines_old.txt")) + } +} +Function Get-DCsNotOwnedByDA {#Searches for DC objects not owned by the Domain Admins group + $count = 0 + $progresscount = 0 + $domaincontrollers = Get-ADComputer -Filter {PrimaryGroupID -eq 516 -or PrimaryGroupID -eq 521} -Property * + $totalcount = ($domaincontrollers | Measure-Object | Select-Object Count).count + if($totalcount -gt 0){ + foreach($machine in $domaincontrollers){ + $progresscount++ + Write-Progress -Activity "Searching for DCs not owned by Domain Admins group..." -Status "Currently identifed $count" -PercentComplete ($progresscount / $totalcount*100) + if($machine.ntsecuritydescriptor.Owner -ne "$env:UserDomain\$DomainAdmins"){ + Add-Content -Path "$outputdir\dcs_not_owned_by_da.txt" -Value "$($machine.Name), $($machine.OperatingSystem), $($machine.OperatingSystemServicePack), $($machine.OperatingSystemVersio), $($machine.IPv4Address), owned by $($machine.ntsecuritydescriptor.Owner)" + $count++ + } + } + Write-Progress -Activity "Searching for DCs not owned by Domain Admins group..." -Status "Ready" -Completed + } + if($count -gt 0){ + Write-Both " [!] We found $count DCs not owned by Domains Admins group! see dcs_not_owned_by_da.txt" + Write-Nessus-Finding "DCsNotByDA" "KB547" ([System.IO.File]::ReadAllText("$outputdir\dcs_not_owned_by_da.txt")) + } +} +Function Get-HostDetails{#Gets basic information about the host + Write-Both " [+] Device Name: $env:ComputerName" + Write-Both " [+] Domain Name: $env:UserDomain" + Write-Both " [+] User Name : $env:UserName" + Write-Both " [+] NT Version : $(Get-WinVersion)" + $IPAddresses = [net.dns]::GetHostAddresses("") | select -ExpandProperty IP* + foreach($ip in $IPAddresses){ + if($ip -ne "::1"){ + Write-Both " [+] IP Address : $ip" + } + } +} +Function Get-FunctionalLevel{#Gets the functional level for domain and forest + $DomainLevel = (Get-ADDomain).domainMode + if($DomainLevel -eq "Windows2000Domain" -and [single](Get-WinVersion) -gt 5.0) { Write-Both " [!] DomainLevel is reduced for backwards compatibility to $DomainLevel!" ; Write-Nessus-Finding "FunctionalLevel" "KB546" "DomainLevel is reduced for backwards compatibility to $DomainLevel" } + if($DomainLevel -eq "Windows2003InterimDomain" -and [single](Get-WinVersion) -gt 5.1) { Write-Both " [!] DomainLevel is reduced for backwards compatibility to $DomainLevel!" ; Write-Nessus-Finding "FunctionalLevel" "KB546" "DomainLevel is reduced for backwards compatibility to $DomainLevel" } + if($DomainLevel -eq "Windows2003Domain" -and [single](Get-WinVersion) -gt 5.2) { Write-Both " [!] DomainLevel is reduced for backwards compatibility to $DomainLevel!" ; Write-Nessus-Finding "FunctionalLevel" "KB546" "DomainLevel is reduced for backwards compatibility to $DomainLevel" } + if($DomainLevel -eq "Windows2008Domain" -and [single](Get-WinVersion) -gt 6.0) { Write-Both " [!] DomainLevel is reduced for backwards compatibility to $DomainLevel!" ; Write-Nessus-Finding "FunctionalLevel" "KB546" "DomainLevel is reduced for backwards compatibility to $DomainLevel" } + if($DomainLevel -eq "Windows2008R2Domain" -and [single](Get-WinVersion) -gt 6.1) { Write-Both " [!] DomainLevel is reduced for backwards compatibility to $DomainLevel!" ; Write-Nessus-Finding "FunctionalLevel" "KB546" "DomainLevel is reduced for backwards compatibility to $DomainLevel" } + if($DomainLevel -eq "Windows2012Domain" -and [single](Get-WinVersion) -gt 6.2) { Write-Both " [!] DomainLevel is reduced for backwards compatibility to $DomainLevel!" ; Write-Nessus-Finding "FunctionalLevel" "KB546" "DomainLevel is reduced for backwards compatibility to $DomainLevel" } + if($DomainLevel -eq "Windows2012R2Domain" -and [single](Get-WinVersion) -gt 6.3) { Write-Both " [!] DomainLevel is reduced for backwards compatibility to $DomainLevel!" ; Write-Nessus-Finding "FunctionalLevel" "KB546" "DomainLevel is reduced for backwards compatibility to $DomainLevel" } + if($DomainLevel -eq "Windows2016Domain" -and [single](Get-WinVersion) -gt 10.0){ Write-Both " [!] DomainLevel is reduced for backwards compatibility to $DomainLevel!" ; Write-Nessus-Finding "FunctionalLevel" "KB546" "DomainLevel is reduced for backwards compatibility to $DomainLevel" } + $ForestLevel = (Get-ADForest).ForestMode + if($ForestLevel -eq "Windows2000Forest" -and [single](Get-WinVersion) -gt 5.0) { Write-Both " [!] ForestLevel is reduced for backwards compatibility to $ForestLevel!" ; Write-Nessus-Finding "FunctionalLevel" "KB546" "ForestLevel is reduced for backwards compatibility to $ForestLevel" } + if($ForestLevel -eq "Windows2003InterimForest" -and [single](Get-WinVersion) -gt 5.1) { Write-Both " [!] ForestLevel is reduced for backwards compatibility to $ForestLevel!" ; Write-Nessus-Finding "FunctionalLevel" "KB546" "ForestLevel is reduced for backwards compatibility to $ForestLevel" } + if($ForestLevel -eq "Windows2003Forest" -and [single](Get-WinVersion) -gt 5.2) { Write-Both " [!] ForestLevel is reduced for backwards compatibility to $ForestLevel!" ; Write-Nessus-Finding "FunctionalLevel" "KB546" "ForestLevel is reduced for backwards compatibility to $ForestLevel" } + if($ForestLevel -eq "Windows2008Forest" -and [single](Get-WinVersion) -gt 6.0) { Write-Both " [!] ForestLevel is reduced for backwards compatibility to $ForestLevel!" ; Write-Nessus-Finding "FunctionalLevel" "KB546" "ForestLevel is reduced for backwards compatibility to $ForestLevel" } + if($ForestLevel -eq "Windows2008R2Forest" -and [single](Get-WinVersion) -gt 6.1) { Write-Both " [!] ForestLevel is reduced for backwards compatibility to $ForestLevel!" ; Write-Nessus-Finding "FunctionalLevel" "KB546" "ForestLevel is reduced for backwards compatibility to $ForestLevel" } + if($ForestLevel -eq "Windows2012Forest" -and [single](Get-WinVersion) -gt 6.2) { Write-Both " [!] ForestLevel is reduced for backwards compatibility to $ForestLevel!" ; Write-Nessus-Finding "FunctionalLevel" "KB546" "ForestLevel is reduced for backwards compatibility to $ForestLevel" } + if($ForestLevel -eq "Windows2012R2Forest" -and [single](Get-WinVersion) -gt 6.3) { Write-Both " [!] ForestLevel is reduced for backwards compatibility to $ForestLevel!" ; Write-Nessus-Finding "FunctionalLevel" "KB546" "ForestLevel is reduced for backwards compatibility to $ForestLevel" } + if($ForestLevel -eq "Windows2016Forest" -and [single](Get-WinVersion) -gt 10.0){ Write-Both " [!] ForestLevel is reduced for backwards compatibility to $ForestLevel!" ; Write-Nessus-Finding "FunctionalLevel" "KB546" "ForestLevel is reduced for backwards compatibility to $ForestLevel" } +} +Function Get-GPOEnum{#Loops GPOs for some important domain-wide settings + $AllowedJoin = @() + $HardenNTLM = @() + $DenyNTLM = @() + $AuditNTLM = @() + $NTLMAuthExceptions = @() + $EncryptionTypesNotConfigured = $true + $AdminLocalLogonAllowed = $true + $AdminRPDLogonAllowed = $true + $AdminNetworkLogonAllowed = $true + $AllGPOs = Get-GPO -All | sort DisplayName + foreach($GPO in $AllGPOs){ + $GPOreport = Get-GPOReport -Guid $GPO.Id -ReportType Xml + #Look for GPO that allows join PC to domain + $permissionindex = $GPOreport.IndexOf('SeMachineAccountPrivilege') + if($permissionindex -gt 0){ + $xmlreport = [xml]$GPOreport + foreach($member in (($xmlreport.GPO.Computer.ExtensionData.Extension.UserRightsAssignment | Where-Object {$_.Name -eq 'SeMachineAccountPrivilege'}).Member) ){ + $obj = New-Object -TypeName PSObject + $obj | Add-Member -MemberType NoteProperty -Name GPO -Value $GPO.DisplayName + $obj | Add-Member -MemberType NoteProperty -Name SID -Value $member.Sid.'#text' + $obj | Add-Member -MemberType NoteProperty -Name Name -Value $member.Name.'#text' + $AllowedJoin += $obj + } + } + #Look for GPO that hardens NTLM + $permissionindex = $GPOreport.IndexOf('NoLMHash') + if($permissionindex -gt 0){ + $xmlreport = [xml]$GPOreport + $value = $xmlreport.GPO.Computer.ExtensionData.Extension.SecurityOptions | Where-Object {$_.KeyName -Match 'NoLMHash'} + $obj = New-Object -TypeName PSObject + $obj | Add-Member -MemberType NoteProperty -Name GPO -Value $GPO.DisplayName + $obj | Add-Member -MemberType NoteProperty -Name Value -Value "NoLMHash $($value.Display.DisplayBoolean)" + $HardenNTLM += $obj + } + $permissionindex = $GPOreport.IndexOf('LmCompatibilityLevel') + if($permissionindex -gt 0){ + $xmlreport = [xml]$GPOreport + $value = $xmlreport.GPO.Computer.ExtensionData.Extension.SecurityOptions | Where-Object {$_.KeyName -Match 'LmCompatibilityLevel'} + $obj = New-Object -TypeName PSObject + $obj | Add-Member -MemberType NoteProperty -Name GPO -Value $GPO.DisplayName + $obj | Add-Member -MemberType NoteProperty -Name Value -Value "LmCompatibilityLevel $($value.Display.DisplayString)" + $HardenNTLM += $obj + } + #Look for GPO that denies NTLM + $permissionindex = $GPOreport.IndexOf('RestrictNTLMInDomain') + if($permissionindex -gt 0){ + $xmlreport = [xml]$GPOreport + $value = $xmlreport.GPO.Computer.ExtensionData.Extension.SecurityOptions | Where-Object {$_.KeyName -Match 'RestrictNTLMInDomain'} + $obj = New-Object -TypeName PSObject + $obj | Add-Member -MemberType NoteProperty -Name GPO -Value $GPO.DisplayName + $obj | Add-Member -MemberType NoteProperty -Name Value -Value "RestrictNTLMInDomain $($value.Display.DisplayString)" + $DenyNTLM += $obj + } + #Look for GPO that audits NTLM + $permissionindex = $GPOreport.IndexOf('AuditNTLMInDomain') + if($permissionindex -gt 0){ + $xmlreport = [xml]$GPOreport + $value = $xmlreport.GPO.Computer.ExtensionData.Extension.SecurityOptions | Where-Object {$_.KeyName -Match 'AuditNTLMInDomain'} + $obj = New-Object -TypeName PSObject + $obj | Add-Member -MemberType NoteProperty -Name GPO -Value $GPO.DisplayName + $obj | Add-Member -MemberType NoteProperty -Name Value -Value "AuditNTLMInDomain $($value.Display.DisplayString)" + $AuditNTLM += $obj + } + $permissionindex = $GPOreport.IndexOf('AuditReceivingNTLMTraffic') + if($permissionindex -gt 0){ + $xmlreport = [xml]$GPOreport + $value = $xmlreport.GPO.Computer.ExtensionData.Extension.SecurityOptions | Where-Object {$_.KeyName -Match 'AuditReceivingNTLMTraffic'} + $obj = New-Object -TypeName PSObject + $obj | Add-Member -MemberType NoteProperty -Name GPO -Value $GPO.DisplayName + $obj | Add-Member -MemberType NoteProperty -Name Value -Value "AuditReceivingNTLMTraffic $($value.Display.DisplayString)" + $AuditNTLM += $obj + } + #Look for GPO that allows NTLM exclusions + $permissionindex = $GPOreport.IndexOf('DCAllowedNTLMServers') + if($permissionindex -gt 0){ + $xmlreport = [xml]$GPOreport + foreach($member in (($xmlreport.GPO.Computer.ExtensionData.Extension.SecurityOptions | Where-Object {$_.KeyName -Match 'DCAllowedNTLMServers'}).SettingStrings.Value) ){ + $NTLMAuthExceptions += $member + } + } + #Validate Kerberos Encryption algorythm + $permissionindex = $GPOreport.IndexOf('MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\Kerberos\Parameters\SupportedEncryptionTypes') + if($permissionindex -gt 0){ + $EncryptionTypesNotConfigured = $false + $xmlreport = [xml]$GPOreport + $EncryptionTypes = $xmlreport.GPO.Computer.ExtensionData.Extension.SecurityOptions.Display.DisplayFields.Field + if(($EncryptionTypes | Where-Object {$_.Name -eq 'DES_CBC_CRC'} | select -ExpandProperty value) -eq 'true') { Write-Both " [!] GPO [$($GPO.DisplayName)] enabled DES_CBC_CRC for Kerberos!" } + elseif(($EncryptionTypes | Where-Object {$_.Name -eq 'DES_CBC_MD5'} | select -ExpandProperty value) -eq 'true') { Write-Both " [!] GPO [$($GPO.DisplayName)] enabled DES_CBC_MD5 for Kerberos!" } + elseif(($EncryptionTypes | Where-Object {$_.Name -eq 'RC4_HMAC_MD5'} | select -ExpandProperty value) -eq 'true') { Write-Both " [!] GPO [$($GPO.DisplayName)] enabled RC4_HMAC_MD5 for Kerberos!" } + elseif(($EncryptionTypes | Where-Object {$_.Name -eq 'AES128_HMAC_SHA1'} | select -ExpandProperty value) -eq 'false'){ Write-Both " [!] AES128_HMAC_SHA1 not enabled for Kerberos!" } + elseif(($EncryptionTypes | Where-Object {$_.Name -eq 'AES256_HMAC_SHA1'} | select -ExpandProperty value) -eq 'false'){ Write-Both " [!] AES256_HMAC_SHA1 not enabled for Kerberos!" } + elseif(($EncryptionTypes | Where-Object {$_.Name -eq 'Future encryption types'} | select -ExpandProperty value) -eq 'false'){ Write-Both " [!] Future encryption types not enabled for Kerberos!" } + } + #Validates Admins local logon restrictions + $permissionindex = $GPOreport.IndexOf('SeDenyInteractiveLogonRight') + if($permissionindex -gt 0){ + $xmlreport = [xml]$GPOreport + foreach($member in (($xmlreport.GPO.Computer.ExtensionData.Extension.UserRightsAssignment | Where-Object {$_.Name -eq 'SeDenyInteractiveLogonRight'}).Member)){ + if($member.Name.'#text' -match "$SchemaAdmins" -or $member.Name.'#text' -match "$DomainAdmins" -or $member.Name.'#text' -match "$EnterpriseAdmins"){ + $AdminLocalLogonAllowed = $false + Add-Content -Path "$outputdir\admin_logon_restrictions.txt" -Value "$($GPO.DisplayName) SeDenyInteractiveLogonRight $($member.Name.'#text')" + } + } + } + #Validates Admins RDP logon restrictions + $permissionindex = $GPOreport.IndexOf('SeDenyRemoteInteractiveLogonRight') + if($permissionindex -gt 0){ + $xmlreport = [xml]$GPOreport + foreach($member in (($xmlreport.GPO.Computer.ExtensionData.Extension.UserRightsAssignment | Where-Object {$_.Name -eq 'SeDenyRemoteInteractiveLogonRight'}).Member)){ + if($member.Name.'#text' -match "$SchemaAdmins" -or $member.Name.'#text' -match "$DomainAdmins" -or $member.Name.'#text' -match "$EnterpriseAdmins"){ + $AdminRPDLogonAllowed = $false + Add-Content -Path "$outputdir\admin_logon_restrictions.txt" -Value "$($GPO.DisplayName) SeDenyRemoteInteractiveLogonRight $($member.Name.'#text')" + } + } + } + #Validates Admins network logon restrictions + $permissionindex = $GPOreport.IndexOf('SeDenyNetworkLogonRight') + if($permissionindex -gt 0){ + $xmlreport = [xml]$GPOreport + foreach($member in (($xmlreport.GPO.Computer.ExtensionData.Extension.UserRightsAssignment | Where-Object {$_.Name -eq 'SeDenyNetworkLogonRight'}).Member)){ + if($member.Name.'#text' -match "$SchemaAdmins" -or $member.Name.'#text' -match "$DomainAdmins" -or $member.Name.'#text' -match "$EnterpriseAdmins"){ + $AdminNetworkLogonAllowed = $false + Add-Content -Path "$outputdir\admin_logon_restrictions.txt" -Value "$($GPO.DisplayName) SeDenyNetworkLogonRight $($member.Name.'#text')" + } + } + } + } + #Output for join PC to domain + foreach($record in $AllowedJoin){ + Write-Both " [+] GPO [$($record.GPO)] allows [$($record.Name)] to join computers to domain" + } + #Output for Admins local logon restrictions + if($AdminLocalLogonAllowed){ + Write-Both " [!] No GPO restricts Domain, Schema and Enterprise local logon across domain!!!" + Write-Nessus-Finding "AdminLogon" "KB479" "No GPO restricts Domain, Schema and Enterprise local logon across domain!" + } + #Output for Admins RDP logon restrictions + if($AdminRPDLogonAllowed){ + Write-Both " [!] No GPO restricts Domain, Schema and Enterprise RDP logon across domain!!!" + Write-Nessus-Finding "AdminLogon" "KB479" "No GPO restricts Domain, Schema and Enterprise RDP logon across domain!" + } + #Output for Admins network logon restrictions + if($AdminNetworkLogonAllowed){ + Write-Both " [!] No GPO restricts Domain, Schema and Enterprise network logon across domain!!!" + Write-Nessus-Finding "AdminLogon" "KB479" "No GPO restricts Domain, Schema and Enterprise network logon across domain!" + } + #Output for Validate Kerberos Encryption algorythm + if($EncryptionTypesNotConfigured){ + Write-Both " [!] RC4_HMAC_MD5 enabled for Kerberos across domain!!!" + Write-Nessus-Finding "WeakKerberosEncryption" "KB995" "RC4_HMAC_MD5 enabled for Kerberos across domain!" + } + #Output for deny NTLM + if($DenyNTLM.count -eq 0){ + if($HardenNTLM.count -eq 0){ + Write-Both " [!] No GPO denies NTLM authentication!" + Write-Both " [!] No GPO explicitely restricts LM or NTLMv1!" + }else{ + Write-Both " [+] NTLM authentication hardening implemented, but NTLM not denied" + foreach($record in $HardenNTLM){ + Write-Both " [-] $($record.value)" + Add-Content -Path "$outputdir\ntlm_restrictions.txt" -Value "NTLM restricted by GPO [$($record.gpo)] with value [$($record.value)]" + } + } + }else{ + foreach($record in $DenyNTLM){ + Add-Content -Path "$outputdir\ntlm_restrictions.txt" -Value "NTLM restricted by GPO [$($record.gpo)] with value [$($record.value)]" + } + } + #Output for NTLM exceptions + if($NTLMAuthExceptions.count -ne 0){ + foreach($record in $NTLMAuthExceptions){ + Add-Content -Path "$outputdir\ntlm_restrictions.txt" -Value "NTLM auth exceptions $($record)" + } + } + #Output for NTLM audit + if($AuditNTLM.count -eq 0){ + Write-Both " [!] No GPO enables NTLM audit authentication!" + }else{ + foreach($record in $DenyNTLM){ + Add-Content -Path "$outputdir\ntlm_restrictions.txt" -Value "NTLM audit GPO [$($record.gpo)] with value [$($record.value)]" + } + } +} +Function Get-PrivilegedGroupMembership{#List Domain Admins, Enterprise Admins and Schema Admins members + $SchemaMembers = Get-ADGroup $SchemaAdmins | Get-ADGroupMember + $EnterpriseMembers = Get-ADGroup $EnterpriseAdmins | Get-ADGroupMember + $DomainAdminsMembers = Get-ADGroup $DomainAdmins | Get-ADGroupMember + if(($SchemaMembers | measure).count -ne 0){ + Write-Both " [!] Schema Admins not empty!!!" + foreach($member in $SchemaMembers){ + Add-Content -Path "$outputdir\schema_admins.txt" -Value "$($member.objectClass) $($member.SamAccountName) $($member.Name)" + } + } + if(($EnterpriseMembers | measure).count -ne 0){ + Write-Both " [!] Enterprise Admins not empty!!!" + foreach($member in $EnterpriseMembers){ + Add-Content -Path "$outputdir\enterprise_admins.txt" -Value "$($member.objectClass) $($member.SamAccountName) $($member.Name)" + } + } + foreach($member in $DomainAdminsMembers){ + Add-Content -Path "$outputdir\domain_admins.txt" -Value "$($member.objectClass) $($member.SamAccountName) $($member.Name)" + } +} +Function Get-DCEval{#Basic validation of all DCs in forest + #Collect all DCs in forest + $Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest() + $ADs = Get-ADDomainController -Filter { Site -like "*" } + #Validate OS version of DCs + $osList = @() + $ADs | ForEach-Object { $osList += $_.OperatingSystem } + if(($osList | sort -Unique | measure).Count -eq 1){ + Write-Both " [+] All DCs are the same OS version of $($osList | sort -Unique)" + }else{ + Write-Both " [!] Operating system differs across DCs!!!" + if(($ADs | Where-Object {$_.OperatingSystem -Match '2003'}) -ne $null){ Write-Both " [+] Domain controllers with WS 2003" ; $ADs | Where-Object {$_.OperatingSystem -Match '2003'} | ForEach-Object { Write-Both " [-] $($_.Name) has $($_.OperatingSystem)" }} + if(($ADs | Where-Object {$_.OperatingSystem -Match '2008 !(R2)'}) -ne $null){ Write-Both " [+] Domain controllers with WS 2008" ; $ADs | Where-Object {$_.OperatingSystem -Match '2008 !(R2)'} | ForEach-Object { Write-Both " [-] $($_.Name) has $($_.OperatingSystem)" }} + if(($ADs | Where-Object {$_.OperatingSystem -Match '2008 R2'}) -ne $null){ Write-Both " [+] Domain controllers with WS 2008 R2" ; $ADs | Where-Object {$_.OperatingSystem -Match '2008 R2'} | ForEach-Object { Write-Both " [-] $($_.Name) has $($_.OperatingSystem)" }} + if(($ADs | Where-Object {$_.OperatingSystem -Match '2012 !(R2)'}) -ne $null){ Write-Both " [+] Domain controllers with WS 2012" ; $ADs | Where-Object {$_.OperatingSystem -Match '2012 !(R2)'} | ForEach-Object { Write-Both " [-] $($_.Name) has $($_.OperatingSystem)" }} + if(($ADs | Where-Object {$_.OperatingSystem -Match '2012 R2'}) -ne $null){ Write-Both " [+] Domain controllers with WS 2012 R2" ; $ADs | Where-Object {$_.OperatingSystem -Match '2012 R2'} | ForEach-Object { Write-Both " [-] $($_.Name) has $($_.OperatingSystem)" }} + if(($ADs | Where-Object {$_.OperatingSystem -Match '2016'}) -ne $null){ Write-Both " [+] Domain controllers with WS 2016" ; $ADs | Where-Object {$_.OperatingSystem -Match '2016'} | ForEach-Object { Write-Both " [-] $($_.Name) has $($_.OperatingSystem)" }} + if(($ADs | Where-Object {$_.OperatingSystem -Match '2019'}) -ne $null){ Write-Both " [+] Domain controllers with WS 2019" ; $ADs | Where-Object {$_.OperatingSystem -Match '2019'} | ForEach-Object { Write-Both " [-] $($_.Name) has $($_.OperatingSystem)" }} + if(($ADs | Where-Object {$_.OperatingSystem -Match '2022'}) -ne $null){ Write-Both " [+] Domain controllers with WS 2022" ; $ADs | Where-Object {$_.OperatingSystem -Match '2022'} | ForEach-Object { Write-Both " [-] $($_.Name) has $($_.OperatingSystem)" }} + } + #Validate DCs hotfix level + if( (( $ADs | Select-Object OperatingSystemHotfix -Unique ) | measure).count -eq 1 -or ( $ADs | Select-Object OperatingSystemHotfix -Unique ) -eq $null ){ + Write-Both " [+] All DCs have the same hotfix of [$($ADs | Select-Object OperatingSystemHotFix -Unique | ForEach-Object {$_.OperatingSystemHotfix})]" + }else{ + Write-Both " [!] Hotfix level differs across DCs!!!" + $ADs | ForEach-Object { + Write-Both " [-] DC $($_.Name) hotfix [$($_.OperatingSystemHotfix)]" + } + } + #Validate DCs Service Pack level + if((($ADs | Select-Object OperatingSystemServicePack -Unique) | measure).count -eq 1 -or ($ADs | Select-Object OperatingSystemServicePack -Unique) -eq $null){ + Write-Both " [+] All DCs have the same Service Pack of [$($ADs | Select-Object OperatingSystemServicePack -Unique | ForEach-Object {$_.OperatingSystemServicePack})]" + }else{ + Write-Both " [!] Service Pack level differs across DCs!!!" + $ADs | ForEach-Object { + Write-Both " [-] DC $($_.Name) Service Pack [$($_.OperatingSystemServicePack)]" + } + } + #Validate DCs OS Version + if((($ADs | Select-Object OperatingSystemVersion -Unique ) | measure).count -eq 1 -or ($ADs | Select-Object OperatingSystemVersion -Unique) -eq $null){ + Write-Both " [+] All DCs have the same OS Version of [$($ADs | Select-Object OperatingSystemVersion -Unique | ForEach-Object {$_.OperatingSystemVersion})]" + }else{ + Write-Both " [!] OS Version differs across DCs!!!" + $ADs | ForEach-Object { + Write-Both " [-] DC $($_.Name) OS Version [$($_.OperatingSystemVersion)]" + } + } + #List sites without GC + $SitesWithNoGC = $false + foreach($Site in $Forest.Sites){ + if(($ADs | Where-Object {$_.Site -eq $Site.Name} | Where-Object {$_.IsGlobalCatalog -eq $true}) -eq $null){ + $SitesWithNoGC = $true + Add-Content -Path "$outputdir\sites_no_gc.txt" -Value "$($Site.Name)" + } + } + if($SitesWithNoGC -eq $true){ + Write-Both " [!] You have sites with no Global Catalog!" + } + #Does one DC holds all FSMO + if(($ADs | Where-Object {$_.OperationMasterRoles -ne $null} | measure).count -eq 1){ + Write-Both " [!] DC $($ADs | Where-Object {$_.OperationMasterRoles -ne $null} | select -ExpandProperty Hostname) holds all FSMO roles!" + } + #DCs with weak Kerberos algorhythm (*CH* Changed below to look for msDS-SupportedEncryptionTypes to work with 2008R2) + $ADcomputers = $ADs | ForEach-Object {Get-ADComputer $_.Name -Properties msDS-SupportedEncryptionTypes} + $WeakKerberos = $false + foreach($DC in $ADcomputers){#(*CH* Need to define all combinations here, only done 28 and 31 so far) (31 = "DES, RC4, AES128, AES256", 28 = "RC4, AES128, AES256") + if( $DC."msDS-SupportedEncryptionTypes" -eq 28 -or $DC."msDS-SupportedEncryptionTypes" -eq 31 ){ + $WeakKerberos = $true + Add-Content -Path "$outputdir\dcs_weak_kerberos_ciphersuite.txt" -Value "$($DC.DNSHostName) $($dc."msDS-SupportedEncryptionTypes")" + } + } + Write-Both " [!] You have DCs with RC4 or DES allowed for Kerberos!!!" + #Check where newly joined computers go + $newComputers = (Get-ADDomain).ComputersContainer + $newUsers = (Get-ADDomain).UsersContainer + Write-Both " [+] New joined computers are stored in $newComputers" + Write-Both " [+] New users are stored in $newUsers" +} +Function Get-DefaultDomainControllersPolicy{#Enumerates Default Domain Controllers Policy for default unsecure and excessive options + $ExcessiveDCInteractiveLogon = $false + $ExcessiveDCBackupPermissions = $false + $ExcessiveDCRestorePermissions = $false + $ExcessiveDCDriverPermissions = $false + $ExcessiveDCLocalShutdownPermissions = $false + $ExcessiveDCRemoteShutdownPermissions = $false + $ExcessiveDCTimePermissions = $false + $ExcessiveDCBatchLogonPermissions = $false + $ExcessiveDCRDPLogonPermissions = $false + $GPO = Get-GPO 'Default Domain Controllers Policy' + $GPOreport = Get-GPOReport -Guid $GPO.Id -ReportType Xml + #Interactive local logon + $permissionindex = $GPOreport.IndexOf('SeInteractiveLogonRight') + if($permissionindex -gt 0 -and $GPO.DisplayName -eq 'Default Domain Controllers Policy'){ + $xmlreport = [xml]$GPOreport + foreach($member in (($xmlreport.GPO.Computer.ExtensionData.Extension.UserRightsAssignment | Where-Object {$_.Name -eq 'SeInteractiveLogonRight'}).Member)){ + if($member.Name.'#text' -ne 'BUILTIN\$Administrators' -and $member.Name.'#text' -ne "$EntrepriseDomainControllers"){ + $ExcessiveDCInteractiveLogon = $true + Add-Content -Path "$outputdir\default_domain_controller_policy_audit.txt" -Value "SeInteractiveLogonRight $($member.Name.'#text')" + } + } + } + #Batch logon + $permissionindex = $GPOreport.IndexOf('SeBatchLogonRight') + if($permissionindex -gt 0 -and $GPO.DisplayName -eq 'Default Domain Controllers Policy'){ + $xmlreport = [xml]$GPOreport + foreach($member in (($xmlreport.GPO.Computer.ExtensionData.Extension.UserRightsAssignment | Where-Object {$_.Name -eq 'SeBatchLogonRight'}).Member)){ + if($member.Name.'#text' -ne 'BUILTIN\$Administrators'){ + $ExcessiveDCBatchLogonPermissions = $true + Add-Content -Path "$outputdir\default_domain_controller_policy_audit.txt" -Value "SeBatchLogonRight $($member.Name.'#text')" + } + } + } + #RDP logon + $permissionindex = $GPOreport.IndexOf('SeInteractiveLogonRight') + if($permissionindex -gt 0 -and $GPO.DisplayName -eq 'Default Domain Controllers Policy'){ + $xmlreport = [xml]$GPOreport + foreach($member in (($xmlreport.GPO.Computer.ExtensionData.Extension.UserRightsAssignment | Where-Object {$_.Name -eq 'SeInteractiveLogonRight'}).Member)){ + if($member.Name.'#text' -ne 'BUILTIN\$Administrators' -and $member.Name.'#text' -ne "$EntrepriseDomainControllers"){ + $ExcessiveDCRDPLogonPermissions = $true + Add-Content -Path "$outputdir\default_domain_controller_policy_audit.txt" -Value "SeInteractiveLogonRight $($member.Name.'#text')" + } + } + } + #Backup + $permissionindex = $GPOreport.IndexOf('SeBackupPrivilege') + if($permissionindex -gt 0 -and $GPO.DisplayName -eq 'Default Domain Controllers Policy'){ + $xmlreport = [xml]$GPOreport + foreach($member in (($xmlreport.GPO.Computer.ExtensionData.Extension.UserRightsAssignment | Where-Object {$_.Name -eq 'SeBackupPrivilege'}).Member)){ + if($member.Name.'#text' -ne 'BUILTIN\$Administrators'){ + $ExcessiveDCBackupPermissions = $true + Add-Content -Path "$outputdir\default_domain_controller_policy_audit.txt" -Value "SeBackupPrivilege $($member.Name.'#text')" + } + } + } + #Restore + $permissionindex = $GPOreport.IndexOf('SeRestorePrivilege') + if($permissionindex -gt 0 -and $GPO.DisplayName -eq 'Default Domain Controllers Policy'){ + $xmlreport = [xml]$GPOreport + foreach($member in (($xmlreport.GPO.Computer.ExtensionData.Extension.UserRightsAssignment | Where-Object {$_.Name -eq 'SeRestorePrivilege'}).Member)){ + if($member.Name.'#text' -ne 'BUILTIN\$Administrators'){ + $ExcessiveDCRestorePermissions = $true + Add-Content -Path "$outputdir\default_domain_controller_policy_audit.txt" -Value "SeRestorePrivilege $($member.Name.'#text')" + } + } + } + #Load driver + $permissionindex = $GPOreport.IndexOf('SeLoadDriverPrivilege') + if($permissionindex -gt 0 -and $GPO.DisplayName -eq 'Default Domain Controllers Policy'){ + $xmlreport = [xml]$GPOreport + foreach($member in (($xmlreport.GPO.Computer.ExtensionData.Extension.UserRightsAssignment | Where-Object {$_.Name -eq 'SeLoadDriverPrivilege'}).Member)){ + if($member.Name.'#text' -ne 'BUILTIN\$Administrators'){ + $ExcessiveDCDriverPermissions = $true + Add-Content -Path "$outputdir\default_domain_controller_policy_audit.txt" -Value "SeLoadDriverPrivilege $($member.Name.'#text')" + } + } + } + #Local shutdown + $permissionindex = $GPOreport.IndexOf('SeShutdownPrivilege') + if($permissionindex -gt 0 -and $GPO.DisplayName -eq 'Default Domain Controllers Policy'){ + $xmlreport = [xml]$GPOreport + foreach($member in (($xmlreport.GPO.Computer.ExtensionData.Extension.UserRightsAssignment | Where-Object {$_.Name -eq 'SeShutdownPrivilege'}).Member)){ + if($member.Name.'#text' -ne 'BUILTIN\$Administrators'){ + $ExcessiveDCLocalShutdownPermissions = $true + Add-Content -Path "$outputdir\default_domain_controller_policy_audit.txt" -Value "SeShutdownPrivilege $($member.Name.'#text')" + } + } + } + #Remote shutdown + $permissionindex = $GPOreport.IndexOf('SeRemoteShutdownPrivilege') + if($permissionindex -gt 0 -and $GPO.DisplayName -eq 'Default Domain Controllers Policy'){ + $xmlreport = [xml]$GPOreport + foreach($member in (($xmlreport.GPO.Computer.ExtensionData.Extension.UserRightsAssignment | Where-Object {$_.Name -eq 'SeRemoteShutdownPrivilege'}).Member)){ + if($member.Name.'#text' -ne 'BUILTIN\$Administrators'){ + $ExcessiveDCRemoteShutdownPermissions = $true + Add-Content -Path "$outputdir\default_domain_controller_policy_audit.txt" -Value "SeRemoteShutdownPrivilege $($member.Name.'#text')" + } + } + } + #Change time + $permissionindex = $GPOreport.IndexOf('SeSystemTimePrivilege') + if($permissionindex -gt 0 -and $GPO.DisplayName -eq 'Default Domain Controllers Policy'){ + $xmlreport = [xml]$GPOreport + foreach($member in (($xmlreport.GPO.Computer.ExtensionData.Extension.UserRightsAssignment | Where-Object {$_.Name -eq 'SeSystemTimePrivilege'}).Member)){ + if($member.Name.'#text' -ne 'BUILTIN\$Administrators' -and $member.Name.'#text' -ne "$LocalService"){ + $ExcessiveDCTimePermissions = $true + Add-Content -Path "$outputdir\default_domain_controller_policy_audit.txt" -Value "SeSystemTimePrivilege $($member.Name.'#text')" + } + } + } + #Output for Default Domain Controllers Policy + if($ExcessiveDCInteractiveLogon -or $ExcessiveDCBackupPermissions -or $ExcessiveDCRestorePermissions -or $ExcessiveDCDriverPermissions -or $ExcessiveDCLocalShutdownPermissions -or $ExcessiveDCRemoteShutdownPermissions -or $ExcessiveDCTimePermissions -or $ExcessiveDCBatchLogonPermissions -or $ExcessiveDCRDPLogonPermissions){ + Write-Both " [!] Excessive permissions in Default Domain Controllers Policy detected!" + } +} +Function Get-RecentChanges(){#Retrieve users and groups that have been created during last 30 days + $DateCutOff = ((Get-Date).AddDays(-30)).Date + $newUsers = Get-ADUser -Filter {whenCreated -ge $DateCutOff} -Properties whenCreated | select whenCreated,SamAccountName + $newGroups = Get-ADGroup -Filter {whenCreated -ge $DateCutOff} -Properties whenCreated | select whenCreated,SamAccountName + $countUsers = 0 + $countGroups = 0 + $progresscountUsers = 0 + $progresscountGroups = 0 + $totalcountUsers = ($newUsers | Measure-Object | Select-Object Count).count + $totalcountGroups = ($newGroups | Measure-Object | Select-Object Count).count + if($totalcountUsers -gt 0){ + foreach($newUser in $newUsers ){Add-Content -Path "$outputdir\new_users.txt" -Value "Account $($newUser.SamAccountName) was created $($newUser.whenCreated)"} + Write-Both " [!] $totalcountUsers new users were created last 30 days, see $outputdir\new_users.txt" + } + if($totalcountGroups -gt 0){ + foreach($newGroup in $newGroups ){Add-Content -Path "$outputdir\new_groups.txt" -Value "Group $($newGroup.SamAccountName) was created $($newGroup.whenCreated)"} + Write-Both " [!] $totalcountGroups new groups were created last 30 days, see $outputdir\new_groups.txt" + } +} +Function Get-ReplicationType{#Retrieve replication mechanism (FRS or DFSR) + $objectName = "DFSR-GlobalSettings" + $searcher = [ADSISearcher] "(objectClass=msDFSR-GlobalSettings)" + $objectExists = $searcher.FindOne() -ne $null + if($objectExists){ + $DFSRFlags=(Get-ADObject -Identity "CN=DFSR-GlobalSettings,$((Get-ADDomain).systemscontainer)" -Properties msDFSR-Flags).'msDFSR-Flags' + switch($DFSRFlags){ + 0 { Write-Both " [!] Migration from FRS to DFSR is not finished. Current state: started!" } + 16 { Write-Both " [!] Migration from FRS to DFSR is not finished. Current state: prepared!" } + 32 { Write-Both " [!] Migration from FRS to DFSR is not finished. Current state: redirected!" } + 48 { Write-Both " [+] DFSR mechanism is used to replicate across domain controllers." } + } + }else{ + Write-Both " [!] FRS mechanism is still used to replicate across domain controllers, you should migrate to DFSR!" + } +} +Function Get-RecycleBinState {#Check if recycle bin is enabled + if((Get-ADOptionalFeature -Filter 'Name -eq "Recycle Bin Feature"').EnabledScopes){ + Write-Both " [+] Recycle Bin is enabled in the domain" + }else{ + Write-Both " [!] Recycle Bin is disabled in the domain, you should consider enabling it!" + } +} +Function Get-CriticalServicesStatus{#Check AD services status + Write-Both " [+] Checking services on all DCs" + $dcList = @() + (Get-ADDomainController -Filter *) | ForEach-Object{$dcList += $_.Name} + $objectName = "DFSR-GlobalSettings" + $searcher = [ADSISearcher] "(objectClass=msDFSR-GlobalSettings)" + $objectExists = $searcher.FindOne() -ne $null + if($objectExists){ + $services = @("dns","netlogon","kdc","w32time","ntds","dfsr") + }else{ + $services = @("dns","netlogon","kdc","w32time","ntds","ntfrs") + } + foreach($DC in $dcList){ + foreach($service in $services){ + $checkService = Get-Service $service -ComputerName $DC -ErrorAction SilentlyContinue + $serviceName = $checkService.Name + $serviceStatus = $checkService.Status + if(!($serviceStatus)){ + Write-Both " [!] Service $($service) cannot be checked on $DC!" + } + elseif($serviceStatus -ne "Running"){ + Write-Both " [!] Service $($service) is not running on $DC!" + } + } + } +} +Function Get-LastWUDate{#Check Windows update status and last install date + $dcList = @() + (Get-ADDomainController -Filter *) | ForEach-Object{$dcList+=$_.Name} + $lastMonth = (Get-Date).AddDays(-30) + Write-Both " [+] Checking Windows Update" + foreach($DC in $dcList){ + + $startMode = (Get-WmiObject -ComputerName $DC -Class Win32_Service -Property StartMode -Filter "Name='wuauserv'" -ErrorAction SilentlyContinue).StartMode + if(!($startMode)){ + Write-Both " [!] Windows Update service cannot be checked on $DC!" + } + elseif($startMode -eq "Disabled"){ + Write-Both " [!] Windows Update service is disabled on $DC!" + } + } + $progresscount = 0 + $totalcount = ($dcList | Measure-Object | Select-Object Count).count + foreach($DC in $dcList){ + if($totalcount -eq 0){ break } + Write-Progress -Activity "Searching for last Windows Update installation on all DCs..." -Status "Currently searching on $DC" -PercentComplete ($progresscount / $totalcount*100) + try{ + $lastHotfix = (Get-HotFix -ComputerName $DC | Where-Object {$_.InstalledOn -ne $null} | Sort-Object -Descending InstalledOn | Select-Object -First 1).InstalledOn + if($lastHotfix -lt $lastMonth){ + Write-Both " [!] Windows is not up to date on $DC, last install: $($lastHotfix)" + }else{ + Write-Both " [+] Windows is up to date on $DC, last install: $($lastHotfix)" + } + } + catch{ + Write-Both " [!] Cannot check last update date on $DC" + } + $progresscount++ + } + Write-Progress -Activity "Searching for last Windows Update installation on all DCs..." -Status "Ready" -Completed +} +Function Get-TimeSource {#Get NTP sync source + $dcList = @() + (Get-ADDomainController -Filter *) | ForEach-Object{$dcList += $_.Name} + Write-Both " [+] Checking NTP configuration" + foreach($DC in $dcList){ + $ntpSource = w32tm /query /source /computer:$DC + if($ntpSource -like '*0x800706BA*'){ + Write-Both " [+] Cannot get time source for $DC" + }else{ + Write-Both " [+] $DC is syncing time from $ntpSource" + } + } +} +Function Get-RODC{#Check for RODC + Write-Both " [+] Checking for Read Only DCs" + $ADs = Get-ADDomainController -Filter { Site -like "*" } + $ADs | ForEach-Object{ + if($_.IsReadOnly){ + Write-Both " [+] DC $($_.Name) is a RODC server!" + } + } +} +Function Install-Dependencies{#Install DSInternals + if($PSVersionTable.PSVersion.Major -ge 5){ + [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor + [Net.SecurityProtocolType]::Tls12 + $count = 0 + $totalcount = 3 + Write-Progress -Activity "Installing dependencies..." -Status "Currently installing NuGet Package Provider" -PercentComplete ($count / $totalcount*100) + if(!(Get-PackageProvider -ListAvailable -Name Nuget -ErrorAction SilentlyContinue)){ Install-PackageProvider -Name NuGet -Force | Out-Null } + $count++ + Write-Progress -Activity "Installing dependencies..." -Status "Currently adding PSGallery to trusted Repositories" -PercentComplete ($count / $totalcount*100) + if((Get-PSRepository -Name PSGallery).InstallationPolicy -eq "Untrusted"){ Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted } + $count++ + Write-Progress -Activity "Installing dependencies..." -Status "Currently installing module DSInternals" -PercentComplete ($count / $totalcount*100) + if(!(Get-Module -ListAvailable -Name DSInternals)){ Install-Module -Name DSInternals -Force } + Write-Progress -Activity "Installing dependencies..." -Status "Ready" -Completed + Import-Module DSInternals + }else{ + Write-Both " [!] PowerShell 5 or greater is needed, see https://www.microsoft.com/en-us/download/details.aspx?id=54616" + } +} +Function Remove-StringLatinCharacters{#Removes latin characters + PARAM ([string]$String) + [Text.Encoding]::ASCII.GetString([Text.Encoding]::GetEncoding("Cyrillic").GetBytes($String)) +} +Function Get-PasswordQuality{#Use DSInternals to evaluate password quality + if(Get-Module -ListAvailable -Name DSInternals){ + $totalSite = (Get-ADObject -Filter {objectClass -like "site" } -SearchBase (Get-ADRootDSE).ConfigurationNamingContext | measure).Count + $count = 0 + Get-ADObject -Filter {objectClass -like "site" } -SearchBase (Get-ADRootDSE).ConfigurationNamingContext | ForEach-Object{ + if($_.Name -eq $(Remove-StringLatinCharacters $_.Name)){ $count++ } + } + if($count -ne $totalSite){ + Write-Both " [!] One or more site have illegal characters in their name, can't get password quality!" + }else{ + Get-ADReplAccount -All -Server $env:ComputerName -NamingContext $(Get-ADDomain | select -ExpandProperty DistinguishedName) | Test-PasswordQuality -IncludeDisabledAccounts | Out-File "$outputdir\password_quality.txt" + Write-Both " [!] Password quality test done, see $outputdir\password_quality.txt" + } + } +} +Function Check-Shares {#Check SYSVOL and NETLOGON share exists + $dcList = @() + (Get-ADDomainController -Filter *) | ForEach-Object{$dcList += $_.Name} + Write-Both " [+] Checking SYSVOL and NETLOGON shares on all DCs" + foreach($DC in $dcList){ + $shareList = (Get-WmiObject -Class Win32_Share -ComputerName $DC -ErrorAction SilentlyContinue) + if(!($shareList)){ + Write-Both " [!] Cannot test shares on $DC!" + }else{ + $sysvolShare = ($shareList | ?{$_ -match 'SYSVOL'} | measure).Count + $netlogonShare = ($shareList | ?{$_ -match 'NETLOGON'} | measure).Count + if($sysvolShare -eq 0){ Write-Both " [!] SYSVOL share is missing on $DC!" } + if($netlogonShare -eq 0){ Write-Both " [!] NETLOGON share is missing on $DC!" } + } + } +} + +$outputdir = (Get-Item -Path ".\").FullName + "\" + $env:computername +$starttime = Get-Date +$scriptname = $MyInvocation.MyCommand.Name +if(!(Test-Path "$outputdir")){ New-Item -ItemType Directory -Path $outputdir | Out-Null } +Write-Both " _____ ____ _____ _ _ _ +| _ | \ | _ |_ _ _| |_| |_ +| | | | | | | | . | | _| +|__|__|____/ |__|__|___|___|_|_| +$versionnum by phillips321 +" +$running=$false +Write-Both "[*] Script start time $starttime" +if(Get-Module -ListAvailable -Name ActiveDirectory){ Import-Module ActiveDirectory }else{ Write-Both "[!] ActiveDirectory module not installed, exiting..." ; exit } +if(Get-Module -ListAvailable -Name ServerManager) { Import-Module ServerManager }else{ Write-Both "[!] ServerManager module not installed, exiting..." ; exit } +if(Get-Module -ListAvailable -Name GroupPolicy) { Import-Module GroupPolicy }else{ Write-Both "[!] GroupPolicy module not installed, exiting..." ; exit } +if(Get-Module -ListAvailable -Name DSInternals) { Import-Module DSInternals }else{ Write-Both "[!] DSInternals module not installed, use -installdeps to force install" } +if(Test-Path "$outputdir\adaudit.nessus"){ Remove-Item -recurse "$outputdir\adaudit.nessus" | Out-Null } +Write-Nessus-Header +Write-Host "[+] Outputting to $outputdir" +Write-Both "[*] Lang specific variables" +Get-Variables +if($installdeps) { $running=$true ; Write-Both "[*] Installing optionnal features" ; Install-Dependencies } +if($hostdetails -or $all) { $running=$true ; Write-Both "[*] Device Information" ; Get-HostDetails } +if($domainaudit -or $all) { $running=$true ; Write-Both "[*] Domain Audit" ; Get-LastWUDate ; Get-DCEval ; Get-TimeSource ; Get-PrivilegedGroupMembership ; Get-MachineAccountQuota; Get-DefaultDomainControllersPolicy ; Get-SMB1Support ; Get-FunctionalLevel ; Get-DCsNotOwnedByDA ; Get-ReplicationType ; Check-Shares ; Get-RecycleBinState ; Get-CriticalServicesStatus ; Get-RODC } +if($trusts -or $all) { $running=$true ; Write-Both "[*] Domain Trust Audit" ; Get-DomainTrusts } +if($accounts -or $all) { $running=$true ; Write-Both "[*] Accounts Audit" ; Get-InactiveAccounts ; Get-DisabledAccounts ; Get-LockedAccounts ; Get-AdminAccountChecks ; Get-NULLSessions ; Get-PrivilegedGroupAccounts ; Get-ProtectedUsers } +if($passwordpolicy -or $all) { $running=$true ; Write-Both "[*] Password Information Audit" ; Get-AccountPassDontExpire ; Get-UserPasswordNotChangedRecently ; Get-PasswordPolicy ; Get-PasswordQuality } +if($ntds -or $all) { $running=$true ; Write-Both "[*] Trying to save NTDS.dit, please wait..." ; Get-NTDSdit } +if($oldboxes -or $all) { $running=$true ; Write-Both "[*] Computer Objects Audit" ; Get-OldBoxes } +if($gpo -or $all) { $running=$true ; Write-Both "[*] GPO audit (and checking SYSVOL for passwords)" ; Get-GPOtoFile ; Get-GPOsPerOU ; Get-SYSVOLXMLS; Get-GPOEnum } +if($ouperms -or $all) { $running=$true ; Write-Both "[*] Check Generic Group AD Permissions" ; Get-OUPerms } +if($laps -or $all) { $running=$true ; Write-Both "[*] Check For Existence of LAPS in domain" ; Get-LAPSStatus } +if($authpolsilos -or $all) { $running=$true ; Write-Both "[*] Check For Existence of Authentication Polices and Silos" ; Get-AuthenticationPoliciesAndSilos } +if($insecurednszone -or $all){ $running=$true ; Write-Both "[*] Check For Existence DNS Zones allowing insecure updates" ; Get-DNSZoneInsecure } +if($recentchanges -or $all) { $running=$true ; Write-Both "[*] Check For newly created users and groups" ; Get-RecentChanges } +if(!$running){ Write-Both "[!] No arguments selected" + Write-Both "[!] Other options are as follows, they can be used in combination" + Write-Both " -installdeps installs optionnal features (DSInternals)" + Write-Both " -hostdetails retrieves hostname and other useful audit info" + Write-Both " -domainaudit retrieves information about the AD such as functional level" + Write-Both " -trusts retrieves information about any doman trusts" + Write-Both " -accounts identifies account issues such as expired, disabled, etc..." + Write-Both " -passwordpolicy retrieves password policy information" + Write-Both " -ntds dumps the NTDS.dit file using ntdsutil" + Write-Both " -oldboxes identifies outdated OSs like 2000/2003/XP/Vista/7/2008 joined to the domain" + Write-Both " -gpo dumps the GPOs in XML and HTML for later analysis" + Write-Both " -ouperms checks generic OU permission issues" + Write-Both " -laps checks if LAPS is installed" + Write-Both " -authpolsilos checks for existence of authentication policies and silos" + Write-Both " -insecurednszone checks for insecure DNS zones" + Write-Both " -recentchanges checks for newly created users and groups (last 30 days)" + Write-Both " -all runs all checks, e.g. $scriptname -all" +} +Write-Nessus-Footer + +#Dirty fix for .nessus characters (will do this properly or as a function later. Will need more characters adding here...) +$originalnessusoutput = Get-Content $outputdir\adaudit.nessus +$nessusoutput = $originalnessusoutput -Replace "&", "&" +$nessusoutput = $nessusoutput -Replace "`“", """ +$nessusoutput = $nessusoutput -Replace "`'", "'" +$nessusoutput = $nessusoutput -Replace "ü", "u" +$nessusoutput | Out-File $outputdir\adaudit-replaced.nessus + +$endtime = Get-Date +Write-Both "[*] Script end time $endtime" \ No newline at end of file diff --git a/Audit.ps1 b/Audit.ps1 new file mode 100644 index 0000000..79fd9f3 --- /dev/null +++ b/Audit.ps1 @@ -0,0 +1,1658 @@ +<# +.SYNOPSIS + + +.NOTES + Version : 1.0 + Author : Hubert CORNET + Creation Date : 20/11/2022 + Purpose/Change : + +.LINK + https://www.tips-of-mine.fr + +.EXEMPLE + + +.DESCRIPTION + + +.PARAMETER CompanyLogo + Enter URL or UNC path to your desired Company Logo for generated report. + + -CompanyLogo "https://www.fichorga.fr/images/logo-logiciel-fichorga.png" + +.PARAMETER ReportTitle + Enter desired title for generated report. + + -ReportTitle "Active Directory Report" + +.PARAMETER Days + Users that have not logged in within [X] amount of days. + + -Days "90" + +.PARAMETER UserCreatedDays + Users that have been created within [X] amount of days. + + -UserCreatedDays "15" + +.PARAMETER DaysUntilPWExpireINT + Users password expires within [X] amount of days + + -DaysUntilPWExpireINT "15" + +.PARAMETER ADModNumber + Active Directory Objects that have been modified within [X] amount of days. + + -ADModNumber "15" + +.INPUTS + + +.OUTPUTS + .log> +#> + +#---------------------------------------------------------[Initialisations]-------------------------------------------------------- + +param ( + #Company logo that will be displayed on the left, can be URL or UNC + [Parameter(ValueFromPipeline = $true, HelpMessage = "Entrez l'URL ou le chemin UNC vers le logo de l'entreprise")] + [String]$CompanyLogo = "https://www.fichorga.fr/images/logo-logiciel-fichorga.png", + #Logo that will be on the right side, UNC or URL + + [Parameter(ValueFromPipeline = $true, HelpMessage = "Entrez le titre souhaité pour le rapport")] + [String]$ReportTitle = "Rapport Active Directory", + #Location the report will be saved to + + [Parameter(ValueFromPipeline = $true, HelpMessage = "Entrez le chemin du répertoire souhaité pour enregistrer; Default: C:\Automation\")] + [String]$ReportSavePath = "C:\Automation\", + #Find users that have not logged in X Amount of days, this sets the days + + [Parameter(ValueFromPipeline = $true, HelpMessage = "Les utilisateurs qui ne se sont pas connectés dans les [X] nombre de jours; Default: 90")] + $Days = 90, + #Get users who have been created in X amount of days and less + + [Parameter(ValueFromPipeline = $true, HelpMessage = "Les utilisateurs qui ont été créés dans [X] nombre de jours; Default: 15")] + $UserCreatedDays = 15, + #Get users whos passwords expire in less than X amount of days + + [Parameter(ValueFromPipeline = $true, HelpMessage = "Le mot de passe de l'utilisateur expire dans un délai de [X] nombre de jours; Default: 15")] + $DaysUntilPWExpireINT = 15, + #Get AD Objects that have been modified in X days and newer + + [Parameter(ValueFromPipeline = $true, HelpMessage = "Les objets AD qui ont été modifiés dans [X] nombre de jours; Default: 15")] + $ADModNumber =15 + + #CSS template located C:\Program Files\WindowsPowerShell\Modules\ReportHTML\1.4.1.1\ + #Default template is orange and named "Sample" +) + +#---------------------------------------------------------[Initialisations]-------------------------------------------------------- + +# Définir l'action d'erreur pour continuer silencieusement +$ErrorActionPreference = "SilentlyContinue" + +$Minute = (Get-Date).Minute +$Hour = (Get-Date).Hour +$Day = (Get-Date).Day +$Month = (Get-Date).Month +$Year = (Get-Date).Year + +#-----------------------------------------------------------[Functions]------------------------------------------------------------ + +Function LastLogonConvert ($ftDate) { + $Date = [DateTime]::FromFileTime($ftDate) + If ($Date -lt (Get-Date '1/1/1900') -or $date -eq 0 -or $date -eq $null) { + "Never" + } + Else { + $Date + } + +} + +Function Write-Color([String[]]$Text, [ConsoleColor[]]$Color = "White", [int]$StartTab = 0, [int] $LinesBefore = 0,[int] $LinesAfter = 0, [string] $LogFile = "", $TimeFormat = "yyyy-MM-dd HH:mm:ss") { + + $DefaultColor = $Color[0] + + If ($LinesBefore -ne 0) { for ($i = 0; $i -lt $LinesBefore; $i++) { Write-Host "`n" -NoNewline } } # Add empty line before + + If ($StartTab -ne 0) { for ($i = 0; $i -lt $StartTab; $i++) { Write-Host "`t" -NoNewLine } } # Add TABS before text + + If ($Color.Count -ge $Text.Count) { + For ($i = 0; $i -lt $Text.Length; $i++) { Write-Host $Text[$i] -ForegroundColor $Color[$i] -NoNewLine } + } + Else { + For ($i = 0; $i -lt $Color.Length ; $i++) { Write-Host $Text[$i] -ForegroundColor $Color[$i] -NoNewLine } + For ($i = $Color.Length; $i -lt $Text.Length; $i++) { Write-Host $Text[$i] -ForegroundColor $DefaultColor -NoNewLine } + } + + Write-Host + If ($LinesAfter -ne 0) { for ($i = 0; $i -lt $LinesAfter; $i++) { Write-Host "`n" } } # Add empty line after + If ($LogFile -ne "") { + $TextToFile = "" + For ($i = 0; $i -lt $Text.Length; $i++) { + $TextToFile += $Text[$i] + } + Write-Output "[$([datetime]::Now.ToString($TimeFormat))]$TextToFile" | Out-File $LogFile -Encoding unicode -Append + } +} + +#--------------------------------------------------------[Debut Du Script]--------------------------------------------------------- + +Clear-Host + +#Check for ReportHTML Module +$Mod = Get-Module -ListAvailable -Name "ReportHTML" + +If ($null -eq $Mod) { + Write-Host "Le module ReportHTML n'est pas présent, tentative d'installation." + + Install-Module -Name ReportHTML -Force + Import-Module ReportHTML -ErrorAction SilentlyContinue +} + +Write-host "`n" +Write-Color "Personnalisation des rapports de collecte ..." -Color White +Write-host "`n" +Write-Color "__________________________________________________________________________________" -Color White +Write-Color "Logo de l'entreprise (gauche) : __________________________________________________ ", $CompanyLogo -Color White, Green +Write-Color "Titre du rapport : _______________________________________________________________ ", $ReportTitle -Color White, Green +Write-Color "Chemin de sauvegarde du rapport : ________________________________________________ ", $ReportSavePath -Color White, Green +Write-Color "Rapport sur le nombre de jours depuis la dernière connexion de l'utilisateur : ___ ", $Days -Color White, Green +Write-Color "Nombre de jours pour la création de nouveaux utilisateurs : ______________________ ", $UserCreatedDays -Color White, Green +Write-Color "Nombre de jours pour l'expiration du mot de passe : ______________________________ ", $DaysUntilPWExpireINT -Color White, Green +Write-Color "Nombre de jours pour les objets AD nouvellement modifiés : _______________________ ", $ADModNumber -Color White, Green +Write-Color "__________________________________________________________________________________" -Color White + +#Array of default Security Groups +$DefaultSGs = @( + "Opérateurs d’assistance Access Control" + "Opérateurs de compte" + "Administrateurs" + "Réplication de mot de passe RODC autorisée" + "Opérateurs de sauvegarde" + "Accès DCOM au service de certificats" + "Éditeurs de certificats" + "Contrôleurs de domaine clonables" + "Opérateurs de chiffrement" + "Réplication de mot de passe RODC refusée" + "Propriétaires d’appareils" + "Administrateurs DHCP" + "Utilisateurs DHCP" + "Utilisateurs du modèle COM distribué" + "DnsUpdateProxy" + "DnsAdmins" + "Administrateurs du domaine" + "Ordinateurs de domaine" + "Contrôleurs de domaine" + "Invités de domaine" + "Utilisateurs du domaine" + "Administrateurs de l’entreprise" + "Enterprise Key Admins" + "Contrôleurs de domaine d’entreprise en lecture seule" + "Lecteurs des journaux d’événements" + "Propriétaires créateurs de la stratégie de groupe" + "Invités" + "Administrateurs Hyper-V" + "IIS_IUSRS" + "Générateurs d’approbation de forêt entrante" + "Administrateurs de clés" + "Opérateurs de configuration réseau" + "Utilisateurs du journal des performances" + "Utilisateurs de l’Analyseur de performances" + "Accès pré-Windows 2000 compatible" + "Opérateurs d'impression" + "Utilisateurs protégés" + "Serveurs RAS et IAS" + "Serveurs de points de terminaison..." + "Serveurs d’administration RDS" + "Serveurs d’accès à distance RDS" + "Contrôleurs de domaine en lecture seule" + "Utilisateurs du Bureau à distance" + "Utilisateurs de gestion à distance" + "Duplicateur" + "Administrateurs du schéma" + "Opérateurs de serveur" + "Administrateurs de réplica de stockage" + "Comptes gérés par le système" + "Serveurs de licences Terminal Server" + "Utilisateurs" + "Accès à l’autorisation Windows" + "WinRMRemoteWMIUsers_" +) + +$Table = New-Object 'System.Collections.Generic.List[System.Object]' +$OUTable = New-Object 'System.Collections.Generic.List[System.Object]' +$UserTable = New-Object 'System.Collections.Generic.List[System.Object]' +$UserPasswordTable = New-Object 'System.Collections.Generic.List[System.Object]' +$GroupTypetable = New-Object 'System.Collections.Generic.List[System.Object]' +$DefaultGrouptable = New-Object 'System.Collections.Generic.List[System.Object]' +$EnabledDisabledUsersTable = New-Object 'System.Collections.Generic.List[System.Object]' +$DomainAdminTable = New-Object 'System.Collections.Generic.List[System.Object]' +$ExpiringAccountsTable = New-Object 'System.Collections.Generic.List[System.Object]' +$CompanyInfoTable = New-Object 'System.Collections.Generic.List[System.Object]' +$securityeventtable = New-Object 'System.Collections.Generic.List[System.Object]' +$DomainTable = New-Object 'System.Collections.Generic.List[System.Object]' +$OUGPOTable = New-Object 'System.Collections.Generic.List[System.Object]' +$GroupMembershipTable = New-Object 'System.Collections.Generic.List[System.Object]' +$PasswordExpirationTable = New-Object 'System.Collections.Generic.List[System.Object]' +$PasswordExpireSoonTable = New-Object 'System.Collections.Generic.List[System.Object]' +$userphaventloggedonrecentlytable = New-Object 'System.Collections.Generic.List[System.Object]' +$EnterpriseAdminTable = New-Object 'System.Collections.Generic.List[System.Object]' +$NewCreatedUsersTable = New-Object 'System.Collections.Generic.List[System.Object]' +$GroupProtectionTable = New-Object 'System.Collections.Generic.List[System.Object]' +$OUProtectionTable = New-Object 'System.Collections.Generic.List[System.Object]' +$GPOTable = New-Object 'System.Collections.Generic.List[System.Object]' +$ADObjectTable = New-Object 'System.Collections.Generic.List[System.Object]' +$ProtectedUsersTable = New-Object 'System.Collections.Generic.List[System.Object]' +$ComputersTable = New-Object 'System.Collections.Generic.List[System.Object]' +$ComputerProtectedTable = New-Object 'System.Collections.Generic.List[System.Object]' +$ComputersEnabledTable = New-Object 'System.Collections.Generic.List[System.Object]' +$DefaultComputersinDefaultOUTable = New-Object 'System.Collections.Generic.List[System.Object]' +$DefaultUsersinDefaultOUTable = New-Object 'System.Collections.Generic.List[System.Object]' +$TOPUserTable = New-Object 'System.Collections.Generic.List[System.Object]' +$TOPGroupsTable = New-Object 'System.Collections.Generic.List[System.Object]' +$TOPComputersTable = New-Object 'System.Collections.Generic.List[System.Object]' +$GraphComputerOS = New-Object 'System.Collections.Generic.List[System.Object]' + +#Get all users right away. Instead of doing several lookups, we will use this object to look up all the information needed. +$AllUsers = Get-ADUser -Filter * -Properties * + +$GPOs = Get-GPO -All | Select-Object DisplayName, GPOStatus, ModificationTime, @{ Label = "ComputerVersion"; Expression = { $_.computer.dsversion } }, @{ Label = "UserVersion"; Expression = { $_.user.dsversion } } + +<########################### + Dashboard +############################> +Write-Host "Analyse sur le rapport du tableau de bord ........................................ " -ForegroundColor Green -NoNewline + +$dte = (Get-Date).AddDays(- $ADModNumber) + +$ADObjs = Get-ADObject -Filter { whenchanged -gt $dte -and ObjectClass -ne "domainDNS" -and ObjectClass -ne "rIDManager" -and ObjectClass -ne "rIDSet" } -Properties * +$Compteur = 0 + +Foreach ($ADObj in $ADObjs) { + $Compteur++ + Write-Progress -Id 0 -Activity "Analyse : " -Status "Processing $($Compteur) of $($ADObjs.count)" -CurrentOperation $ADObj -PercentComplete (($Compteur / $ADObjs.count) * 100) + + If ($ADObj.ObjectClass -eq "GroupPolicyContainer") { + $Name = $ADObj.DisplayName + } + Else{ + $Name = $ADObj.Name + } + + $obj = [PSCustomObject]@{ + "Name" = $Name + "Type Object" = $ADObj.ObjectClass + "Date changement" = $ADObj.WhenChanged + } + $ADObjectTable.Add($obj) +} + +$ADRecycleBinStatus = (Get-ADOptionalFeature -Filter 'name -like "Recycle Bin Feature"').EnabledScopes + +If ($ADRecycleBinStatus.Count -lt 1) { + $ADRecycleBin = "Desactive" +} +Else { + $ADRecycleBin = "Actif" +} + +#Company Information +$ADInfo = Get-ADDomain +$ForestObj = Get-ADForest +$DomainControllerobj = Get-ADDomain +$Forest = $ADInfo.Forest +$InfrastructureMaster = $DomainControllerobj.InfrastructureMaster +$RIDMaster = $DomainControllerobj.RIDMaster +$PDCEmulator = $DomainControllerobj.PDCEmulator +$DomainNamingMaster = $ForestObj.DomainNamingMaster +$SchemaMaster = $ForestObj.SchemaMaster + +$obj = [PSCustomObject]@{ + "Domaine" = $Forest + "Corbeille AD" = $ADRecycleBin + "Maitre de l'infrastructure" = $InfrastructureMaster + "Maitre RID" = $RIDMaster + "Emulateur PDC" = $PDCEmulator + "Maitre des noms de domaine" = $DomainNamingMaster + "Maitre Schema" = $SchemaMaster +} + +$CompanyInfoTable.Add($obj) + +#Get newly created users +$When = ((Get-Date).AddDays(- $UserCreatedDays)).Date +$NewUsers = $AllUsers | Where-Object { $_.whenCreated -ge $When } + +Foreach ($Newuser in $Newusers) { + $obj = [PSCustomObject]@{ + "Name" = $Newuser.Name + "Actif" = $Newuser.Enabled + "Date creation" = $Newuser.whenCreated + } + $NewCreatedUsersTable.Add($obj) +} + +#Get Domain Admins +$DomainAdminMembers = Get-ADGroupMember "Admins du domaine" + +Foreach ($DomainAdminMember in $DomainAdminMembers) { + $Name = $DomainAdminMember.Name + $Type = $DomainAdminMember.ObjectClass + $Enabled = ($AllUsers | Where-Object { $_.Name -eq $Name }).Enabled + + $obj = [PSCustomObject]@{ + "Name" = $Name + "Actif" = $Enabled + "Type" = $Type + } + $DomainAdminTable.Add($obj) +} + +#Get Enterprise Admins +$EnterpriseAdminsMembers = Get-ADGroupMember "Administrateurs de l’entreprise" + +If (($EnterpriseAdminsMembers).Count -eq 0) { + $EnterpriseAdminsMember = [PSCustomObject]@{ + Information = "Informations : Aucun utilisateur n'a ete trouve dans le groupe Administrateurs de l’entreprise" + } +} +Else { + Foreach ($EnterpriseAdminsMember in $EnterpriseAdminsMembers) { + $Name = $EnterpriseAdminsMember.Name + $Type = $EnterpriseAdminsMember.ObjectClass + $Enabled = ($AllUsers | Where-Object { $_.Name -eq $Name }).Enabled + + $obj = [PSCustomObject]@{ + "Name" = $Name + "Actif" = $Enabled + "Type" = $Type + } + $EnterpriseAdminTable.Add($obj) + } +} + +$DefaultComputersOU = (Get-ADDomain).computerscontainer +$DefaultComputers = Get-ADComputer -Filter * -Properties * -SearchBase "$DefaultComputersOU" + +Foreach ($DefaultComputer in $DefaultComputers) { + $obj = [PSCustomObject]@{ + "Name" = $DefaultComputer.Name + "Actif" = $DefaultComputer.Enabled + "Systeme d'exploitation" = $DefaultComputer.OperatingSystem + "Date modification" = $DefaultComputer.Modified + "Dernier mot de passe defini" = $DefaultComputer.PasswordLastSet + "Protege contre la suppression" = $DefaultComputer.ProtectedFromAccidentalDeletion + } + $DefaultComputersinDefaultOUTable.Add($obj) +} + +$DefaultUsersOU = (Get-ADDomain).UsersContainer +$DefaultUsers = $Allusers | Where-Object { $_.DistinguishedName -like "*$($DefaultUsersOU)" } | Select-Object Name, UserPrincipalName, Enabled, ProtectedFromAccidentalDeletion, EmailAddress, @{ Name = 'lastlogon'; Expression = { LastLogonConvert $_.lastlogon } }, DistinguishedName + +Foreach ($DefaultUser in $DefaultUsers) { + $obj = [PSCustomObject]@{ + "Name" = $DefaultUser.Name + "UserPrincipalName" = $DefaultUser.UserPrincipalName + "Actif" = $DefaultUser.Enabled + "Protege contre la suppression" = $DefaultUser.ProtectedFromAccidentalDeletion + "Derniere connexion" = $DefaultUser.LastLogon + "Adresse mail" = $DefaultUser.EmailAddress + } + $DefaultUsersinDefaultOUTable.Add($obj) +} + +#Expiring Accounts +$LooseUsers = Search-ADAccount -AccountExpiring -UsersOnly + +Foreach ($LooseUser in $LooseUsers) { + $NameLoose = $LooseUser.Name + $UPNLoose = $LooseUser.UserPrincipalName + $ExpirationDate = $LooseUser.AccountExpirationDate + $enabled = $LooseUser.Enabled + + $obj = [PSCustomObject]@{ + "Name" = $NameLoose + "UserPrincipalName" = $UPNLoose + "Date expiration" = $ExpirationDate + "Actif" = $enabled + } + $ExpiringAccountsTable.Add($obj) +} + +If (($ExpiringAccountsTable).Count -eq 0) { + $ExpiringAccountsTable = [PSCustomObject]@{ + Information = "Informations : Aucun utilisateur n'expire bientot" + } +} + +#Analyse journaux audti sécurité +$SecurityLogs = Get-EventLog -Newest 7 -LogName "Security" | Where-Object { $_.Message -like "*An account*" } + +Foreach ($SecurityLog in $SecurityLogs) { + $TimeGenerated = $SecurityLog.TimeGenerated + $EntryType = $SecurityLog.EntryType + $Recipient = $SecurityLog.Message + + $obj = [PSCustomObject]@{ + "Time" = $TimeGenerated + "Type" = $EntryType + "Message" = $Recipient + } + $SecurityEventTable.Add($obj) +} + +If (($securityeventtable).Count -eq 0) { + $securityeventtable = [PSCustomObject]@{ + Information = "Informations : Aucun journal de securite recent" + } +} + +#Tenant Domain +$Domains = Get-ADForest | Select-Object -ExpandProperty upnsuffixes | ForEach-Object{ + $obj = [PSCustomObject]@{ + "UPN Suffixes" = $_ + Valid = "True" + } + $DomainTable.Add($obj) +} + +Write-Host "Terminé !" -ForegroundColor White + +Write-Progress -Id 0 -Activity "Analyse : " -completed + +<########################### + Groups +############################> +Write-Host "Rapport sur les groupes .......................................................... " -ForegroundColor Green -NoNewline + +#Get groups and sort in alphabetical order +$Groups = Get-ADGroup -Filter * -Properties * +$SecurityCount = 0 +$MailSecurityCount = 0 +$CustomGroup = 0 +$DefaultGroup = 0 +$Groupswithmemebrship = 0 +$Groupswithnomembership = 0 +$GroupsProtected = 0 +$GroupsNotProtected = 0 +$Compteur = 0 + +Foreach ($Group in $Groups) { + $Compteur++ + Write-Progress -Id 1 -Activity "Analyse : " -Status "Processing $($Compteur) of $($Groups.count)" -CurrentOperation $Group -PercentComplete (($Compteur / $Groups.count) * 100) + $DefaultADGroup = 'False' + $Type = New-Object 'System.Collections.Generic.List[System.Object]' + $Gemail = (Get-ADGroup $Group -Properties mail).mail + + If (($group.GroupCategory -eq "Security") -and ($Gemail -ne $Null)) { + $MailSecurityCount++ + } + + If (($group.GroupCategory -eq "Security") -and (($Gemail) -eq $Null)) { + $SecurityCount++ + } + + If ($Group.ProtectedFromAccidentalDeletion -eq $True) { + $GroupsProtected++ + } + Else { + $GroupsNotProtected++ + } + + If ($DefaultSGs -contains $Group.Name) { + $DefaultADGroup = "True" + $DefaultGroup++ + } + Else { + $CustomGroup++ + } + + If ($group.GroupCategory -eq "Distribution") { + $Type = "Groupe de distribution" + } + + If (($group.GroupCategory -eq "Security") -and (($Gemail) -eq $Null)) { + $Type = "Groupe de securite" + } + + If (($group.GroupCategory -eq "Security") -and (($Gemail) -ne $Null)) { + $Type = "Groupe de securite active par courrier" + } + + If ($Group.Name -ne "Domain Users") { + $Users = (Get-ADGroupMember -Identity $Group | Sort-Object DisplayName | Select-Object -ExpandProperty Name) -join ", " + + If (!($Users)) { + $Groupswithnomembership++ + } + Else { + $Groupswithmemebrship++ + } + } + Else { + $Users = "Skipped Domain Users Membership" + } + + $OwnerDN = Get-ADGroup -Filter { name -eq $Group.Name } -Properties managedBy | Select-Object -ExpandProperty ManagedBy + $Manager = $AllUsers | Where-Object { $_.distinguishedname -eq $OwnerDN } | Select-Object -ExpandProperty Name + + $obj = [PSCustomObject]@{ + "Name" = $Group.name + "Type" = $Type + "Membres" = $users + "Gere par" = $Manager + "Adresse mail" = $GEmail + "Protege contre la suppression" = $Group.ProtectedFromAccidentalDeletion + "Default AD Groupe" = $DefaultADGroup + } + $table.Add($obj) +} + +If (($table).Count -eq 0) { + $table = [PSCustomObject]@{ + Information = "Information : Aucun groupe n'a ete trouve" + } +} + +#TOP groups table +$obj1 = [PSCustomObject]@{ + "Total Groupes" = $Groups.Count + "Groupes de securite compatibles avec la messagerie" = $MailSecurityCount + "Groupes de securite" = $SecurityCount + "Groupes de distribution" = $DistroCount +} + +$TOPGroupsTable.Add($obj1) + +$obj1 = [PSCustomObject]@{ + 'Name' = "Groupes de securite compatibles avec la messagerie" + 'Count' = $MailSecurityCount +} + +$GroupTypetable.Add($obj1) + +$obj1 = [PSCustomObject]@{ + 'Name' = "Groupes de securite" + 'Count' = $SecurityCount +} + +$GroupTypetable.Add($obj1) +$DistroCount = ($Groups | Where-Object { $_.GroupCategory -eq "Distribution" }).Count + +$obj1 = [PSCustomObject]@{ + 'Name' = "Groupes de distribution" + 'Count' = $DistroCount +} + +$GroupTypetable.Add($obj1) + +#Default Group Pie Chart +$obj1 = [PSCustomObject]@{ + 'Name' = "Groupes par defaut" + 'Count' = $DefaultGroup +} + +$DefaultGrouptable.Add($obj1) + +$obj1 = [PSCustomObject]@{ + 'Name' = "Groupes personnalises" + 'Count' = $CustomGroup +} + +$DefaultGrouptable.Add($obj1) + +#Group Protection Pie Chart +$obj1 = [PSCustomObject]@{ + 'Name' = "Protege" + 'Count' = $GroupsProtected +} + +$GroupProtectionTable.Add($obj1) + +$obj1 = [PSCustomObject]@{ + 'Name' = "Non Protege" + 'Count' = $GroupsNotProtected +} + +$GroupProtectionTable.Add($obj1) + +#Groups with membership vs no membership pie chart +$objmem = [PSCustomObject]@{ + 'Name' = "Avec les membres" + 'Count' = $Groupswithmemebrship +} + +$GroupMembershipTable.Add($objmem) + +$objmem = [PSCustomObject]@{ + 'Name' = "Aucun membre" + 'Count' = $Groupswithnomembership +} + +$GroupMembershipTable.Add($objmem) + +Write-Host "Terminé !" -ForegroundColor White + +Write-Progress -Id 1 -Activity "Analyse : " -completed + +<########################### + Organizational Units +############################> +Write-Host "Analyse sur le rapport sur les unités organisation ............................... " -ForegroundColor Green -NoNewline + +#Get all OUs' +$OUs = Get-ADOrganizationalUnit -Filter * -Properties * +$OUwithLinked = 0 +$OUwithnoLink = 0 +$OUProtected = 0 +$OUNotProtected = 0 +$Compteur = 0 + +Foreach ($OU in $OUs) { + $Compteur++ + Write-Progress -Id 2 -Activity "Analyse : " -Status "Processing $($Compteur) of $($OUs.count)" -CurrentOperation $OU -PercentComplete (($Compteur / $OUs.count) * 100) + $LinkedGPOs = New-Object 'System.Collections.Generic.List[System.Object]' + + If (($OU.linkedgrouppolicyobjects).length -lt 1) { + $LinkedGPOs = "None" + $OUwithnoLink++ + } + Else { + $OUwithLinked++ + $GPOslinks = $OU.linkedgrouppolicyobjects + + Foreach ($GPOlink in $GPOslinks) { + $Split1 = $GPOlink -split "{" | Select-Object -Last 1 + $Split2 = $Split1 -split "}" | Select-Object -First 1 + $LinkedGPOs.Add((Get-GPO -Guid $Split2 -ErrorAction SilentlyContinue).DisplayName) + } + } + + If ($OU.ProtectedFromAccidentalDeletion -eq $True) { + $OUProtected++ + } + Else { + $OUNotProtected++ + } + + $LinkedGPOs = $LinkedGPOs -join ", " + $obj = [PSCustomObject]@{ + "Name" = $OU.Name + "Linked GPOs" = $LinkedGPOs + "Date modification" = $OU.WhenChanged + "Protege contre la suppression" = $OU.ProtectedFromAccidentalDeletion + } + $OUTable.Add($obj) +} + +If (($OUTable).Count -eq 0) { + $OUTable = [PSCustomObject]@{ + Information = "Information : Aucune unite organisationnelle n'a ete trouvee" + } +} + +#OUs with no GPO Linked +$obj1 = [PSCustomObject]@{ + 'Name' = "OU sans GPOs lies" + 'Count' = $OUwithnoLink +} + +$OUGPOTable.Add($obj1) + +$obj2 = [PSCustomObject]@{ + 'Name' = "OU avec GPO's lies" + 'Count' = $OUwithLinked +} + +$OUGPOTable.Add($obj2) + +#OUs Protected Pie Chart +$obj1 = [PSCustomObject]@{ + 'Name' = "Protege" + 'Count' = $OUProtected +} + +$OUProtectionTable.Add($obj1) + +$obj2 = [PSCustomObject]@{ + 'Name' = "Non protege" + 'Count' = $OUNotProtected +} + +$OUProtectionTable.Add($obj2) + +Write-Host "Terminé !" -ForegroundColor White + +Write-Progress -Id 2 -Activity "Analyse : " -completed + +<########################### + USERS +############################> +Write-Host "Analyse sur le rapport des utilisateurs .......................................... " -ForegroundColor Green -NoNewline + +$UserEnabled = 0 +$UserDisabled = 0 +$UserPasswordExpires = 0 +$UserPasswordNeverExpires = 0 +$ProtectedUsers = 0 +$NonProtectedUsers = 0 +$Compteur = 0 + +$UsersWithPasswordsExpiringInUnderAWeek = 0 +$UsersNotLoggedInOver30Days = 0 +$AccountsExpiringSoon = 0 + +Foreach ($User in $AllUsers) { + $Compteur++ + Write-Progress -Id 3 -Activity "Analyse : " -Status "Processing $($Compteur) of $($AllUsers.count)" -CurrentOperation $User -PercentComplete (($Compteur / $AllUsers.count) * 100) + + $AttVar = $User | Select-Object Enabled, PasswordExpired, PasswordLastSet, PasswordNeverExpires, PasswordNotRequired, Name, SamAccountName, EmailAddress, AccountExpirationDate, @{ Name = 'lastlogon'; Expression = { LastLogonConvert $_.lastlogon } }, DistinguishedName + $maxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge + + If ((($AttVar.PasswordNeverExpires) -eq $False) -and (($AttVar.Enabled) -ne $false)) { + #Get Password last set date + $passwordSetDate = ($User | ForEach-Object { $_.PasswordLastSet }) + + If ($null -eq $passwordSetDate) { + $daystoexpire = "Utilisateur ne s'est jamais connecte" + } + Else { + #Check for Fine Grained Passwords + $PasswordPol = (Get-ADUserResultantPasswordPolicy $user) + + If (($PasswordPol) -ne $null) { + $maxPasswordAge = ($PasswordPol).MaxPasswordAge + } + + $expireson = $passwordsetdate + $maxPasswordAge + $today = (Get-Date) + + #Gets the count on how many days until the password expires and stores it in the $daystoexpire var + $daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days + } + } + Else { + $daystoexpire = "N/A" + } + + #Get users that haven't logged on in X amount of days, var is set at start of script + If (($User.Enabled -eq $True) -and ($User.LastLogonDate -lt (Get-Date).AddDays(- $Days)) -and ($User.LastLogonDate -ne $NULL)) { + $obj = [PSCustomObject]@{ + "Name" = $User.Name + "UserPrincipalName" = $User.UserPrincipalName + "Actif" = $AttVar.Enabled + "Protege contre la suppression" = $User.ProtectedFromAccidentalDeletion + "Derniere connexion" = $AttVar.lastlogon + "Mot de passe n'expire jamais" = $AttVar.PasswordNeverExpires + "Jours avant l'expiration du mot de passe" = $daystoexpire + } + $userphaventloggedonrecentlytable.Add($obj) + } + + If (($userphaventloggedonrecentlytable).Count -eq 0) { + $userphaventloggedonrecentlytable = [PSCustomObject]@{ + Information = "Information : Aucun utilisateur n'a ete trouve comme n'ayant pas ete connecte en $Days jours" + } + } + + #Items for protected vs non protected users + If ($User.ProtectedFromAccidentalDeletion -eq $False) { + $NonProtectedUsers++ + } + Else { + $ProtectedUsers++ + } + + #Items for the enabled vs disabled users pie chart + If (($AttVar.PasswordNeverExpires) -ne $false) { + $UserPasswordNeverExpires++ + } + Else { + $UserPasswordExpires++ + } + + #Items for password expiration pie chart + If (($AttVar.Enabled) -ne $false) { + $UserEnabled++ + } + Else { + $UserDisabled++ + } + + $Name = $User.Name + $UPN = $User.UserPrincipalName + $Enabled = $AttVar.Enabled + $EmailAddress = $AttVar.EmailAddress + $AccountExpiration = $AttVar.AccountExpirationDate + $PasswordExpired = $AttVar.PasswordExpired + $PasswordLastSet = $AttVar.PasswordLastSet + $PasswordNeverExpires = $AttVar.PasswordNeverExpires + $daysUntilPWExpire = $daystoexpire + + $obj = [PSCustomObject]@{ + "Name" = $Name + "UserPrincipalName" = $UPN + "Actif" = $Enabled + "Protege contre la suppression" = $User.ProtectedFromAccidentalDeletion + "Derniere connexion" = $LastLogon + "Adresse mail " = $EmailAddress + "Expiration du compte" = $AccountExpiration + "Changer du mot de passe Prochaine" = $PasswordExpired + "Dernier mot de passe defini" = $PasswordLastSet + "Mot de passe n'expire jamais" = $PasswordNeverExpires + "Jours avant l'expiration du mot de passe" = $daystoexpire + } + + $usertable.Add($obj) + + If ($daystoexpire -lt $DaysUntilPWExpireINT) { + $obj = [PSCustomObject]@{ + 'Name' = $Name + "Jours avant l'expiration du mot de passe" = $daystoexpire + } + $PasswordExpireSoonTable.Add($obj) + } +} + +If (($usertable).Count -eq 0) { + $usertable = [PSCustomObject]@{ + Information = "Information : Aucun utilisateur n'a ete trouve" + } +} + +#Data for users enabled vs disabled pie graph +$objULic = [PSCustomObject]@{ + 'Name' = "Actif" + 'Count' = $UserEnabled +} + +$EnabledDisabledUsersTable.Add($objULic) + +$objULic = [PSCustomObject]@{ + 'Name' = "Desactiver" + 'Count' = $UserDisabled +} + +$EnabledDisabledUsersTable.Add($objULic) + +#Data for users password expires pie graph +$objULic = [PSCustomObject]@{ + 'Name' = "Expiration du mot de passe" + 'Count' = $UserPasswordExpires +} + +$PasswordExpirationTable.Add($objULic) + +$objULic = [PSCustomObject]@{ + 'Name' = "Le mot de passe n'expire jamais" + 'Count' = $UserPasswordNeverExpires +} + +$PasswordExpirationTable.Add($objULic) + +#Data for protected users pie graph +$objULic = [PSCustomObject]@{ + 'Name' = "Protege" + 'Count' = $ProtectedUsers +} + +$ProtectedUsersTable.Add($objULic) + +$objULic = [PSCustomObject]@{ + 'Name' = "Non protege" + 'Count' = $NonProtectedUsers +} + +$ProtectedUsersTable.Add($objULic) + +#TOP User table +If (($ExpiringAccountsTable).Count -gt 0) { + $objULic = [PSCustomObject]@{ + "Total des utilisateurs" = $AllUsers.Count + "Utilisateurs dont les mots de passe expirent dans moins de $DaysUntilPWExpireINT jours" = $PasswordExpireSoonTable.Count + "Comptes arrivant a expiration" = $ExpiringAccountsTable.Count + "Utilisateurs non connectes depuis $Days jours" = $userphaventloggedonrecentlytable.Count + } + $TOPUserTable.Add($objULic) +} +Else { + $objULic = [PSCustomObject]@{ + "Total des utilisateurs" = $AllUsers.Count + "Utilisateurs dont les mots de passe expirent dans moins de $DaysUntilPWExpireINT jours" = $PasswordExpireSoonTable.Count + "Comptes arrivant a expiration" = "0" + "Utilisateurs non connectes depuis $Days jours" = $userphaventloggedonrecentlytable.Count + } + $TOPUserTable.Add($objULic) +} + +#Get-ADReplAccount -All -Server $env:ComputerName -NamingContext $(Get-ADDomain | select -ExpandProperty DistinguishedName) | Test-PasswordQuality -IncludeDisabledAccounts + + +Write-Host "Terminé !" -ForegroundColor White + +Write-Progress -Id 3 -Activity "Done" -completed + +<########################### + Group Policy Object +############################> +Write-Host "Rapport sur les GPOs ............................................................. " -ForegroundColor Green -NoNewline + +$Compteur = 0 + +$GPOTable = New-Object 'System.Collections.Generic.List[System.Object]' + +Foreach ($GPO in $GPOs) { + $Compteur++ + Write-Progress -Id 4 -Activity "Analyse : " -Status "Processing $($Compteur) of $($GPOs.count)" -CurrentOperation $GPO -PercentComplete (($Compteur / $GPOs.count) * 100) + + $obj = [PSCustomObject]@{ + "Name" = $GPO.DisplayName + "Status" = $GPO.GpoStatus + "Date modification" = $GPO.ModificationTime + "User Version" = $GPO.UserVersion + "Computer Version" = $GPO.ComputerVersion + } + + $GPOTable.Add($obj) +} +Write-Host "Terminé !" -ForegroundColor White + +Write-Progress -Id 4 -Activity "Done" -completed + +<########################### + Computers +############################> +Write-Host "Rapport sur le travail sur ordinateur ............................................ " -ForegroundColor Green -NoNewline + +$Computers = Get-ADComputer -Filter * -Properties * +$ComputersProtected = 0 +$ComputersNotProtected = 0 +$ComputerEnabled = 0 +$ComputerDisabled = 0 +$Server2022 = 0 +$Server2019 = 0 +$Server2016 = 0 +$Server2012 = 0 +$Server2012R2 = 0 +$Server2008R2 = 0 +$Windows11 = 0 +$Windows10 = 0 +$Windows8 = 0 +$Windows7 = 0 +$Server2012R2 = 0 +$Compteur = 0 + +Foreach ($Computer in $Computers) { + $Compteur++ + Write-Progress -Id 5 -Activity "Analyse : " -Status "Processing $($Compteur) of $($Computers.count)" -CurrentOperation $Computer -PercentComplete (($Compteur / $Computers.count) * 100) + + If ($Computer.ProtectedFromAccidentalDeletion -eq $True) { + $ComputersProtected++ + } + Else { + $ComputersNotProtected++ + } + + If ($Computer.Enabled -eq $True) { + $ComputerEnabled++ + } + Else { + $ComputerDisabled++ + } + + $obj = [PSCustomObject]@{ + "ComputerName" = $Computer.Name + "Actif" = $Computer.Enabled + "Systeme d'exploitation" = $Computer.OperatingSystem + "Description" = $Computer.Description + "Date modification" = $Computer.Modified + "Date dernier mot de passe defini" = $Computer.PasswordLastSet + "Protege contre la suppression" = $Computer.ProtectedFromAccidentalDeletion + } + + $ComputersTable.Add($obj) + + If ($Computer.OperatingSystem -like "*Server 2022*") { + $Server2022++ + } + Elseif ($Computer.OperatingSystem -like "*Server 2019*") { + $Server2019++ + } + Elseif ($Computer.OperatingSystem -like "*Server 2016*") { + $Server2016++ + } + Elseif ($Computer.OperatingSystem -like "*Server 2012 R2*") { + $Server2012R2++ + } + Elseif ($Computer.OperatingSystem -like "*Server 2012*") { + $Server2012++ + } + Elseif ($Computer.OperatingSystem -like "*Server 2008 R2*") { + $Server2008R2++ + } + Elseif ($Computer.OperatingSystem -like "*Windows 11*") { + $Windows11++ + } + Elseif ($Computer.OperatingSystem -like "*Windows 10*") { + $Windows10++ + } + Elseif ($Computer.OperatingSystem -like "*Windows 8*") { + $Windows8++ + } + Elseif ($Computer.OperatingSystem -like "*Windows 7*") { + $Windows7++ + } +} + +If (($ComputersTable).Count -eq 0) { + $ComputersTable = [PSCustomObject]@{ + Information = "Information : Aucun ordinateur n'a ete trouve" + } +} + +#Data for TOP Computers data table +$objULic = [PSCustomObject]@{ + "Total Ordinateurs" = $Computers.Count + "Serveur 2022" = $Server2022 + "Serveur 2019" = $Server2019 + "Serveur 2016" = $Server2016 + "Serveur 2012 R2" = $Server2012R2 + "Serveur 2012" = $Server2012 + "Serveur 2008 R2" = $Server2008R2 + "Windows 11" = $Windows11 + "Windows 10" = $Windows10 + "Windows 8" = $Windows8 + "Windows 7" = $Windows7 +} + +$TOPComputersTable.Add($objULic) + +#Pie chart breaking down OS for computer obj + +$objULic = [PSCustomObject]@{ + "Name" = "Serveur 2022" + "Count" = $Server2022 +} + +$GraphComputerOS.Add($objULic) + +$objULic = [PSCustomObject]@{ + "Name" = "Serveur 2019" + "Count" = $Server2019 +} + +$GraphComputerOS.Add($objULic) + +$objULic = [PSCustomObject]@{ + "Name" = "Serveur 2016" + "Count" = $Server2016 +} + +$GraphComputerOS.Add($objULic) + +$objULic = [PSCustomObject]@{ + "Name" = "Serveur 2012 R2" + "Count" = $Server2012R2 +} + +$GraphComputerOS.Add($objULic) + +$objULic = [PSCustomObject]@{ + "Name" = "Serveur 2012" + "Count" = $Server2012 +} + +$GraphComputerOS.Add($objULic) + +$objULic = [PSCustomObject]@{ + "Name" = "Serveur 2008 R2" + "Count" = $Server2008R2 +} + +$GraphComputerOS.Add($objULic) + +$objULic = [PSCustomObject]@{ + "Name" = "Windows 11" + "Count" = $Windows11 +} + +$objULic = [PSCustomObject]@{ + "Name" = "Windows 10" + "Count" = $Windows10 +} + +$GraphComputerOS.Add($objULic) + +$objULic = [PSCustomObject]@{ + "Name" = "Windows 8" + "Count" = $Windows8 +} + +$GraphComputerOS.Add($objULic) + +$objULic = [PSCustomObject]@{ + "Name" = "Windows 7" + "Count" = $Windows7 +} + +$GraphComputerOS.Add($objULic) + +#Data for protected Computers pie graph +$objULic = [PSCustomObject]@{ + "Name" = "Protege" + "Count" = $ComputerProtected +} + +$ComputerProtectedTable.Add($objULic) + +$objULic = [PSCustomObject]@{ + "Name" = "Non protege" + "Count" = $ComputersNotProtected +} + +$ComputerProtectedTable.Add($objULic) + +#Data for enabled/vs Computers pie graph +$objULic = [PSCustomObject]@{ + "Name" = "Actif" + "Count" = $ComputerEnabled +} + +$ComputersEnabledTable.Add($objULic) + +$objULic = [PSCustomObject]@{ + "Name" = "Desactiver" + "Count" = $ComputerDisabled +} + +$ComputersEnabledTable.Add($objULic) + +Write-Host "Terminé !" -ForegroundColor White + +Write-Progress -Id 5 -Activity "Done" -completed + +$tabarray = @("Tableau de bord", "Groupes", "Unites d Organisation", "Utilisateurs", "Groupe Police Objet", "Ordinateurs") + +Write-Host "Compilation du rapport ........................................................... " -ForegroundColor Green -NoNewline + +##--OU Protection PIE CHART--## +#Basic Properties +$PO12 = Get-HTMLPieChartObject +$PO12.Title = "Unites organisation protegees contre la suppression" +$PO12.Size.Height = 250 +$PO12.Size.width = 250 +$PO12.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PO12.ChartStyle.ColorSchemeName = "ColorScheme3" + +#There are 8 generated schemes, randomly generated at runtime +$PO12.ChartStyle.ColorSchemeName = "Generated3" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PO12.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PO12.DataDefinition.DataNameColumnName = 'Name' +$PO12.DataDefinition.DataValueColumnName = 'Count' + +##--Computer OS Breakdown PIE CHART--## +$PieObjectComputerObjOS = Get-HTMLPieChartObject +$PieObjectComputerObjOS.Title = "Computer Operating Systems" + +#These file exist in the module directoy, There are 4 schemes by default +$PieObjectComputerObjOS.ChartStyle.ColorSchemeName = "ColorScheme3" + +#There are 8 generated schemes, randomly generated at runtime +$PieObjectComputerObjOS.ChartStyle.ColorSchemeName = "Generated3" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PieObjectComputerObjOS.ChartStyle.ColorSchemeName = 'Random' + +##--Computers Protection PIE CHART--## +#Basic Properties +$PieObjectComputersProtected = Get-HTMLPieChartObject +$PieObjectComputersProtected.Title = "Ordinateurs proteges contre la suppression" +$PieObjectComputersProtected.Size.Height = 250 +$PieObjectComputersProtected.Size.width = 250 +$PieObjectComputersProtected.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PieObjectComputersProtected.ChartStyle.ColorSchemeName = "ColorScheme3" + +#There are 8 generated schemes, randomly generated at runtime +$PieObjectComputersProtected.ChartStyle.ColorSchemeName = "Generated3" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PieObjectComputersProtected.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PieObjectComputersProtected.DataDefinition.DataNameColumnName = 'Name' +$PieObjectComputersProtected.DataDefinition.DataValueColumnName = 'Count' + +##--Computers Enabled PIE CHART--## +#Basic Properties +$PieObjectComputersEnabled = Get-HTMLPieChartObject +$PieObjectComputersEnabled.Title = "Ordinateurs actives et desactives" +$PieObjectComputersEnabled.Size.Height = 250 +$PieObjectComputersEnabled.Size.width = 250 +$PieObjectComputersEnabled.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PieObjectComputersEnabled.ChartStyle.ColorSchemeName = "ColorScheme3" + +#There are 8 generated schemes, randomly generated at runtime +$PieObjectComputersEnabled.ChartStyle.ColorSchemeName = "Generated3" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PieObjectComputersEnabled.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PieObjectComputersEnabled.DataDefinition.DataNameColumnName = 'Name' +$PieObjectComputersEnabled.DataDefinition.DataValueColumnName = 'Count' + +##--USERS Protection PIE CHART--## +#Basic Properties +$PieObjectProtectedUsers = Get-HTMLPieChartObject +$PieObjectProtectedUsers.Title = "Utilisateurs proteges contre la suppression" +$PieObjectProtectedUsers.Size.Height = 250 +$PieObjectProtectedUsers.Size.width = 250 +$PieObjectProtectedUsers.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PieObjectProtectedUsers.ChartStyle.ColorSchemeName = "ColorScheme3" + +#There are 8 generated schemes, randomly generated at runtime +$PieObjectProtectedUsers.ChartStyle.ColorSchemeName = "Generated3" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PieObjectProtectedUsers.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PieObjectProtectedUsers.DataDefinition.DataNameColumnName = 'Name' +$PieObjectProtectedUsers.DataDefinition.DataValueColumnName = 'Count' + +#Basic Properties +$PieObjectOUGPOLinks = Get-HTMLPieChartObject +$PieObjectOUGPOLinks.Title = "Liens OU/GPO" +$PieObjectOUGPOLinks.Size.Height = 250 +$PieObjectOUGPOLinks.Size.width = 250 +$PieObjectOUGPOLinks.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PieObjectOUGPOLinks.ChartStyle.ColorSchemeName = "ColorScheme4" + +#There are 8 generated schemes, randomly generated at runtime +$PieObjectOUGPOLinks.ChartStyle.ColorSchemeName = "Generated5" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PieObjectOUGPOLinks.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PieObjectOUGPOLinks.DataDefinition.DataNameColumnName = 'Name' +$PieObjectOUGPOLinks.DataDefinition.DataValueColumnName = 'Count' + +#Basic Properties +$PieObject4 = Get-HTMLPieChartObject +$PieObject4.Title = "Office 365 Unassigned Licenses" +$PieObject4.Size.Height = 250 +$PieObject4.Size.width = 250 +$PieObject4.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PieObject4.ChartStyle.ColorSchemeName = "ColorScheme4" + +#There are 8 generated schemes, randomly generated at runtime +$PieObject4.ChartStyle.ColorSchemeName = "Generated4" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PieObject4.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PieObject4.DataDefinition.DataNameColumnName = 'Name' +$PieObject4.DataDefinition.DataValueColumnName = 'Unassigned Licenses' + +#Basic Properties +$PieObjectGroupType = Get-HTMLPieChartObject +$PieObjectGroupType.Title = "Types de groupes" +$PieObjectGroupType.Size.Height = 250 +$PieObjectGroupType.Size.width = 250 +$PieObjectGroupType.ChartStyle.ChartType = 'doughnut' + +#Pie Chart Groups with members vs no members +$PieObjectGroupMembersType = Get-HTMLPieChartObject +$PieObjectGroupMembersType.Title = "Adhesion au groupe" +$PieObjectGroupMembersType.Size.Height = 250 +$PieObjectGroupMembersType.Size.width = 250 +$PieObjectGroupMembersType.ChartStyle.ChartType = 'doughnut' +$PieObjectGroupMembersType.ChartStyle.ColorSchemeName = "ColorScheme4" +$PieObjectGroupMembersType.ChartStyle.ColorSchemeName = "Generated8" +$PieObjectGroupMembersType.ChartStyle.ColorSchemeName = 'Random' +$PieObjectGroupMembersType.DataDefinition.DataNameColumnName = 'Name' +$PieObjectGroupMembersType.DataDefinition.DataValueColumnName = 'Count' + +#Basic Properties +$PieObjectGroupType2 = Get-HTMLPieChartObject +$PieObjectGroupType2.Title = "Groupes personnalises et groupes par defaut" +$PieObjectGroupType2.Size.Height = 250 +$PieObjectGroupType2.Size.width = 250 +$PieObjectGroupType2.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PieObjectGroupType.ChartStyle.ColorSchemeName = "ColorScheme4" + +#There are 8 generated schemes, randomly generated at runtime +$PieObjectGroupType.ChartStyle.ColorSchemeName = "Generated8" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PieObjectGroupType.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PieObjectGroupType.DataDefinition.DataNameColumnName = 'Name' +$PieObjectGroupType.DataDefinition.DataValueColumnName = 'Count' + +##--Enabled users vs Disabled Users PIE CHART--## +#Basic Properties +$EnabledDisabledUsersPieObject = Get-HTMLPieChartObject +$EnabledDisabledUsersPieObject.Title = "Utilisateurs actives et desactives" +$EnabledDisabledUsersPieObject.Size.Height = 250 +$EnabledDisabledUsersPieObject.Size.width = 250 +$EnabledDisabledUsersPieObject.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$EnabledDisabledUsersPieObject.ChartStyle.ColorSchemeName = "ColorScheme3" + +#There are 8 generated schemes, randomly generated at runtime +$EnabledDisabledUsersPieObject.ChartStyle.ColorSchemeName = "Generated3" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$EnabledDisabledUsersPieObject.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$EnabledDisabledUsersPieObject.DataDefinition.DataNameColumnName = 'Name' +$EnabledDisabledUsersPieObject.DataDefinition.DataValueColumnName = 'Count' + +##--PasswordNeverExpires PIE CHART--## +#Basic Properties +$PWExpiresUsersTable = Get-HTMLPieChartObject +$PWExpiresUsersTable.Title = "Expiration Mot De Passe" +$PWExpiresUsersTable.Size.Height = 250 +$PWExpiresUsersTable.Size.Width = 250 +$PWExpiresUsersTable.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PWExpiresUsersTable.ChartStyle.ColorSchemeName = "ColorScheme3" + +#There are 8 generated schemes, randomly generated at runtime +$PWExpiresUsersTable.ChartStyle.ColorSchemeName = "Generated3" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PWExpiresUsersTable.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PWExpiresUsersTable.DataDefinition.DataNameColumnName = 'Name' +$PWExpiresUsersTable.DataDefinition.DataValueColumnName = 'Count' + +##--Group Protection PIE CHART--## +#Basic Properties +$PieObjectGroupProtection = Get-HTMLPieChartObject +$PieObjectGroupProtection.Title = "Groupes proteges contre la suppression" +$PieObjectGroupProtection.Size.Height = 250 +$PieObjectGroupProtection.Size.width = 250 +$PieObjectGroupProtection.ChartStyle.ChartType = 'doughnut' + +#These file exist in the module directoy, There are 4 schemes by default +$PieObjectGroupProtection.ChartStyle.ColorSchemeName = "ColorScheme3" + +#There are 8 generated schemes, randomly generated at runtime +$PieObjectGroupProtection.ChartStyle.ColorSchemeName = "Generated3" + +#you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme +$PieObjectGroupProtection.ChartStyle.ColorSchemeName = 'Random' + +#Data defintion you can reference any column from name and value from the dataset. +#Name and Count are the default to work with the Group function. +$PieObjectGroupProtection.DataDefinition.DataNameColumnName = 'Name' +$PieObjectGroupProtection.DataDefinition.DataValueColumnName = 'Count' + +#Tableau de bord Report +$FinalReport = New-Object 'System.Collections.Generic.List[System.Object]' +$FinalReport.Add($(Get-HTMLOpenPage -TitleText $ReportTitle -LeftLogoString $CompanyLogo -RightLogoString $CompanyLogo)) +$FinalReport.Add($(Get-HTMLTabHeader -TabNames $tabarray)) +$FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[0] -TabHeading ("Rapport: " + (Get-Date -Format dd-MM-yyyy)))) +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Informations sur l'entreprise")) +$FinalReport.Add($(Get-HTMLContentTable $CompanyInfoTable)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Groupes")) +$FinalReport.Add($(Get-HTMLColumn1of2)) +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Administrateurs de domaines")) +$FinalReport.Add($(Get-HTMLContentDataTable $DomainAdminTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumn2of2)) +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Administrateurs d'entreprise")) +$FinalReport.Add($(Get-HTMLContentDataTable $EnterpriseAdminTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Objets dans les OU par defaut")) +$FinalReport.Add($(Get-HTMLColumn1of2)) +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Ordinateurs")) +$FinalReport.Add($(Get-HTMLContentDataTable $DefaultComputersinDefaultOUTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumn2of2)) +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Utilisateurs")) +$FinalReport.Add($(Get-HTMLContentDataTable $DefaultUsersinDefaultOUTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Objets AD modifies en dernier $ADModNumber jours")) +$FinalReport.Add($(Get-HTMLContentDataTable $ADObjectTable)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Objets en voie d'expiration")) +$FinalReport.Add($(Get-HTMLColumn1of2)) +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Utilisateurs dont les mots de passe expirent dans $DaysUntilPWExpireINT jours")) +$FinalReport.Add($(Get-HTMLContentDataTable $PasswordExpireSoonTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumn2of2)) +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Comptes expirant bientot")) +$FinalReport.Add($(Get-HTMLContentDataTable $ExpiringAccountsTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Comptes")) +$FinalReport.Add($(Get-HTMLColumn1of2)) +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Utilisateurs non connectes depuis $Days jours")) +$FinalReport.Add($(Get-HTMLContentDataTable $userphaventloggedonrecentlytable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumn2of2)) +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Comptes crees en $UserCreatedDays jours")) +$FinalReport.Add($(Get-HTMLContentDataTable $NewCreatedUsersTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Journaux de securite")) +$FinalReport.Add($(Get-HTMLContentDataTable $securityeventtable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "UPN Suffixes")) +$FinalReport.Add($(Get-HTMLContentTable $DomainTable)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLTabContentClose)) + +#Groups Report +$FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[1] -TabHeading ("Rapport: " + (Get-Date -Format dd-MM-yyyy)))) +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Apercu des groupes")) +$FinalReport.Add($(Get-HTMLContentTable $TOPGroupsTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Groupes Active Directory")) +$FinalReport.Add($(Get-HTMLContentDataTable $Table -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumn1of2)) + +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Administrateurs de domaines")) +$FinalReport.Add($(Get-HTMLContentDataTable $DomainAdminTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumn2of2)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Administrateurs d'entreprise")) +$FinalReport.Add($(Get-HTMLContentDataTable $EnterpriseAdminTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Graphiques Groupes Active Directory")) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 1 -ColumnCount 4)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectGroupType -DataSet $GroupTypetable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 2 -ColumnCount 4)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectGroupType2 -DataSet $DefaultGrouptable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 3 -ColumnCount 4)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectGroupMembersType -DataSet $GroupMembershipTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 4 -ColumnCount 4)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectGroupProtection -DataSet $GroupProtectionTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLTabContentClose)) + +#Organizational Unit Report +$FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[2] -TabHeading ("Rapport: " + (Get-Date -Format dd-MM-yyyy)))) +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Unites organisations")) +$FinalReport.Add($(Get-HTMLContentDataTable $OUTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Graphiques unites organisations")) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 1 -ColumnCount 2)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectOUGPOLinks -DataSet $OUGPOTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 2 -ColumnCount 2)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PO12 -DataSet $OUProtectionTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentclose)) +$FinalReport.Add($(Get-HTMLTabContentClose)) + +#Users Report +$FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[3] -TabHeading ("Rapport: " + (Get-Date -Format dd-MM-yyyy)))) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Apercu des utilisateurs")) +$FinalReport.Add($(Get-HTMLContentTable $TOPUserTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Utilisateurs d'Active Directory")) +$FinalReport.Add($(Get-HTMLContentDataTable $UserTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Groupe de mot de passe")) +$FinalReport.Add($(Get-HTMLContentDataTable $$UserPasswordTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Articles en voie d'expiration")) +$FinalReport.Add($(Get-HTMLColumn1of2)) +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Utilisateurs dont les mots de passe expirent dans $DaysUntilPWExpireINT jours")) +$FinalReport.Add($(Get-HTMLContentDataTable $PasswordExpireSoonTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumn2of2)) +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Comptes expirant bientot")) +$FinalReport.Add($(Get-HTMLContentDataTable $ExpiringAccountsTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Comptes")) +$FinalReport.Add($(Get-HTMLColumn1of2)) +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Utilisateurs non connectes depuis $Days jours")) +$FinalReport.Add($(Get-HTMLContentDataTable $userphaventloggedonrecentlytable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumn2of2)) + +$FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Comptes crees en $UserCreatedDays jours")) +$FinalReport.Add($(Get-HTMLContentDataTable $NewCreatedUsersTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Graphiques utilisateurs")) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 1 -ColumnCount 3)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $EnabledDisabledUsersPieObject -DataSet $EnabledDisabledUsersTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 2 -ColumnCount 3)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PWExpiresUsersTable -DataSet $PasswordExpirationTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 3 -ColumnCount 3)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectProtectedUsers -DataSet $ProtectedUsersTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLTabContentClose)) + +#GPO Report +$FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[4] -TabHeading ("Rapport: " + (Get-Date -Format dd-MM-yyyy)))) +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Police Groupe Objet")) +$FinalReport.Add($(Get-HTMLContentDataTable $GPOTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) +$FinalReport.Add($(Get-HTMLTabContentClose)) + +#Computers Report +$FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[5] -TabHeading ("Rapport: " + (Get-Date -Format dd-MM-yyyy)))) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Apercu des ordinateurs")) +$FinalReport.Add($(Get-HTMLContentTable $TOPComputersTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Ordinateurs")) +$FinalReport.Add($(Get-HTMLContentDataTable $ComputersTable -HideFooter)) +$FinalReport.Add($(Get-HTMLContentClose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Graphiques d'ordinateurs")) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 1 -ColumnCount 2)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectComputersProtected -DataSet $ComputerProtectedTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 2 -ColumnCount 2)) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectComputersEnabled -DataSet $ComputersEnabledTable)) +$FinalReport.Add($(Get-HTMLColumnClose)) +$FinalReport.Add($(Get-HTMLContentclose)) + +$FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Repartition des systemes d'exploitation des ordinateurs")) +$FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectComputerObjOS -DataSet $GraphComputerOS)) +$FinalReport.Add($(Get-HTMLContentclose)) + +$FinalReport.Add($(Get-HTMLTabContentClose)) +$FinalReport.Add($(Get-HTMLClosePage)) + +$ReportName = ("$Day-$Month-$Year-$Hour-$Minute-AD Report") + +#Save-HTMLReport -ReportContent $FinalReport -ShowReport -ReportName $ReportName -ReportPath $ReportSavePath +Add-Content $ReportSavePath$ReportName".html" $FinalReport + +Write-Host "Terminé !" -ForegroundColor White + +#---------------------------------------------------------[Fin Du Script]---------------------------------------------------------- + +Stop-Transcript \ No newline at end of file diff --git a/Get-AdComputerInventory.ps1 b/Get-AdComputerInventory.ps1 new file mode 100644 index 0000000..d4bb7e5 --- /dev/null +++ b/Get-AdComputerInventory.ps1 @@ -0,0 +1,50 @@ +$Computers = Get-ADComputer -filter * | Select-Object -ExpandProperty Name +# Get-ADComputer -Filter { OperatingSystem -NotLike '*Server*' } -Properties OperatingSystem + +Foreach ($computer in $computers) { + + if (!(Test-Connection -Cn $computer -BufferSize 16 -Count 1 -ea 0 -quiet)) { + write-host "cannot reach $computer offline" -f red + } + else { + $outtbl = @() + Try { + $sr = Get-WmiObject win32_bios -ComputerName $Computer -ErrorAction Stop + $Xr = Get-WmiObject –class Win32_processor -ComputerName $computer -ErrorAction Stop + $ld = get-adcomputer $computer -properties Name, Lastlogondate, operatingsystem, ipv4Address, enabled, description, DistinguishedName -ErrorAction Stop + $r = "{0} GB" -f ((Get-WmiObject Win32_PhysicalMemory -ComputerName $computer | Measure-Object Capacity -Sum).Sum / 1GB) + $x = gwmi win32_computersystem -ComputerName $computer | Select-Object @{Name = "Type"; Expression = { if (($_.pcsystemtype -eq '2') ) { + 'Laptop' + } + Else { + 'Desktop Or Other something else' + } + } + }, Manufacturer, @{Name = "Model"; Expression = { if (($_.model -eq "$null") ) { 'Virtual' } Else { $_.model } } }, username -ErrorAction Stop + $t = New-Object PSObject -Property @{ + serialnumber = $sr.serialnumber + computername = $ld.name + Ipaddress = $ld.ipv4Address + Enabled = $ld.Enabled + Description = $ld.description + Ou = $ld.DistinguishedName.split(',')[1].split('=')[1] + Type = $x.type + Manufacturer = $x.Manufacturer + Model = $x.Model + Ram = $R + ProcessorName = ($xr.name | Out-String).Trim() + NumberOfCores = ($xr.NumberOfCores | Out-String).Trim() + NumberOfLogicalProcessors = ($xr.NumberOfLogicalProcessors | Out-String).Trim() + Addresswidth = ($xr.Addresswidth | Out-String).Trim() + Operatingsystem = $ld.operatingsystem + Lastlogondate = $ld.lastlogondate + LoggedinUser = $x.username + } + $outtbl += $t + } + catch [Exception] { + "Error communicating with $computer, skipping to next" + } + $outtbl | Select-Object Computername, enabled, description, ipAddress, Ou, Type, Serialnumber, Manufacturer, Model, Ram, ProcessorName, NumberOfCores, NumberOfLogicalProcessors, Addresswidth, Operatingsystem, loggedinuser, Lastlogondate + } +} \ No newline at end of file diff --git a/creation-automatique.ps1 b/creation-automatique.ps1 new file mode 100644 index 0000000..8bfa764 --- /dev/null +++ b/creation-automatique.ps1 @@ -0,0 +1,409 @@ +# Fonction pour les requetes SQL +Function QuerySQLServer([string]$DBServer, [string]$DBName, [string]$Query) { + Try { + $ErrorActionPreference = "Stop" + + $resultsDataTable = New-Object System.Data.DataTable + + $cn = new-object System.Data.SqlClient.SqlConnection("Data Source=$DBServer;Integrated Security=SSPI;Initial Catalog=$DBName") + $cn.open() + + $cmd = new-object "System.Data.SqlClient.SqlCommand" ($Query , $cn) + $reader = $cmd.ExecuteReader() + + $resultsDataTable.Load($reader) + + $cn.Close() + + return $resultsDataTable + } + Catch { + write-host $_.Exception.Message + $_.Exception.Message >> "d:\tmp\error.log" + } + Finally { + $ErrorActionPreference = "Continue" + } +} + +# Fonction pour les requetes dans GLPI +Function QueryGLPI([string]$Titre, [string]$Message, [string]$Categorie) { + Write-host $Titre + Write-host $Message + Write-host $Categorie + + $UtilisateurGLPI = Get-GlpiToolsUsers -UserName helpdesk + + $Ticket = New-GlpiToolsTicket -Name $Titre -Content $Message -Type Request -itilcategories_id $Categorie -Priority Medium -requester_id $UtilisateurGLPI.ID + + Update-GlpiToolsTicket -ticket_id $Ticket.id -requester_id $UtilisateurGLPI.ID -technician_id '12' +} + +cls + +$ListeException = $null +$ListeVide = $null +$FichierException = "D:\tmp\Exception.txt" +$FichierVide = "D:\tmp\vide.txt" +$percentCompleteA = $null +$percentCompleteB = $null +$CounterA = $null +$CounterB = $null +$EtatUtilisateur = $null + +$DateDesactivation = Get-Date -Format "dd/MM/yyyy" +$DateExpiration = (Get-Date $DateDesactivation).AddDays(-1) +$DateDelete = (Get-Date $DateDesactivation).AddDays(-30) + +$DateTmp = (Get-Date).AddDays(-1) +$DateCreation = Get-Date $DateTmp -Format "yyyy-dd-MM" + +Start-Transcript -path "D:\tmp\MyTranscript-$DateCreation.txt" + +$OuPath = "OU=Utilisateurs,DC=fr,DC=dgs,DC=group" +$ListeUserAD = Get-ADUser -Filter * -SearchBase $OuPath -Properties cn,description,sAMAccountName + +## Desactivation ou Update de compte + +Foreach ($UserAD in $ListeUserAD) { + # Barre de progression + $percentCompleteA = $(($CounterA / $ListeUserAD.Count) * 100 ) + + $ProgressA = @{ + Activity = "Getting folder information for '$($UserAD.Name)'." + Status = "Processing $CounterA of $($ListeUserAD.Count)" + PercentComplete = $([math]::Round($percentCompleteA, 2)) + } + + Write-Progress @ProgressA -Id 1 + + # recherche inforamtiopn 1 utilisateur + $InfoUser = Get-ADUser -identity $UserAD.sAMAccountName -properties 'msDS-cloudExtensionAttribute1','msDS-cloudExtensionAttribute2',mail,employeeID,EmployeeNumber,EmployeeType,Title,Initials + + $C = $UserAD.C + $City = $UserAD.City + $Cn = $UserAD.Cn + $Company = $UserAD.Company + $department = $UserAD.Department + $displayName = $UserAD.DisplayName + $EmailAddress = $UserAD.EmailAddress + $Enable = $UserAD.Enabled + $GivenName = $UserAD.GivenName + $Name = $UserAD.Name + $Office = $UserAD.Office + $Organization = $UserAD.Organization + $PostalCode = $UserAD.PostalCode + $sn = $UserAD.Sn + $Surname = $UserAD.Surname + + $ExtensionAttribute1 = $InfoUser.'msDS-cloudExtensionAttribute1' + $ExtensionAttribute2 = $InfoUser.'msDS-cloudExtensionAttribute2' + $Mail = $InfoUser.Mail + $EmployeeID = $InfoUser.employeeID + $EmployeeNumber = $InfoUser.EmployeeNumber + $EmployeeType = $InfoUser.EmployeeType + $Title = $InfoUser.Title + $Initials = $InfoUser.Initials + + # Est-ce qu'il est actif + If ($Enable -eq "True") { + # Est-ce qu'il est interne + If($EmployeeType -eq "Interne") { + # Est-ce qu'il a un ID + If ($EmployeeID) { + # Si l'employeeID est bien présent + $EtatUtilisateurD = QuerySQLServer "SWDHBBDDP01.fr.dgs.group" "dhb_prd" "SELECT NOM,PRN,NOM_PAT,LIB_EMP,ADR_EML,MTR,NUM_ALC,COD_SEX,FLG_AGT,DAT_SRT FROM [dhb_prd].[dhbref].[TAB_RH_SAL] WHERE MTR = '$EmployeeID' And DAT_SRT IS NOT NULL" + $EtatUtilisateurU = QuerySQLServer "SWDHBBDDP01.fr.dgs.group" "dhb_prd" "SELECT NOM,PRN,NOM_PAT,LIB_EMP,ADR_EML,MTR,NUM_ALC,COD_SEX,FLG_AGT,DAT_SRT FROM [dhb_prd].[dhbref].[TAB_RH_SAL] WHERE MTR = '$EmployeeID'" + + # Desactivation du compte ? + If ($EtatUtilisateurD) { + If ($DateExpiration -gt $EtatUtilisateurD.DAT_SRT) { + + Get-ADUser -Identity $UserAD.sAMAccountName | Move-ADObject -TargetPath "OU=_A_SUPPRIMER,OU=Utilisateurs,DC=fr,DC=dgs,DC=group" + Set-ADAccountExpiration -Identity $UserAD.sAMAccountName -DateTime $dateExpiration + Set-ADUser -Identity $Utilisateur -Clear msDS-cloudExtensionAttribute2 + Set-ADUser -Identity $UserAD.sAMAccountName -Add @{'msDS-cloudExtensionAttribute2' = "$DateExpiration"} + Disable-ADAccount -Identity $UserAD.sAMAccountName + + $TitreA = "Désactivation du compte Active Directory : $UserAD.sAMAccountName " + + $MessageA = "Bonjour, `r`n `r`n" ` + +"Nous venons de désactiver le compte de : $DisplayName `r`n `r`n" ` + +"Prénom : $GivenName `r`n" ` + +"Nom : $Surname `r`n" ` + +"Mail : $Mail `r`n" ` + +"Matricule : $EmployeeID `r`n" ` + +"Fonction : $Title `r`n" ` + +"`r`n" ` + +"Conformément à la politique entreprise le compte restera en état désactivé pendant 30 jours avant d'être supprimé `r`n" ` + +"La suppression du compte GMAIL se fait également en automatique." + + QueryGLPI $TitreA $MessageA "213" + } + } + + # Mise en place de la civilité + If ($EtatUtilisateurU) { + If (($Initials -ne "Mr") -And ($EtatUtilisateurU.COD_SEX -eq "H")) { + + Set-ADUser -Identity $UserAD.sAMAccountName -Clear Initials + Set-ADUser -Identity $UserAD.sAMAccountName -Initials "Mr" + + Write-Host " - Update civilité - Mr" + } + ElseIf (($Initials -ne "Mme") -And ($EtatUtilisateurU.COD_SEX -eq "F")) { + + Set-ADUser -Identity $UserAD.sAMAccountName -Clear Initials + Set-ADUser -Identity $UserAD.sAMAccountName -Initials "Mme" + + Write-Host " - Update civilité - Mme" + } + Else { + # Write-Host " - Pas de modification" + } + } + + # Mise en place du Employee Number + If ($EmployeeNumber -ne $EtatUtilisateurU.NUM_ALC) { + If ($EmployeeID.substring(0, 1) -eq 0 ) { + $tmp = ($EtatUtilisateurU.NUM_ALC).Remove(0,1) + If (!($EmployeeNumber -eq $tmp)) { + Write-host " - 2erreur : "$EtatUtilisateurU.MTR" > $EmployeeID | "$EtatUtilisateurU.NUM_ALC" > $EmployeeNumber" + } + } + Else { + Write-host " - erreur : "$EtatUtilisateurU.MTR" > $EmployeeID | "$EtatUtilisateurU.NUM_ALC" > $EmployeeNumber" + } + } + + # Controle du status + If (($ExtensionAttribute1 -eq $null) -Or ($ExtensionAttribute1 -ne $EmployeeType)) { + Set-ADUser -Identity $UserAD.sAMAccountName -Add @{'msDS-cloudExtensionAttribute1' = $EmployeeType} + } + } + Else { + # Si l'employé ID n'est pas présent + $EtatUtilisateurID = QuerySQLServer "SWDHBBDDP01.fr.dgs.group" "dhb_prd" "SELECT NOM,PRN,NOM_PAT,LIB_EMP,ADR_EML,MTR,NUM_ALC,COD_SEX,FLG_AGT,DAT_SRT FROM [dhb_prd].[dhbref].[TAB_RH_SAL] WHERE NOM = '$Surname' And PRN ='$GivenName' And DAT_SRT IS NULL" + + If ($EtatUtilisateurID) { + + Set-ADUser -Identity $UserAD.sAMAccountName -EmployeeID $EtatUtilisateurID.MTR + + Write-Host " - Mise en place de employee ID" + } + } + } + Else { + # Passage d'un externe en interne + } + } + $EtatUtilisateurD = $null + $EtatUtilisateurU = $null + + $CounterA++ +} + +## Suppression des comptes de plus 1 mois + +$OuPathDelete = "OU=_A_SUPPRIMER,OU=Utilisateurs,DC=fr,DC=dgs,DC=group" +$ListeUserADDelete = Get-ADUser -Filter * -SearchBase $OuPathDelete -Properties cn,description,sAMAccountName + +Foreach ($UserADDelete in $ListeUserADDelete) { + # Barre de progression + $percentCompleteB = $(($CounterB / $ListeUserADDelete.Count) * 100 ) + + $ProgressB = @{ + Activity = "Getting folder information for '$($UserADDelete.Name)'." + Status = "Processing $CounterB of $($ListeUserADDelete.Count)" + PercentComplete = $([math]::Round($percentCompleteB, 2)) + } + + Write-Progress @ProgressB -Id 1 + + $InfoUserDelete = Get-ADUser -identity $UserADDelete.sAMAccountName -properties 'msDS-cloudExtensionAttribute2' + + $ExtensionAttributeDelete2 = $InfoUserDelete.'msDS-cloudExtensionAttribute2' + + If ($Enable -eq $False) { + If ($DateDelete -gt $ExtensionAttributeDelete2) { + Remove-ADUser -Identity $UserADDelete.sAMAccountName + + $TitreB = "Suppression du compte Active Directory : $UserAD.sAMAccountName " + + $MessageB = "Bonjour, `r`n `r`n" ` + +"Nous venons de supprimer le compte de : $DisplayName `r`n `r`n" ` + +"Prénom : $GivenName `r`n" ` + +"Nom : $Surname `r`n" ` + +"Mail : $Mail `r`n" ` + +"Matricule : $EmployeeID `r`n" ` + +"Fonction : $Title `r`n" ` + +"`r`n" ` + +"Conformément à la politique entreprise le compte est resté en état désactivé pendant 30 jours `r`n" ` + +"La suppression du compte GMAIL se fait également en automatique." + + QueryGLPI $TitreB $MessageB "213" + } + } + $EtatUtilisateur = $null + + $CounterB++ +} + +## Creation compte + +$ListeNouveau = QuerySQLServer "SWDHBBDDP01.fr.dgs.group" "dhb_prd" "SELECT NOM,PRN,NOM_PAT,LIB_EMP,ADR_EML,MTR,NUM_ALC,COD_SEX,FLG_AGT,DAT_SRT,NUM_MAG_AGT FROM [dhb_prd].[dhbref].[TAB_RH_SAL] WHERE DTH_CRE >= '$DateCreation' ORDER BY DTH_CRE DESC" +$ListeNouveau | Format-Table +Pause +If ($ListeNouveau) { + Foreach ($NouveauUtilisateur in $ListeNouveau) { + + $InfoUserNew = Get-ADUser -Filter * | Where-Object {$_.GivenName -like $NouveauUtilisateur.PRN -and $_.Surname -like $NouveauUtilisateur.NOM} + + If ($InfoUserNew) { + $InfoUserNewA = Get-ADUser -identity $InfoUserNew.sAMAccountName -properties 'msDS-cloudExtensionAttribute1','msDS-cloudExtensionAttribute2',mail,employeeID,EmployeeNumber,EmployeeType,Title,Initials + } + + $C = $InfoUserNew.c + $City = $InfoUserNew.City + $Cn = $InfoUserNew.cn + $Company = $InfoUserNew.company + $department = $InfoUserNew.department + $DisplayName = $InfoUserNew.displayName + $EmailAddress = $InfoUserNew.EmailAddress + $Enable = $InfoUserNew.Enabled + $GivenName = $InfoUserNew.GivenName + $Name = $InfoUserNew.Name + $Office = $InfoUserNew.Office + $Organization = $InfoUserNew.Organization + $PostalCode = $InfoUserNew.PostalCode + $sn = $InfoUserNew.sn + $Surname = $InfoUserNew.Surname + + $ExtensionAttribute1 = $InfoUserNewA.'msDS-cloudExtensionAttribute1' + $ExtensionAttribute2 = $InfoUserNewA.'msDS-cloudExtensionAttribute2' + $Mail = $InfoUserNewA.Mail + $EmployeeID = $InfoUserNewA.employeeID + $EmployeeNumber = $InfoUserNewA.EmployeeNumber + $EmployeeType = $InfoUserNewA.EmployeeType + $Title = $InfoUserNewA.Title + $Initials = $InfoUserNewA.Initials + + If ($NouveauUtilisateur.MTR -eq $EmployeeID) { + Write-host "Existe deja" + } + Else { + Write-Host "A creer" + + $Surnametmp = ($NouveauUtilisateur.NOM).ToLower() + $GivenNametmp = ($NouveauUtilisateur.PRN).ToLower() + $Titletmp = ($NouveauUtilisateur.LIB_EMP).ToLower() + $Initialstmp = $NouveauUtilisateur.COD_SEX + $CodeMagtmp = $NouveauUtilisateur.NUM_MAG_AGT + + $SurnameNew = (Get-Culture).TextInfo.ToTitleCase($Surnametmp) + $GivenNameNew = (Get-Culture).TextInfo.ToTitleCase($GivenNametmp) + $TitleNew = (Get-Culture).TextInfo.ToTitleCase($Titletmp) + $EmployeeIDNew = $NouveauUtilisateur.MTR + + If ($NouveauUtilisateur.NOM_PAT) { + $SurnamePattmp = ($NouveauUtilisateur.NOM_PAT).ToLower() + $SurnamePatNew = (Get-Culture).TextInfo.ToTitleCase($SurnamePattmp) + } + + $NameNew = $GivenNameNew+" "+$SurnameNew + $DisplayNameNew = $GivenNameNew+" "+$SurnameNew+" "+$SurnamePatNew + $SamAccountNameNew = (("$GivenNameNew.$SurnameNew").Replace(' ','').Replace('é','e').Replace('è','e').Replace('ç','c').Replace('ï','i').Replace('î','i').Replace('ë','e').Replace('ö','o').Replace('ô','o')).ToLower() + $UserPrincipalNameNew = (("$GivenNameNew.$SurnameNew@fr.dgs.group").Replace(' ','').Replace('é','e').Replace('è','e').Replace('ç','c').Replace('ï','i').Replace('î','i').Replace('ë','e').Replace('ö','o').Replace('ô','o')).ToLower() + $MailNew = (("$GivenNameNew.$SurnameNew@saint-maclou.com").Replace(' ','').Replace('é','e').Replace('è','e').Replace('ç','c').Replace('ï','i').Replace('î','i').Replace('ë','e').Replace('ö','o').Replace('ô','o')).ToLower() + $Password = ([System.Guid]::NewGuid()).ToString() + + + If ($SamAccountNameNew.Length -gt 20) { + $tmp = ($SamAccountNameNew).substring(0, 20) + $SamAccountNameNew = $tmp + } + + Write-host $NameNew + Write-host $DisplayNameNew + Write-host $SamAccountNameNew + Write-host $UserPrincipalNameNew + Write-host $MailNew + Write-host $Password + Write-host $EmployeeIDNew + Write-host $TitleNew + + New-ADUser -Name "$NameNew" -DisplayName "$DisplayNameNew" -GivenName "$GivenNameNew" -Surname "$SurnameNew" -SamAccountName "$SamAccountNameNew" -UserPrincipalName "$UserPrincipalNameNew" -Path "OU=_ARRIVER,OU=Utilisateurs,DC=fr,DC=dgs,DC=group" -AccountPassword (ConvertTo-SecureString "$Password" -AsPlainText -force) -Enabled $true -EmailAddress $MailNew + + sleep 10 + + Set-ADUser -Identity $SamAccountNameNew -replace @{c="FR";co="France";countrycode=250} + Set-ADUser -Identity $SamAccountNameNew -Add @{'msDS-cloudExtensionAttribute1' = "Interne"} + Set-ADUser -Identity $SamAccountNameNew -Add @{'EmployeeType' = "Interne"} + Set-ADUser -Identity $SamAccountNameNew -Add @{'EmployeeID' = "$EmployeeIDNew"} + Set-ADUser -Identity $SamAccountNameNew -Title "$TitleNew" + Set-ADUser -Identity $SamAccountNameNew -Description "A remplir par le Helpdesk" + Set-ADUser -Identity $SamAccountNameNew -City "A remplir par le Helpdesk" + + If ($Initialstmp -eq "H") { + Set-ADUser -Identity $SamAccountNameNew -Initials "Mr" + Write-Host "Update civilite - Mr" + } + ElseIf ($Initialstmp -eq "F") { + Set-ADUser -Identity $SamAccountNameNew -Initials "Mme" + Write-Host "Update civilite - Mme" + } + Else { + + } + + $TitreC = "Creation du compte de : $DisplayNameNew " + + $MessageC = "Bonjour, `r`n `r`n" ` + +"la creation de compte automatique a cree le compte de : $DisplayNameNew `r`n `r`n" ` + +"Prenom : $GivenNameNew `r`n" ` + +"Nom : $SurnameNew `r`n" ` + +"Mail : $MailNew `r`n" ` + +"Password temporaire : $Password `r`n" ` + +"Matricule : $EmployeeIDNew `r`n" ` + +"Fonction : $TitleNew `r`n" + + QueryGLPI $TitreC $MessageC "104" + + $C = $Null + $City = $Null + $Cn = $Null + $Company = $Null + $department = $Null + $DisplayName = $Null + $EmailAddress = $Null + $Enable = $Null + $GivenName = $Null + $Name = $Null + $Office = $Null + $Organization = $Null + $PostalCode = $Null + $sn = $Null + $Surname = $Null + $ExtensionAttribute1 = $Null + $ExtensionAttribute2 = $Null + $Mail = $Null + $EmployeeID = $Null + $EmployeeNumber = $Null + $EmployeeType = $Null + $Title = $Null + $Initials = $Null + $Surnametmp = $Null + $GivenNametmp = $Null + $Titletmp = $Null + $Initialstmp = $Null + $CodeMagtmp = $Null + $SurnameNew = $Null + $SurnamePatNew = $Null + $GivenNameNew = $Null + $TitleNew = $Null + $EmployeeIDNew = $Null + } + } +} + +Stop-Transcript