├── LICENSE ├── PSHTML-AD.ps1 └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Brad Wyatt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PSHTML-AD.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Generate graphed report for all Active Directory objects. 4 | 5 | .DESCRIPTION 6 | Generate graphed report for all Active Directory objects. 7 | 8 | .PARAMETER CompanyLogo 9 | Enter URL or UNC path to your desired Company Logo for generated report. 10 | 11 | -CompanyLogo "\\Server01\Admin\Files\CompanyLogo.png" 12 | 13 | .PARAMETER RightLogo 14 | Enter URL or UNC path to your desired right-side logo for generated report. 15 | 16 | -RightLogo "https://www.psmpartners.com/wp-content/uploads/2017/10/porcaro-stolarek-mete.png" 17 | 18 | .PARAMETER ReportTitle 19 | Enter desired title for generated report. 20 | 21 | -ReportTitle "Active Directory Report" 22 | 23 | .PARAMETER Days 24 | Users that have not logged in [X] amount of days or more. 25 | 26 | -Days "30" 27 | 28 | .PARAMETER UserCreatedDays 29 | Users that have been created within [X] amount of days. 30 | 31 | -UserCreatedDays "7" 32 | 33 | .PARAMETER DaysUntilPWExpireINT 34 | Users password expires within [X] amount of days 35 | 36 | -DaysUntilPWExpireINT "7" 37 | 38 | .PARAMETER ADModNumber 39 | Active Directory Objects that have been modified within [X] amount of days. 40 | 41 | -ADModNumber "3" 42 | 43 | .NOTES 44 | Version: 1.0.3 45 | Author: Bradley Wyatt 46 | Date: 12/4/2018 47 | Modified: JBear 12/5/2018 48 | Bradley Wyatt 12/8/2018 49 | jporgand 12/6/2018 50 | #> 51 | 52 | param ( 53 | 54 | #Company logo that will be displayed on the left, can be URL or UNC 55 | [Parameter(ValueFromPipeline = $true, HelpMessage = "Enter URL or UNC path to Company Logo")] 56 | [String]$CompanyLogo = "", 57 | #Logo that will be on the right side, UNC or URL 58 | 59 | [Parameter(ValueFromPipeline = $true, HelpMessage = "Enter URL or UNC path for Side Logo")] 60 | [String]$RightLogo = "https://www.psmpartners.com/wp-content/uploads/2017/10/porcaro-stolarek-mete.png", 61 | #Title of generated report 62 | 63 | [Parameter(ValueFromPipeline = $true, HelpMessage = "Enter desired title for report")] 64 | [String]$ReportTitle = "Active Directory Report", 65 | #Location the report will be saved to 66 | 67 | [Parameter(ValueFromPipeline = $true, HelpMessage = "Enter desired directory path to save; Default: C:\Automation\")] 68 | [String]$ReportSavePath = "C:\Automation\", 69 | #Find users that have not logged in X Amount of days, this sets the days 70 | 71 | [Parameter(ValueFromPipeline = $true, HelpMessage = "Users that have not logged on in more than [X] days. amount of days; Default: 30")] 72 | $Days = 30, 73 | #Get users who have been created in X amount of days and less 74 | 75 | [Parameter(ValueFromPipeline = $true, HelpMessage = "Users that have been created within [X] amount of days; Default: 7")] 76 | $UserCreatedDays = 7, 77 | #Get users whos passwords expire in less than X amount of days 78 | 79 | [Parameter(ValueFromPipeline = $true, HelpMessage = "Users password expires within [X] amount of days; Default: 7")] 80 | $DaysUntilPWExpireINT = 7, 81 | #Get AD Objects that have been modified in X days and newer 82 | 83 | [Parameter(ValueFromPipeline = $true, HelpMessage = "AD Objects that have been modified within [X] amount of days; Default: 3")] 84 | $ADModNumber = 3 85 | 86 | #CSS template located C:\Program Files\WindowsPowerShell\Modules\ReportHTML\1.4.1.1\ 87 | #Default template is orange and named "Sample" 88 | ) 89 | 90 | Write-Host "Gathering Report Customization..." -ForegroundColor White 91 | Write-Host "__________________________________" -ForegroundColor White 92 | (Write-Host -NoNewline "Company Logo (left): " -ForegroundColor Yellow), (Write-Host $CompanyLogo -ForegroundColor White) 93 | (Write-Host -NoNewline "Company Logo (right): " -ForegroundColor Yellow), (Write-Host $RightLogo -ForegroundColor White) 94 | (Write-Host -NoNewline "Report Title: " -ForegroundColor Yellow), (Write-Host $ReportTitle -ForegroundColor White) 95 | (Write-Host -NoNewline "Report Save Path: " -ForegroundColor Yellow), (Write-Host $ReportSavePath -ForegroundColor White) 96 | (Write-Host -NoNewline "Amount of Days from Last User Logon Report: " -ForegroundColor Yellow), (Write-Host $Days -ForegroundColor White) 97 | (Write-Host -NoNewline "Amount of Days for New User Creation Report: " -ForegroundColor Yellow), (Write-Host $UserCreatedDays -ForegroundColor White) 98 | (Write-Host -NoNewline "Amount of Days for User Password Expiration Report: " -ForegroundColor Yellow), (Write-Host $DaysUntilPWExpireINT -ForegroundColor White) 99 | (Write-Host -NoNewline "Amount of Days for Newly Modified AD Objects Report: " -ForegroundColor Yellow), (Write-Host $ADModNumber -ForegroundColor White) 100 | Write-Host "__________________________________" -ForegroundColor White 101 | 102 | function LastLogonConvert ($ftDate) 103 | { 104 | 105 | $Date = [DateTime]::FromFileTime($ftDate) 106 | 107 | if ($Date -lt (Get-Date '1/1/1900') -or $date -eq 0 -or $date -eq $null) 108 | { 109 | 110 | "Never" 111 | } 112 | 113 | else 114 | { 115 | 116 | $Date 117 | } 118 | 119 | } #End function LastLogonConvert 120 | 121 | #Check for ReportHTML Module 122 | $Mod = Get-Module -ListAvailable -Name "ReportHTML" 123 | 124 | If ($null -eq $Mod) 125 | { 126 | 127 | Write-Host "ReportHTML Module is not present, attempting to install it" 128 | 129 | Install-Module -Name ReportHTML -Force 130 | Import-Module ReportHTML -ErrorAction SilentlyContinue 131 | } 132 | 133 | #Array of default Security Groups 134 | $DefaultSGs = @( 135 | 136 | "Access Control Assistance Operators" 137 | "Account Operators" 138 | "Administrators" 139 | "Allowed RODC Password Replication Group" 140 | "Backup Operators" 141 | "Certificate Service DCOM Access" 142 | "Cert Publishers" 143 | "Cloneable Domain Controllers" 144 | "Cryptographic Operators" 145 | "Denied RODC Password Replication Group" 146 | "Distributed COM Users" 147 | "DnsUpdateProxy" 148 | "DnsAdmins" 149 | "Domain Admins" 150 | "Domain Computers" 151 | "Domain Controllers" 152 | "Domain Guests" 153 | "Domain Users" 154 | "Enterprise Admins" 155 | "Enterprise Key Admins" 156 | "Enterprise Read-only Domain Controllers" 157 | "Event Log Readers" 158 | "Group Policy Creator Owners" 159 | "Guests" 160 | "Hyper-V Administrators" 161 | "IIS_IUSRS" 162 | "Incoming Forest Trust Builders" 163 | "Key Admins" 164 | "Network Configuration Operators" 165 | "Performance Log Users" 166 | "Performance Monitor Users" 167 | "Print Operators" 168 | "Pre-Windows 2000 Compatible Access" 169 | "Protected Users" 170 | "RAS and IAS Servers" 171 | "RDS Endpoint Servers" 172 | "RDS Management Servers" 173 | "RDS Remote Access Servers" 174 | "Read-only Domain Controllers" 175 | "Remote Desktop Users" 176 | "Remote Management Users" 177 | "Replicator" 178 | "Schema Admins" 179 | "Server Operators" 180 | "Storage Replica Administrators" 181 | "System Managed Accounts Group" 182 | "Terminal Server License Servers" 183 | "Users" 184 | "Windows Authorization Access Group" 185 | "WinRMRemoteWMIUsers" 186 | ) 187 | 188 | $Table = New-Object 'System.Collections.Generic.List[System.Object]' 189 | $OUTable = New-Object 'System.Collections.Generic.List[System.Object]' 190 | $UserTable = New-Object 'System.Collections.Generic.List[System.Object]' 191 | $GroupTypetable = New-Object 'System.Collections.Generic.List[System.Object]' 192 | $DefaultGrouptable = New-Object 'System.Collections.Generic.List[System.Object]' 193 | $EnabledDisabledUsersTable = New-Object 'System.Collections.Generic.List[System.Object]' 194 | $DomainAdminTable = New-Object 'System.Collections.Generic.List[System.Object]' 195 | $ExpiringAccountsTable = New-Object 'System.Collections.Generic.List[System.Object]' 196 | $CompanyInfoTable = New-Object 'System.Collections.Generic.List[System.Object]' 197 | $securityeventtable = New-Object 'System.Collections.Generic.List[System.Object]' 198 | $DomainTable = New-Object 'System.Collections.Generic.List[System.Object]' 199 | $OUGPOTable = New-Object 'System.Collections.Generic.List[System.Object]' 200 | $GroupMembershipTable = New-Object 'System.Collections.Generic.List[System.Object]' 201 | $PasswordExpirationTable = New-Object 'System.Collections.Generic.List[System.Object]' 202 | $PasswordExpireSoonTable = New-Object 'System.Collections.Generic.List[System.Object]' 203 | $userphaventloggedonrecentlytable = New-Object 'System.Collections.Generic.List[System.Object]' 204 | $EnterpriseAdminTable = New-Object 'System.Collections.Generic.List[System.Object]' 205 | $NewCreatedUsersTable = New-Object 'System.Collections.Generic.List[System.Object]' 206 | $GroupProtectionTable = New-Object 'System.Collections.Generic.List[System.Object]' 207 | $OUProtectionTable = New-Object 'System.Collections.Generic.List[System.Object]' 208 | $GPOTable = New-Object 'System.Collections.Generic.List[System.Object]' 209 | $ADObjectTable = New-Object 'System.Collections.Generic.List[System.Object]' 210 | $ProtectedUsersTable = New-Object 'System.Collections.Generic.List[System.Object]' 211 | $ComputersTable = New-Object 'System.Collections.Generic.List[System.Object]' 212 | $ComputerProtectedTable = New-Object 'System.Collections.Generic.List[System.Object]' 213 | $ComputersEnabledTable = New-Object 'System.Collections.Generic.List[System.Object]' 214 | $DefaultComputersinDefaultOUTable = New-Object 'System.Collections.Generic.List[System.Object]' 215 | $DefaultUsersinDefaultOUTable = New-Object 'System.Collections.Generic.List[System.Object]' 216 | $TOPUserTable = New-Object 'System.Collections.Generic.List[System.Object]' 217 | $TOPGroupsTable = New-Object 'System.Collections.Generic.List[System.Object]' 218 | $TOPComputersTable = New-Object 'System.Collections.Generic.List[System.Object]' 219 | $GraphComputerOS = New-Object 'System.Collections.Generic.List[System.Object]' 220 | 221 | #Get all users right away. Instead of doing several lookups, we will use this object to look up all the information needed. 222 | $AllUsers = Get-ADUser -Filter * -Properties * 223 | 224 | $GPOs = Get-GPO -All | Select-Object DisplayName, GPOStatus, ModificationTime, @{ Label = "ComputerVersion"; Expression = { $_.computer.dsversion } }, @{ Label = "UserVersion"; Expression = { $_.user.dsversion } } 225 | 226 | <########################### 227 | Dashboard 228 | ############################> 229 | 230 | Write-Host "Working on Dashboard Report..." -ForegroundColor Green 231 | 232 | $dte = (Get-Date).AddDays(- $ADModNumber) 233 | 234 | $ADObjs = Get-ADObject -Filter { whenchanged -gt $dte -and ObjectClass -ne "domainDNS" -and ObjectClass -ne "rIDManager" -and ObjectClass -ne "rIDSet" } -Properties * 235 | 236 | foreach ($ADObj in $ADObjs) 237 | { 238 | 239 | if ($ADObj.ObjectClass -eq "GroupPolicyContainer") 240 | { 241 | 242 | $Name = $ADObj.DisplayName 243 | } 244 | 245 | else 246 | { 247 | 248 | $Name = $ADObj.Name 249 | } 250 | 251 | $obj = [PSCustomObject]@{ 252 | 253 | 'Name' = $Name 254 | 'Object Type' = $ADObj.ObjectClass 255 | 'When Changed' = $ADObj.WhenChanged 256 | } 257 | 258 | $ADObjectTable.Add($obj) 259 | } 260 | if (($ADObjectTable).Count -eq 0) 261 | { 262 | 263 | $Obj = [PSCustomObject]@{ 264 | 265 | Information = 'Information: No AD Objects have been modified recently' 266 | } 267 | 268 | $ADObjectTable.Add($obj) 269 | } 270 | 271 | 272 | $ADRecycleBinStatus = (Get-ADOptionalFeature -Filter 'name -like "Recycle Bin Feature"').EnabledScopes 273 | 274 | if ($ADRecycleBinStatus.Count -lt 1) 275 | { 276 | 277 | $ADRecycleBin = "Disabled" 278 | } 279 | 280 | else 281 | { 282 | 283 | $ADRecycleBin = "Enabled" 284 | } 285 | 286 | #Company Information 287 | $ADInfo = Get-ADDomain 288 | $ForestObj = Get-ADForest 289 | $DomainControllerobj = Get-ADDomain 290 | $Forest = $ADInfo.Forest 291 | $InfrastructureMaster = $DomainControllerobj.InfrastructureMaster 292 | $RIDMaster = $DomainControllerobj.RIDMaster 293 | $PDCEmulator = $DomainControllerobj.PDCEmulator 294 | $DomainNamingMaster = $ForestObj.DomainNamingMaster 295 | $SchemaMaster = $ForestObj.SchemaMaster 296 | 297 | $obj = [PSCustomObject]@{ 298 | 299 | 'Domain' = $Forest 300 | 'AD Recycle Bin' = $ADRecycleBin 301 | 'Infrastructure Master' = $InfrastructureMaster 302 | 'RID Master' = $RIDMaster 303 | 'PDC Emulator' = $PDCEmulator 304 | 'Domain Naming Master' = $DomainNamingMaster 305 | 'Schema Master' = $SchemaMaster 306 | } 307 | 308 | $CompanyInfoTable.Add($obj) 309 | 310 | if (($CompanyInfoTable).Count -eq 0) 311 | { 312 | 313 | $Obj = [PSCustomObject]@{ 314 | 315 | Information = 'Information: Could not get items for table' 316 | } 317 | $CompanyInfoTable.Add($obj) 318 | } 319 | 320 | #Get newly created users 321 | $When = ((Get-Date).AddDays(- $UserCreatedDays)).Date 322 | $NewUsers = $AllUsers | Where-Object { $_.whenCreated -ge $When } 323 | 324 | foreach ($Newuser in $Newusers) 325 | { 326 | 327 | $obj = [PSCustomObject]@{ 328 | 329 | 'Name' = $Newuser.Name 330 | 'Enabled' = $Newuser.Enabled 331 | 'Creation Date' = $Newuser.whenCreated 332 | } 333 | 334 | $NewCreatedUsersTable.Add($obj) 335 | } 336 | if (($NewCreatedUsersTable).Count -eq 0) 337 | { 338 | 339 | $Obj = [PSCustomObject]@{ 340 | 341 | Information = 'Information: No new users have been recently created' 342 | } 343 | $NewCreatedUsersTable.Add($obj) 344 | } 345 | 346 | 347 | 348 | #Get Domain Admins 349 | $DomainAdminMembers = Get-ADGroupMember "Domain Admins" 350 | 351 | foreach ($DomainAdminMember in $DomainAdminMembers) 352 | { 353 | 354 | $Name = $DomainAdminMember.Name 355 | $Type = $DomainAdminMember.ObjectClass 356 | $Enabled = ($AllUsers | Where-Object { $_.Name -eq $Name }).Enabled 357 | 358 | $obj = [PSCustomObject]@{ 359 | 360 | 'Name' = $Name 361 | 'Enabled' = $Enabled 362 | 'Type' = $Type 363 | } 364 | 365 | $DomainAdminTable.Add($obj) 366 | } 367 | 368 | if (($DomainAdminTable).Count -eq 0) 369 | { 370 | 371 | $Obj = [PSCustomObject]@{ 372 | 373 | Information = 'Information: No Domain Admin Members were found' 374 | } 375 | $DomainAdminTable.Add($obj) 376 | } 377 | 378 | 379 | #Get Enterprise Admins 380 | $EnterpriseAdminsMembers = Get-ADGroupMember "Enterprise Admins" -Server $SchemaMaster 381 | 382 | foreach ($EnterpriseAdminsMember in $EnterpriseAdminsMembers) 383 | { 384 | 385 | $Name = $EnterpriseAdminsMember.Name 386 | $Type = $EnterpriseAdminsMember.ObjectClass 387 | $Enabled = ($AllUsers | Where-Object { $_.Name -eq $Name }).Enabled 388 | 389 | $obj = [PSCustomObject]@{ 390 | 391 | 'Name' = $Name 392 | 'Enabled' = $Enabled 393 | 'Type' = $Type 394 | } 395 | 396 | $EnterpriseAdminTable.Add($obj) 397 | } 398 | 399 | if (($EnterpriseAdminTable).Count -eq 0) 400 | { 401 | 402 | $Obj = [PSCustomObject]@{ 403 | 404 | Information = 'Information: Enterprise Admin members were found' 405 | } 406 | $EnterpriseAdminTable.Add($obj) 407 | } 408 | 409 | $DefaultComputersOU = (Get-ADDomain).computerscontainer 410 | $DefaultComputers = Get-ADComputer -Filter * -Properties * -SearchBase "$DefaultComputersOU" 411 | 412 | foreach ($DefaultComputer in $DefaultComputers) 413 | { 414 | 415 | $obj = [PSCustomObject]@{ 416 | 417 | 'Name' = $DefaultComputer.Name 418 | 'Enabled' = $DefaultComputer.Enabled 419 | 'Operating System' = $DefaultComputer.OperatingSystem 420 | 'Modified Date' = $DefaultComputer.Modified 421 | 'Password Last Set' = $DefaultComputer.PasswordLastSet 422 | 'Protect from Deletion' = $DefaultComputer.ProtectedFromAccidentalDeletion 423 | } 424 | 425 | $DefaultComputersinDefaultOUTable.Add($obj) 426 | } 427 | 428 | if (($DefaultComputersinDefaultOUTable).Count -eq 0) 429 | { 430 | 431 | $Obj = [PSCustomObject]@{ 432 | 433 | Information = 'Information: No computers were found in the Default OU' 434 | } 435 | $DefaultComputersinDefaultOUTable.Add($obj) 436 | } 437 | 438 | $DefaultUsersOU = (Get-ADDomain).UsersContainer 439 | $DefaultUsers = $Allusers | Where-Object { $_.DistinguishedName -like "*$($DefaultUsersOU)" } | Select-Object Name, UserPrincipalName, Enabled, ProtectedFromAccidentalDeletion, EmailAddress, @{ Name = 'lastlogon'; Expression = { LastLogonConvert $_.lastlogon } }, DistinguishedName 440 | 441 | foreach ($DefaultUser in $DefaultUsers) 442 | { 443 | 444 | $obj = [PSCustomObject]@{ 445 | 446 | 'Name' = $DefaultUser.Name 447 | 'UserPrincipalName' = $DefaultUser.UserPrincipalName 448 | 'Enabled' = $DefaultUser.Enabled 449 | 'Protected from Deletion' = $DefaultUser.ProtectedFromAccidentalDeletion 450 | 'Last Logon' = $DefaultUser.LastLogon 451 | 'Email Address' = $DefaultUser.EmailAddress 452 | } 453 | 454 | $DefaultUsersinDefaultOUTable.Add($obj) 455 | } 456 | if (($DefaultUsersinDefaultOUTable).Count -eq 0) 457 | { 458 | 459 | $Obj = [PSCustomObject]@{ 460 | 461 | Information = 'Information: No Users were found in the default OU' 462 | } 463 | $DefaultUsersinDefaultOUTable.Add($obj) 464 | } 465 | 466 | 467 | #Expiring Accounts 468 | $LooseUsers = Search-ADAccount -AccountExpiring -UsersOnly 469 | 470 | foreach ($LooseUser in $LooseUsers) 471 | { 472 | 473 | $NameLoose = $LooseUser.Name 474 | $UPNLoose = $LooseUser.UserPrincipalName 475 | $ExpirationDate = $LooseUser.AccountExpirationDate 476 | $enabled = $LooseUser.Enabled 477 | 478 | $obj = [PSCustomObject]@{ 479 | 480 | 'Name' = $NameLoose 481 | 'UserPrincipalName' = $UPNLoose 482 | 'Expiration Date' = $ExpirationDate 483 | 'Enabled' = $enabled 484 | } 485 | 486 | $ExpiringAccountsTable.Add($obj) 487 | } 488 | 489 | if (($ExpiringAccountsTable).Count -eq 0) 490 | { 491 | 492 | $Obj = [PSCustomObject]@{ 493 | 494 | Information = 'Information: No Users were found to expire soon' 495 | } 496 | $ExpiringAccountsTable.Add($obj) 497 | } 498 | 499 | #Security Logs 500 | $SecurityLogs = Get-EventLog -Newest 7 -LogName "Security" | Where-Object { $_.Message -like "*An account*" } 501 | 502 | foreach ($SecurityLog in $SecurityLogs) 503 | { 504 | 505 | $TimeGenerated = $SecurityLog.TimeGenerated 506 | $EntryType = $SecurityLog.EntryType 507 | $Recipient = $SecurityLog.Message 508 | 509 | $obj = [PSCustomObject]@{ 510 | 511 | 'Time' = $TimeGenerated 512 | 'Type' = $EntryType 513 | 'Message' = $Recipient 514 | } 515 | 516 | $SecurityEventTable.Add($obj) 517 | } 518 | 519 | if (($SecurityEventTable).Count -eq 0) 520 | { 521 | 522 | $Obj = [PSCustomObject]@{ 523 | 524 | Information = 'Information: No logon security events were found' 525 | } 526 | $SecurityEventTable.Add($obj) 527 | } 528 | 529 | #Tenant Domain 530 | $Domains = Get-ADForest | Select-Object -ExpandProperty upnsuffixes | ForEach-Object{ 531 | 532 | $obj = [PSCustomObject]@{ 533 | 534 | 'UPN Suffixes' = $_ 535 | Valid = "True" 536 | } 537 | 538 | $DomainTable.Add($obj) 539 | } 540 | if (($DomainTable).Count -eq 0) 541 | { 542 | 543 | $Obj = [PSCustomObject]@{ 544 | 545 | Information = 'Information: No UPN Suffixes were found' 546 | } 547 | $DomainTable.Add($obj) 548 | } 549 | 550 | Write-Host "Done!" -ForegroundColor White 551 | 552 | <########################### 553 | 554 | Groups 555 | 556 | ############################> 557 | 558 | Write-Host "Working on Groups Report..." -ForegroundColor Green 559 | 560 | #Get groups and sort in alphabetical order 561 | $Groups = Get-ADGroup -Filter * -Properties * 562 | $SecurityCount = 0 563 | $MailSecurityCount = 0 564 | $CustomGroup = 0 565 | $DefaultGroup = 0 566 | $Groupswithmemebrship = 0 567 | $Groupswithnomembership = 0 568 | $GroupsProtected = 0 569 | $GroupsNotProtected = 0 570 | 571 | foreach ($Group in $Groups) 572 | { 573 | 574 | $DefaultADGroup = 'False' 575 | $Type = New-Object 'System.Collections.Generic.List[System.Object]' 576 | $Gemail = (Get-ADGroup $Group -Properties mail).mail 577 | 578 | if (($group.GroupCategory -eq "Security") -and ($Gemail -ne $Null)) 579 | { 580 | 581 | $MailSecurityCount++ 582 | } 583 | 584 | if (($group.GroupCategory -eq "Security") -and (($Gemail) -eq $Null)) 585 | { 586 | 587 | $SecurityCount++ 588 | } 589 | 590 | if ($Group.ProtectedFromAccidentalDeletion -eq $True) 591 | { 592 | 593 | $GroupsProtected++ 594 | } 595 | 596 | else 597 | { 598 | 599 | $GroupsNotProtected++ 600 | } 601 | 602 | if ($DefaultSGs -contains $Group.Name) 603 | { 604 | 605 | $DefaultADGroup = "True" 606 | $DefaultGroup++ 607 | } 608 | 609 | else 610 | { 611 | 612 | $CustomGroup++ 613 | } 614 | 615 | if ($group.GroupCategory -eq "Distribution") 616 | { 617 | 618 | $Type = "Distribution Group" 619 | } 620 | 621 | if (($group.GroupCategory -eq "Security") -and (($Gemail) -eq $Null)) 622 | { 623 | 624 | $Type = "Security Group" 625 | } 626 | 627 | if (($group.GroupCategory -eq "Security") -and (($Gemail) -ne $Null)) 628 | { 629 | 630 | $Type = "Mail-Enabled Security Group" 631 | } 632 | 633 | if ($Group.Name -ne "Domain Users") 634 | { 635 | 636 | $Users = (Get-ADGroupMember -Identity $Group | Sort-Object DisplayName | Select-Object -ExpandProperty Name) -join ", " 637 | 638 | if (!($Users)) 639 | { 640 | 641 | $Groupswithnomembership++ 642 | } 643 | 644 | else 645 | { 646 | 647 | $Groupswithmemebrship++ 648 | 649 | } 650 | } 651 | 652 | else 653 | { 654 | 655 | $Users = "Skipped Domain Users Membership" 656 | } 657 | 658 | $OwnerDN = Get-ADGroup -Filter { name -eq $Group.Name } -Properties managedBy | Select-Object -ExpandProperty ManagedBy 659 | Try 660 | { 661 | $Manager = Get-ADUser -Filter { distinguishedname -like $OwnerDN } | Select-Object -ExpandProperty Name 662 | } 663 | Catch 664 | { 665 | write-host -ForegroundColor Yellow "Cannot resolve the manager, " $Manager " on the group " $group.name 666 | } 667 | 668 | #$Manager = $AllUsers | Where-Object { $_.distinguishedname -eq $OwnerDN } | Select-Object -ExpandProperty Name 669 | 670 | $obj = [PSCustomObject]@{ 671 | 672 | 'Name' = $Group.name 673 | 'Type' = $Type 674 | 'Members' = $users 675 | 'Managed By' = $Manager 676 | 'E-mail Address' = $GEmail 677 | 'Protected from Deletion' = $Group.ProtectedFromAccidentalDeletion 678 | 'Default AD Group' = $DefaultADGroup 679 | } 680 | 681 | $table.Add($obj) 682 | } 683 | 684 | if (($table).Count -eq 0) 685 | { 686 | 687 | $Obj = [PSCustomObject]@{ 688 | 689 | Information = 'Information: No Groups were found' 690 | } 691 | $table.Add($obj) 692 | } 693 | #TOP groups table 694 | $obj1 = [PSCustomObject]@{ 695 | 696 | 'Total Groups' = $Groups.Count 697 | 'Mail-Enabled Security Groups' = $MailSecurityCount 698 | 'Security Groups' = $SecurityCount 699 | 'Distribution Groups' = $DistroCount 700 | } 701 | 702 | $TOPGroupsTable.Add($obj1) 703 | 704 | $obj1 = [PSCustomObject]@{ 705 | 706 | 'Name' = 'Mail-Enabled Security Groups' 707 | 'Count' = $MailSecurityCount 708 | } 709 | 710 | $GroupTypetable.Add($obj1) 711 | 712 | $obj1 = [PSCustomObject]@{ 713 | 714 | 'Name' = 'Security Groups' 715 | 'Count' = $SecurityCount 716 | } 717 | 718 | $GroupTypetable.Add($obj1) 719 | $DistroCount = ($Groups | Where-Object { $_.GroupCategory -eq "Distribution" }).Count 720 | 721 | $obj1 = [PSCustomObject]@{ 722 | 723 | 'Name' = 'Distribution Groups' 724 | 'Count' = $DistroCount 725 | } 726 | 727 | $GroupTypetable.Add($obj1) 728 | 729 | #Default Group Pie Chart 730 | $obj1 = [PSCustomObject]@{ 731 | 732 | 'Name' = 'Default Groups' 733 | 'Count' = $DefaultGroup 734 | } 735 | 736 | $DefaultGrouptable.Add($obj1) 737 | 738 | $obj1 = [PSCustomObject]@{ 739 | 740 | 'Name' = 'Custom Groups' 741 | 'Count' = $CustomGroup 742 | } 743 | 744 | $DefaultGrouptable.Add($obj1) 745 | 746 | #Group Protection Pie Chart 747 | $obj1 = [PSCustomObject]@{ 748 | 749 | 'Name' = 'Protected' 750 | 'Count' = $GroupsProtected 751 | } 752 | 753 | $GroupProtectionTable.Add($obj1) 754 | 755 | $obj1 = [PSCustomObject]@{ 756 | 757 | 'Name' = 'Not Protected' 758 | 'Count' = $GroupsNotProtected 759 | } 760 | 761 | $GroupProtectionTable.Add($obj1) 762 | 763 | #Groups with membership vs no membership pie chart 764 | $objmem = [PSCustomObject]@{ 765 | 766 | 'Name' = 'With Members' 767 | 'Count' = $Groupswithmemebrship 768 | } 769 | 770 | $GroupMembershipTable.Add($objmem) 771 | 772 | $objmem = [PSCustomObject]@{ 773 | 774 | 'Name' = 'No Members' 775 | 'Count' = $Groupswithnomembership 776 | } 777 | 778 | $GroupMembershipTable.Add($objmem) 779 | 780 | Write-Host "Done!" -ForegroundColor White 781 | 782 | <########################### 783 | 784 | Organizational Units 785 | 786 | ############################> 787 | 788 | Write-Host "Working on Organizational Units Report..." -ForegroundColor Green 789 | 790 | #Get all OUs' 791 | $OUs = Get-ADOrganizationalUnit -Filter * -Properties * 792 | $OUwithLinked = 0 793 | $OUwithnoLink = 0 794 | $OUProtected = 0 795 | $OUNotProtected = 0 796 | 797 | foreach ($OU in $OUs) 798 | { 799 | 800 | $LinkedGPOs = New-Object 'System.Collections.Generic.List[System.Object]' 801 | 802 | if (($OU.linkedgrouppolicyobjects).length -lt 1) 803 | { 804 | 805 | $LinkedGPOs = "None" 806 | $OUwithnoLink++ 807 | } 808 | 809 | else 810 | { 811 | 812 | $OUwithLinked++ 813 | $GPOslinks = $OU.linkedgrouppolicyobjects 814 | 815 | foreach ($GPOlink in $GPOslinks) 816 | { 817 | 818 | $Split1 = $GPOlink -split "{" | Select-Object -Last 1 819 | $Split2 = $Split1 -split "}" | Select-Object -First 1 820 | $LinkedGPOs.Add((Get-GPO -Guid $Split2 -ErrorAction SilentlyContinue).DisplayName) 821 | } 822 | } 823 | 824 | if ($OU.ProtectedFromAccidentalDeletion -eq $True) 825 | { 826 | 827 | $OUProtected++ 828 | } 829 | 830 | else 831 | { 832 | 833 | $OUNotProtected++ 834 | } 835 | 836 | $LinkedGPOs = $LinkedGPOs -join ", " 837 | $obj = [PSCustomObject]@{ 838 | 839 | 'Name' = $OU.Name 840 | 'Linked GPOs' = $LinkedGPOs 841 | 'Modified Date' = $OU.WhenChanged 842 | 'Protected from Deletion' = $OU.ProtectedFromAccidentalDeletion 843 | } 844 | 845 | $OUTable.Add($obj) 846 | } 847 | 848 | if (($OUTable).Count -eq 0) 849 | { 850 | 851 | $Obj = [PSCustomObject]@{ 852 | 853 | Information = 'Information: No OUs were found' 854 | } 855 | $OUTable.Add($obj) 856 | } 857 | 858 | #OUs with no GPO Linked 859 | $obj1 = [PSCustomObject]@{ 860 | 861 | 'Name' = "OUs with no GPO's linked" 862 | 'Count' = $OUwithnoLink 863 | } 864 | 865 | $OUGPOTable.Add($obj1) 866 | 867 | $obj2 = [PSCustomObject]@{ 868 | 869 | 'Name' = "OUs with GPO's linked" 870 | 'Count' = $OUwithLinked 871 | } 872 | 873 | $OUGPOTable.Add($obj2) 874 | 875 | #OUs Protected Pie Chart 876 | $obj1 = [PSCustomObject]@{ 877 | 878 | 'Name' = "Protected" 879 | 'Count' = $OUProtected 880 | } 881 | 882 | $OUProtectionTable.Add($obj1) 883 | 884 | $obj2 = [PSCustomObject]@{ 885 | 886 | 'Name' = "Not Protected" 887 | 'Count' = $OUNotProtected 888 | } 889 | 890 | $OUProtectionTable.Add($obj2) 891 | 892 | Write-Host "Done!" -ForegroundColor White 893 | 894 | <########################### 895 | 896 | USERS 897 | 898 | ############################> 899 | 900 | Write-Host "Working on Users Report..." -ForegroundColor Green 901 | 902 | $UserEnabled = 0 903 | $UserDisabled = 0 904 | $UserPasswordExpires = 0 905 | $UserPasswordNeverExpires = 0 906 | $ProtectedUsers = 0 907 | $NonProtectedUsers = 0 908 | 909 | $UsersWIthPasswordsExpiringInUnderAWeek = 0 910 | $UsersNotLoggedInOver30Days = 0 911 | $AccountsExpiringSoon = 0 912 | 913 | 914 | #Get users that haven't logged on in X amount of days, var is set at start of script 915 | $userphaventloggedonrecentlytable = New-Object 'System.Collections.Generic.List[System.Object]' 916 | foreach ($User in $AllUsers) 917 | { 918 | 919 | $AttVar = $User | Select-Object Enabled, PasswordExpired, PasswordLastSet, PasswordNeverExpires, PasswordNotRequired, Name, SamAccountName, EmailAddress, AccountExpirationDate, @{ Name = 'lastlogon'; Expression = { LastLogonConvert $_.lastlogon } }, DistinguishedName 920 | $maxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.Days 921 | 922 | if ((($AttVar.PasswordNeverExpires) -eq $False) -and (($AttVar.Enabled) -ne $false)) 923 | { 924 | 925 | #Get Password last set date 926 | $passwordSetDate = ($User | ForEach-Object { $_.PasswordLastSet }) 927 | 928 | if ($null -eq $passwordSetDate) 929 | { 930 | 931 | $daystoexpire = "User has never logged on" 932 | } 933 | 934 | else 935 | { 936 | 937 | #Check for Fine Grained Passwords 938 | $PasswordPol = (Get-ADUserResultantPasswordPolicy $user) 939 | 940 | if (($PasswordPol) -ne $null) 941 | { 942 | 943 | $maxPasswordAge = ($PasswordPol).MaxPasswordAge 944 | } 945 | 946 | $expireson = $passwordsetdate.AddDays($maxPasswordAge) 947 | $today = (Get-Date) 948 | 949 | #Gets the count on how many days until the password expires and stores it in the $daystoexpire var 950 | $daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days 951 | } 952 | } 953 | 954 | else 955 | { 956 | 957 | $daystoexpire = "N/A" 958 | } 959 | 960 | if (($User.Enabled -eq $True) -and ($AttVar.LastLogon -lt ((Get-Date).AddDays(- $Days))) -and ($User.LastLogon -ne $NULL)) 961 | { 962 | 963 | $obj = [PSCustomObject]@{ 964 | 965 | 'Name' = $User.Name 966 | 'UserPrincipalName' = $User.UserPrincipalName 967 | 'Enabled' = $AttVar.Enabled 968 | 'Protected from Deletion' = $User.ProtectedFromAccidentalDeletion 969 | 'Last Logon' = $AttVar.lastlogon 970 | 'Password Never Expires' = $AttVar.PasswordNeverExpires 971 | 'Days Until Password Expires' = $daystoexpire 972 | } 973 | 974 | $userphaventloggedonrecentlytable.Add($obj) 975 | } 976 | 977 | #Items for protected vs non protected users 978 | if ($User.ProtectedFromAccidentalDeletion -eq $False) 979 | { 980 | 981 | $NonProtectedUsers++ 982 | } 983 | 984 | else 985 | { 986 | 987 | $ProtectedUsers++ 988 | } 989 | 990 | #Items for the enabled vs disabled users pie chart 991 | if (($AttVar.PasswordNeverExpires) -ne $false) 992 | { 993 | 994 | $UserPasswordNeverExpires++ 995 | } 996 | 997 | else 998 | { 999 | 1000 | $UserPasswordExpires++ 1001 | } 1002 | 1003 | #Items for password expiration pie chart 1004 | if (($AttVar.Enabled) -ne $false) 1005 | { 1006 | 1007 | $UserEnabled++ 1008 | } 1009 | 1010 | else 1011 | { 1012 | 1013 | $UserDisabled++ 1014 | } 1015 | 1016 | $Name = $User.Name 1017 | $UPN = $User.UserPrincipalName 1018 | $Enabled = $AttVar.Enabled 1019 | $EmailAddress = $AttVar.EmailAddress 1020 | $AccountExpiration = $AttVar.AccountExpirationDate 1021 | $PasswordExpired = $AttVar.PasswordExpired 1022 | $PasswordLastSet = $AttVar.PasswordLastSet 1023 | $PasswordNeverExpires = $AttVar.PasswordNeverExpires 1024 | $daysUntilPWExpire = $daystoexpire 1025 | 1026 | $obj = [PSCustomObject]@{ 1027 | 1028 | 'Name' = $Name 1029 | 'UserPrincipalName' = $UPN 1030 | 'Enabled' = $Enabled 1031 | 'Protected from Deletion' = $User.ProtectedFromAccidentalDeletion 1032 | 'Last Logon' = $LastLogon 1033 | 'Email Address' = $EmailAddress 1034 | 'Account Expiration' = $AccountExpiration 1035 | 'Change Password Next Logon' = $PasswordExpired 1036 | 'Password Last Set' = $PasswordLastSet 1037 | 'Password Never Expires' = $PasswordNeverExpires 1038 | 'Days Until Password Expires' = $daystoexpire 1039 | } 1040 | 1041 | $usertable.Add($obj) 1042 | 1043 | if ($daystoexpire -lt $DaysUntilPWExpireINT) 1044 | { 1045 | 1046 | $obj = [PSCustomObject]@{ 1047 | 1048 | 'Name' = $Name 1049 | 'Days Until Password Expires' = $daystoexpire 1050 | } 1051 | 1052 | $PasswordExpireSoonTable.Add($obj) 1053 | } 1054 | } 1055 | if (($userphaventloggedonrecentlytable).Count -eq 0) 1056 | { 1057 | $userphaventloggedonrecentlytable = [PSCustomObject]@{ 1058 | 1059 | Information = "Information: No Users were found to have not logged on in $Days days or more" 1060 | } 1061 | } 1062 | if (($PasswordExpireSoonTable).Count -eq 0) 1063 | { 1064 | 1065 | $Obj = [PSCustomObject]@{ 1066 | 1067 | Information = 'Information: No users were found to have passwords expiring soon' 1068 | } 1069 | $PasswordExpireSoonTable.Add($obj) 1070 | } 1071 | 1072 | 1073 | if (($usertable).Count -eq 0) 1074 | { 1075 | 1076 | $Obj = [PSCustomObject]@{ 1077 | 1078 | Information = 'Information: No users were found' 1079 | } 1080 | $usertable.Add($obj) 1081 | } 1082 | 1083 | #Data for users enabled vs disabled pie graph 1084 | $objULic = [PSCustomObject]@{ 1085 | 1086 | 'Name' = 'Enabled' 1087 | 'Count' = $UserEnabled 1088 | } 1089 | 1090 | $EnabledDisabledUsersTable.Add($objULic) 1091 | 1092 | $objULic = [PSCustomObject]@{ 1093 | 1094 | 'Name' = 'Disabled' 1095 | 'Count' = $UserDisabled 1096 | } 1097 | 1098 | $EnabledDisabledUsersTable.Add($objULic) 1099 | 1100 | #Data for users password expires pie graph 1101 | $objULic = [PSCustomObject]@{ 1102 | 1103 | 'Name' = 'Password Expires' 1104 | 'Count' = $UserPasswordExpires 1105 | } 1106 | 1107 | $PasswordExpirationTable.Add($objULic) 1108 | 1109 | $objULic = [PSCustomObject]@{ 1110 | 1111 | 'Name' = 'Password Never Expires' 1112 | 'Count' = $UserPasswordNeverExpires 1113 | } 1114 | 1115 | $PasswordExpirationTable.Add($objULic) 1116 | 1117 | #Data for protected users pie graph 1118 | $objULic = [PSCustomObject]@{ 1119 | 1120 | 'Name' = 'Protected' 1121 | 'Count' = $ProtectedUsers 1122 | } 1123 | 1124 | $ProtectedUsersTable.Add($objULic) 1125 | 1126 | $objULic = [PSCustomObject]@{ 1127 | 1128 | 'Name' = 'Not Protected' 1129 | 'Count' = $NonProtectedUsers 1130 | } 1131 | 1132 | $ProtectedUsersTable.Add($objULic) 1133 | if ($null -ne (($userphaventloggedonrecentlytable).Information)) 1134 | { 1135 | $UHLONXD = "0" 1136 | 1137 | } 1138 | Else 1139 | { 1140 | $UHLONXD = $userphaventloggedonrecentlytable.Count 1141 | 1142 | } 1143 | #TOP User table 1144 | If ($null -eq (($ExpiringAccountsTable).Information)) 1145 | { 1146 | 1147 | $objULic = [PSCustomObject]@{ 1148 | 'Total Users' = $AllUsers.Count 1149 | "Users with Passwords Expiring in less than $DaysUntilPWExpireINT days" = $PasswordExpireSoonTable.Count 1150 | 'Expiring Accounts' = $ExpiringAccountsTable.Count 1151 | "Users Haven't Logged on in $Days Days or more" = $UHLONXD 1152 | } 1153 | 1154 | $TOPUserTable.Add($objULic) 1155 | 1156 | 1157 | } 1158 | Else 1159 | { 1160 | 1161 | $objULic = [PSCustomObject]@{ 1162 | 'Total Users' = $AllUsers.Count 1163 | "Users with Passwords Expiring in less than $DaysUntilPWExpireINT days" = $PasswordExpireSoonTable.Count 1164 | 'Expiring Accounts' = "0" 1165 | "Users Haven't Logged on in $Days Days or more" = $UHLONXD 1166 | } 1167 | $TOPUserTable.Add($objULic) 1168 | } 1169 | 1170 | Write-Host "Done!" -ForegroundColor White 1171 | <########################### 1172 | 1173 | Group Policy 1174 | 1175 | ############################> 1176 | Write-Host "Working on Group Policy Report..." -ForegroundColor Green 1177 | 1178 | $GPOTable = New-Object 'System.Collections.Generic.List[System.Object]' 1179 | 1180 | foreach ($GPO in $GPOs) 1181 | { 1182 | 1183 | $obj = [PSCustomObject]@{ 1184 | 1185 | 'Name' = $GPO.DisplayName 1186 | 'Status' = $GPO.GpoStatus 1187 | 'Modified Date' = $GPO.ModificationTime 1188 | 'User Version' = $GPO.UserVersion 1189 | 'Computer Version' = $GPO.ComputerVersion 1190 | } 1191 | 1192 | $GPOTable.Add($obj) 1193 | } 1194 | if (($GPOTable).Count -eq 0) 1195 | { 1196 | 1197 | $Obj = [PSCustomObject]@{ 1198 | 1199 | Information = 'Information: No Group Policy Obejects were found' 1200 | } 1201 | $GPOTable.Add($obj) 1202 | } 1203 | Write-Host "Done!" -ForegroundColor White 1204 | <########################### 1205 | 1206 | Computers 1207 | 1208 | ############################> 1209 | Write-Host "Working on Computers Report..." -ForegroundColor Green 1210 | 1211 | $Computers = Get-ADComputer -Filter * -Properties * 1212 | $ComputersProtected = 0 1213 | $ComputersNotProtected = 0 1214 | $ComputerEnabled = 0 1215 | $ComputerDisabled = 0 1216 | #Only search for versions of windows that exist in the Environment 1217 | $WindowsRegex = "(Windows (Server )?(\d+|XP)?( R2)?).*" 1218 | $OsVersions = $Computers | Select-Object OperatingSystem -unique | ForEach-Object { 1219 | if ($_.OperatingSystem -match $WindowsRegex ){ 1220 | return $matches[1] 1221 | } elseif ($_.OperatingSystem -ne $null) { 1222 | return $_.OperatingSystem 1223 | } 1224 | } | Select-Object -unique | Sort-Object 1225 | 1226 | $OsObj = [PSCustomObject]@{} 1227 | 1228 | $OsVersions | ForEach-Object { 1229 | 1230 | $OsObj | Add-Member -Name $_ -Value 0 -Type NoteProperty 1231 | 1232 | } 1233 | 1234 | foreach ($Computer in $Computers) 1235 | { 1236 | 1237 | if ($Computer.ProtectedFromAccidentalDeletion -eq $True) 1238 | { 1239 | 1240 | $ComputersProtected++ 1241 | } 1242 | 1243 | else 1244 | { 1245 | 1246 | $ComputersNotProtected++ 1247 | } 1248 | 1249 | if ($Computer.Enabled -eq $True) 1250 | { 1251 | 1252 | $ComputerEnabled++ 1253 | } 1254 | 1255 | else 1256 | { 1257 | 1258 | $ComputerDisabled++ 1259 | } 1260 | 1261 | $obj = [PSCustomObject]@{ 1262 | 1263 | 'Name' = $Computer.Name 1264 | 'Enabled' = $Computer.Enabled 1265 | 'Operating System' = $Computer.OperatingSystem 1266 | 'Modified Date' = $Computer.Modified 1267 | 'Password Last Set' = $Computer.PasswordLastSet 1268 | 'Protect from Deletion' = $Computer.ProtectedFromAccidentalDeletion 1269 | } 1270 | 1271 | $ComputersTable.Add($obj) 1272 | 1273 | if ($Computer.OperatingSystem -match $WindowsRegex) 1274 | { 1275 | $OsObj."$($matches[1])"++ 1276 | } 1277 | 1278 | } 1279 | 1280 | if (($ComputersTable).Count -eq 0) 1281 | { 1282 | 1283 | $Obj = [PSCustomObject]@{ 1284 | 1285 | Information = 'Information: No computers were found' 1286 | } 1287 | $ComputersTable.Add($obj) 1288 | } 1289 | 1290 | #Pie chart breaking down OS for computer obj 1291 | $OsObj.PSObject.Properties | ForEach-Object { 1292 | $GraphComputerOS.Add([PSCustomObject]@{'Name' = $_.Name;"Count" =$_.Value}) 1293 | } 1294 | 1295 | #Data for TOP Computers data table 1296 | $OsObj | Add-Member -Name 'Total Computers' -Value $Computers.Count -Type NoteProperty 1297 | 1298 | $TOPComputersTable.Add($OsObj) 1299 | 1300 | 1301 | #Data for protected Computers pie graph 1302 | $objULic = [PSCustomObject]@{ 1303 | 1304 | 'Name' = 'Protected' 1305 | 'Count' = $ComputerProtected 1306 | } 1307 | 1308 | $ComputerProtectedTable.Add($objULic) 1309 | 1310 | $objULic = [PSCustomObject]@{ 1311 | 1312 | 'Name' = 'Not Protected' 1313 | 'Count' = $ComputersNotProtected 1314 | } 1315 | 1316 | $ComputerProtectedTable.Add($objULic) 1317 | 1318 | #Data for enabled/vs Computers pie graph 1319 | $objULic = [PSCustomObject]@{ 1320 | 1321 | 'Name' = 'Enabled' 1322 | 'Count' = $ComputerEnabled 1323 | } 1324 | 1325 | $ComputersEnabledTable.Add($objULic) 1326 | 1327 | $objULic = [PSCustomObject]@{ 1328 | 1329 | 'Name' = 'Disabled' 1330 | 'Count' = $ComputerDisabled 1331 | } 1332 | 1333 | $ComputersEnabledTable.Add($objULic) 1334 | 1335 | Write-Host "Done!" -ForegroundColor White 1336 | 1337 | $tabarray = @('Dashboard', 'Groups', 'Organizational Units', 'Users', 'Group Policy', 'Computers') 1338 | 1339 | Write-Host "Compiling Report..." -ForegroundColor Green 1340 | 1341 | ##--OU Protection PIE CHART--## 1342 | #Basic Properties 1343 | $PO12 = Get-HTMLPieChartObject 1344 | $PO12.Title = "Organizational Units Protected from Deletion" 1345 | $PO12.Size.Height = 250 1346 | $PO12.Size.width = 250 1347 | $PO12.ChartStyle.ChartType = 'doughnut' 1348 | 1349 | #These file exist in the module directoy, There are 4 schemes by default 1350 | $PO12.ChartStyle.ColorSchemeName = "ColorScheme3" 1351 | 1352 | #There are 8 generated schemes, randomly generated at runtime 1353 | $PO12.ChartStyle.ColorSchemeName = "Generated3" 1354 | 1355 | #you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme 1356 | $PO12.ChartStyle.ColorSchemeName = 'Random' 1357 | 1358 | #Data defintion you can reference any column from name and value from the dataset. 1359 | #Name and Count are the default to work with the Group function. 1360 | $PO12.DataDefinition.DataNameColumnName = 'Name' 1361 | $PO12.DataDefinition.DataValueColumnName = 'Count' 1362 | 1363 | ##--Computer OS Breakdown PIE CHART--## 1364 | $PieObjectComputerObjOS = Get-HTMLPieChartObject 1365 | $PieObjectComputerObjOS.Title = "Computer Operating Systems" 1366 | 1367 | #These file exist in the module directoy, There are 4 schemes by default 1368 | $PieObjectComputerObjOS.ChartStyle.ColorSchemeName = "ColorScheme3" 1369 | 1370 | #There are 8 generated schemes, randomly generated at runtime 1371 | $PieObjectComputerObjOS.ChartStyle.ColorSchemeName = "Generated3" 1372 | 1373 | #you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme 1374 | $PieObjectComputerObjOS.ChartStyle.ColorSchemeName = 'Random' 1375 | 1376 | ##--Computers Protection PIE CHART--## 1377 | #Basic Properties 1378 | $PieObjectComputersProtected = Get-HTMLPieChartObject 1379 | $PieObjectComputersProtected.Title = "Computers Protected from Deletion" 1380 | $PieObjectComputersProtected.Size.Height = 250 1381 | $PieObjectComputersProtected.Size.width = 250 1382 | $PieObjectComputersProtected.ChartStyle.ChartType = 'doughnut' 1383 | 1384 | #These file exist in the module directoy, There are 4 schemes by default 1385 | $PieObjectComputersProtected.ChartStyle.ColorSchemeName = "ColorScheme3" 1386 | 1387 | #There are 8 generated schemes, randomly generated at runtime 1388 | $PieObjectComputersProtected.ChartStyle.ColorSchemeName = "Generated3" 1389 | 1390 | #you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme 1391 | $PieObjectComputersProtected.ChartStyle.ColorSchemeName = 'Random' 1392 | 1393 | #Data defintion you can reference any column from name and value from the dataset. 1394 | #Name and Count are the default to work with the Group function. 1395 | $PieObjectComputersProtected.DataDefinition.DataNameColumnName = 'Name' 1396 | $PieObjectComputersProtected.DataDefinition.DataValueColumnName = 'Count' 1397 | 1398 | ##--Computers Enabled PIE CHART--## 1399 | #Basic Properties 1400 | $PieObjectComputersEnabled = Get-HTMLPieChartObject 1401 | $PieObjectComputersEnabled.Title = "Computers Enabled vs Disabled" 1402 | $PieObjectComputersEnabled.Size.Height = 250 1403 | $PieObjectComputersEnabled.Size.width = 250 1404 | $PieObjectComputersEnabled.ChartStyle.ChartType = 'doughnut' 1405 | 1406 | #These file exist in the module directoy, There are 4 schemes by default 1407 | $PieObjectComputersEnabled.ChartStyle.ColorSchemeName = "ColorScheme3" 1408 | 1409 | #There are 8 generated schemes, randomly generated at runtime 1410 | $PieObjectComputersEnabled.ChartStyle.ColorSchemeName = "Generated3" 1411 | 1412 | #you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme 1413 | $PieObjectComputersEnabled.ChartStyle.ColorSchemeName = 'Random' 1414 | 1415 | #Data defintion you can reference any column from name and value from the dataset. 1416 | #Name and Count are the default to work with the Group function. 1417 | $PieObjectComputersEnabled.DataDefinition.DataNameColumnName = 'Name' 1418 | $PieObjectComputersEnabled.DataDefinition.DataValueColumnName = 'Count' 1419 | 1420 | ##--USERS Protection PIE CHART--## 1421 | #Basic Properties 1422 | $PieObjectProtectedUsers = Get-HTMLPieChartObject 1423 | $PieObjectProtectedUsers.Title = "Users Protected from Deletion" 1424 | $PieObjectProtectedUsers.Size.Height = 250 1425 | $PieObjectProtectedUsers.Size.width = 250 1426 | $PieObjectProtectedUsers.ChartStyle.ChartType = 'doughnut' 1427 | 1428 | #These file exist in the module directoy, There are 4 schemes by default 1429 | $PieObjectProtectedUsers.ChartStyle.ColorSchemeName = "ColorScheme3" 1430 | 1431 | #There are 8 generated schemes, randomly generated at runtime 1432 | $PieObjectProtectedUsers.ChartStyle.ColorSchemeName = "Generated3" 1433 | 1434 | #you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme 1435 | $PieObjectProtectedUsers.ChartStyle.ColorSchemeName = 'Random' 1436 | 1437 | #Data defintion you can reference any column from name and value from the dataset. 1438 | #Name and Count are the default to work with the Group function. 1439 | $PieObjectProtectedUsers.DataDefinition.DataNameColumnName = 'Name' 1440 | $PieObjectProtectedUsers.DataDefinition.DataValueColumnName = 'Count' 1441 | 1442 | #Basic Properties 1443 | $PieObjectOUGPOLinks = Get-HTMLPieChartObject 1444 | $PieObjectOUGPOLinks.Title = "OU GPO Links" 1445 | $PieObjectOUGPOLinks.Size.Height = 250 1446 | $PieObjectOUGPOLinks.Size.width = 250 1447 | $PieObjectOUGPOLinks.ChartStyle.ChartType = 'doughnut' 1448 | 1449 | #These file exist in the module directoy, There are 4 schemes by default 1450 | $PieObjectOUGPOLinks.ChartStyle.ColorSchemeName = "ColorScheme4" 1451 | 1452 | #There are 8 generated schemes, randomly generated at runtime 1453 | $PieObjectOUGPOLinks.ChartStyle.ColorSchemeName = "Generated5" 1454 | 1455 | #you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme 1456 | $PieObjectOUGPOLinks.ChartStyle.ColorSchemeName = 'Random' 1457 | 1458 | #Data defintion you can reference any column from name and value from the dataset. 1459 | #Name and Count are the default to work with the Group function. 1460 | $PieObjectOUGPOLinks.DataDefinition.DataNameColumnName = 'Name' 1461 | $PieObjectOUGPOLinks.DataDefinition.DataValueColumnName = 'Count' 1462 | 1463 | #Basic Properties 1464 | $PieObject4 = Get-HTMLPieChartObject 1465 | $PieObject4.Title = "Office 365 Unassigned Licenses" 1466 | $PieObject4.Size.Height = 250 1467 | $PieObject4.Size.width = 250 1468 | $PieObject4.ChartStyle.ChartType = 'doughnut' 1469 | 1470 | #These file exist in the module directoy, There are 4 schemes by default 1471 | $PieObject4.ChartStyle.ColorSchemeName = "ColorScheme4" 1472 | 1473 | #There are 8 generated schemes, randomly generated at runtime 1474 | $PieObject4.ChartStyle.ColorSchemeName = "Generated4" 1475 | 1476 | #you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme 1477 | $PieObject4.ChartStyle.ColorSchemeName = 'Random' 1478 | 1479 | #Data defintion you can reference any column from name and value from the dataset. 1480 | #Name and Count are the default to work with the Group function. 1481 | $PieObject4.DataDefinition.DataNameColumnName = 'Name' 1482 | $PieObject4.DataDefinition.DataValueColumnName = 'Unassigned Licenses' 1483 | 1484 | #Basic Properties 1485 | $PieObjectGroupType = Get-HTMLPieChartObject 1486 | $PieObjectGroupType.Title = "Group Types" 1487 | $PieObjectGroupType.Size.Height = 250 1488 | $PieObjectGroupType.Size.width = 250 1489 | $PieObjectGroupType.ChartStyle.ChartType = 'doughnut' 1490 | 1491 | #Pie Chart Groups with members vs no members 1492 | $PieObjectGroupMembersType = Get-HTMLPieChartObject 1493 | $PieObjectGroupMembersType.Title = "Group Membership" 1494 | $PieObjectGroupMembersType.Size.Height = 250 1495 | $PieObjectGroupMembersType.Size.width = 250 1496 | $PieObjectGroupMembersType.ChartStyle.ChartType = 'doughnut' 1497 | $PieObjectGroupMembersType.ChartStyle.ColorSchemeName = "ColorScheme4" 1498 | $PieObjectGroupMembersType.ChartStyle.ColorSchemeName = "Generated8" 1499 | $PieObjectGroupMembersType.ChartStyle.ColorSchemeName = 'Random' 1500 | $PieObjectGroupMembersType.DataDefinition.DataNameColumnName = 'Name' 1501 | $PieObjectGroupMembersType.DataDefinition.DataValueColumnName = 'Count' 1502 | 1503 | #Basic Properties 1504 | $PieObjectGroupType2 = Get-HTMLPieChartObject 1505 | $PieObjectGroupType2.Title = "Custom vs Default Groups" 1506 | $PieObjectGroupType2.Size.Height = 250 1507 | $PieObjectGroupType2.Size.width = 250 1508 | $PieObjectGroupType2.ChartStyle.ChartType = 'doughnut' 1509 | 1510 | #These file exist in the module directoy, There are 4 schemes by default 1511 | $PieObjectGroupType.ChartStyle.ColorSchemeName = "ColorScheme4" 1512 | 1513 | #There are 8 generated schemes, randomly generated at runtime 1514 | $PieObjectGroupType.ChartStyle.ColorSchemeName = "Generated8" 1515 | 1516 | #you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme 1517 | $PieObjectGroupType.ChartStyle.ColorSchemeName = 'Random' 1518 | 1519 | #Data defintion you can reference any column from name and value from the dataset. 1520 | #Name and Count are the default to work with the Group function. 1521 | $PieObjectGroupType.DataDefinition.DataNameColumnName = 'Name' 1522 | $PieObjectGroupType.DataDefinition.DataValueColumnName = 'Count' 1523 | 1524 | ##--Enabled users vs Disabled Users PIE CHART--## 1525 | #Basic Properties 1526 | $EnabledDisabledUsersPieObject = Get-HTMLPieChartObject 1527 | $EnabledDisabledUsersPieObject.Title = "Enabled vs Disabled Users" 1528 | $EnabledDisabledUsersPieObject.Size.Height = 250 1529 | $EnabledDisabledUsersPieObject.Size.width = 250 1530 | $EnabledDisabledUsersPieObject.ChartStyle.ChartType = 'doughnut' 1531 | 1532 | #These file exist in the module directoy, There are 4 schemes by default 1533 | $EnabledDisabledUsersPieObject.ChartStyle.ColorSchemeName = "ColorScheme3" 1534 | 1535 | #There are 8 generated schemes, randomly generated at runtime 1536 | $EnabledDisabledUsersPieObject.ChartStyle.ColorSchemeName = "Generated3" 1537 | 1538 | #you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme 1539 | $EnabledDisabledUsersPieObject.ChartStyle.ColorSchemeName = 'Random' 1540 | 1541 | #Data defintion you can reference any column from name and value from the dataset. 1542 | #Name and Count are the default to work with the Group function. 1543 | $EnabledDisabledUsersPieObject.DataDefinition.DataNameColumnName = 'Name' 1544 | $EnabledDisabledUsersPieObject.DataDefinition.DataValueColumnName = 'Count' 1545 | 1546 | ##--PasswordNeverExpires PIE CHART--## 1547 | #Basic Properties 1548 | $PWExpiresUsersTable = Get-HTMLPieChartObject 1549 | $PWExpiresUsersTable.Title = "Password Expiration" 1550 | $PWExpiresUsersTable.Size.Height = 250 1551 | $PWExpiresUsersTable.Size.Width = 250 1552 | $PWExpiresUsersTable.ChartStyle.ChartType = 'doughnut' 1553 | 1554 | #These file exist in the module directoy, There are 4 schemes by default 1555 | $PWExpiresUsersTable.ChartStyle.ColorSchemeName = "ColorScheme3" 1556 | 1557 | #There are 8 generated schemes, randomly generated at runtime 1558 | $PWExpiresUsersTable.ChartStyle.ColorSchemeName = "Generated3" 1559 | 1560 | #you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme 1561 | $PWExpiresUsersTable.ChartStyle.ColorSchemeName = 'Random' 1562 | 1563 | #Data defintion you can reference any column from name and value from the dataset. 1564 | #Name and Count are the default to work with the Group function. 1565 | $PWExpiresUsersTable.DataDefinition.DataNameColumnName = 'Name' 1566 | $PWExpiresUsersTable.DataDefinition.DataValueColumnName = 'Count' 1567 | 1568 | ##--Group Protection PIE CHART--## 1569 | #Basic Properties 1570 | $PieObjectGroupProtection = Get-HTMLPieChartObject 1571 | $PieObjectGroupProtection.Title = "Groups Protected from Deletion" 1572 | $PieObjectGroupProtection.Size.Height = 250 1573 | $PieObjectGroupProtection.Size.width = 250 1574 | $PieObjectGroupProtection.ChartStyle.ChartType = 'doughnut' 1575 | 1576 | #These file exist in the module directoy, There are 4 schemes by default 1577 | $PieObjectGroupProtection.ChartStyle.ColorSchemeName = "ColorScheme3" 1578 | 1579 | #There are 8 generated schemes, randomly generated at runtime 1580 | $PieObjectGroupProtection.ChartStyle.ColorSchemeName = "Generated3" 1581 | 1582 | #you can also ask for a random scheme. Which also happens ifyou have too many records for the scheme 1583 | $PieObjectGroupProtection.ChartStyle.ColorSchemeName = 'Random' 1584 | 1585 | #Data defintion you can reference any column from name and value from the dataset. 1586 | #Name and Count are the default to work with the Group function. 1587 | $PieObjectGroupProtection.DataDefinition.DataNameColumnName = 'Name' 1588 | $PieObjectGroupProtection.DataDefinition.DataValueColumnName = 'Count' 1589 | 1590 | #Dashboard Report 1591 | $FinalReport = New-Object 'System.Collections.Generic.List[System.Object]' 1592 | $FinalReport.Add($(Get-HTMLOpenPage -TitleText $ReportTitle -LeftLogoString $CompanyLogo -RightLogoString $RightLogo)) 1593 | $FinalReport.Add($(Get-HTMLTabHeader -TabNames $tabarray)) 1594 | $FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[0] -TabHeading ("Report: " + (Get-Date -Format MM-dd-yyyy)))) 1595 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Company Information")) 1596 | $FinalReport.Add($(Get-HTMLContentTable $CompanyInfoTable)) 1597 | $FinalReport.Add($(Get-HTMLContentClose)) 1598 | 1599 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Groups")) 1600 | $FinalReport.Add($(Get-HTMLColumn1of2)) 1601 | $FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText 'Domain Administrators')) 1602 | $FinalReport.Add($(Get-HTMLContentDataTable $DomainAdminTable -HideFooter)) 1603 | $FinalReport.Add($(Get-HTMLContentClose)) 1604 | $FinalReport.Add($(Get-HTMLColumnClose)) 1605 | $FinalReport.Add($(Get-HTMLColumn2of2)) 1606 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText 'Enterprise Administrators')) 1607 | $FinalReport.Add($(Get-HTMLContentDataTable $EnterpriseAdminTable -HideFooter)) 1608 | $FinalReport.Add($(Get-HTMLContentClose)) 1609 | $FinalReport.Add($(Get-HTMLColumnClose)) 1610 | $FinalReport.Add($(Get-HTMLContentClose)) 1611 | 1612 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Objects in Default OUs")) 1613 | $FinalReport.Add($(Get-HTMLColumn1of2)) 1614 | $FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText 'Computers')) 1615 | $FinalReport.Add($(Get-HTMLContentDataTable $DefaultComputersinDefaultOUTable -HideFooter)) 1616 | $FinalReport.Add($(Get-HTMLContentClose)) 1617 | $FinalReport.Add($(Get-HTMLColumnClose)) 1618 | $FinalReport.Add($(Get-HTMLColumn2of2)) 1619 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText 'Users')) 1620 | $FinalReport.Add($(Get-HTMLContentDataTable $DefaultUsersinDefaultOUTable -HideFooter)) 1621 | $FinalReport.Add($(Get-HTMLContentClose)) 1622 | $FinalReport.Add($(Get-HTMLColumnClose)) 1623 | $FinalReport.Add($(Get-HTMLContentClose)) 1624 | 1625 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "AD Objects Modified in Last $ADModNumber Days")) 1626 | $FinalReport.Add($(Get-HTMLContentDataTable $ADObjectTable)) 1627 | $FinalReport.Add($(Get-HTMLContentClose)) 1628 | 1629 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Expiring Items")) 1630 | $FinalReport.Add($(Get-HTMLColumn1of2)) 1631 | $FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Users with Passwords Expiring in less than $DaysUntilPWExpireINT days")) 1632 | $FinalReport.Add($(Get-HTMLContentDataTable $PasswordExpireSoonTable -HideFooter)) 1633 | $FinalReport.Add($(Get-HTMLContentClose)) 1634 | $FinalReport.Add($(Get-HTMLColumnClose)) 1635 | $FinalReport.Add($(Get-HTMLColumn2of2)) 1636 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText 'Accounts Expiring Soon')) 1637 | $FinalReport.Add($(Get-HTMLContentDataTable $ExpiringAccountsTable -HideFooter)) 1638 | $FinalReport.Add($(Get-HTMLContentClose)) 1639 | $FinalReport.Add($(Get-HTMLColumnClose)) 1640 | $FinalReport.Add($(Get-HTMLContentClose)) 1641 | 1642 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Accounts")) 1643 | $FinalReport.Add($(Get-HTMLColumn1of2)) 1644 | $FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Users Haven't Logged on in $Days Days or more")) 1645 | $FinalReport.Add($(Get-HTMLContentDataTable $userphaventloggedonrecentlytable -HideFooter)) 1646 | $FinalReport.Add($(Get-HTMLContentClose)) 1647 | $FinalReport.Add($(Get-HTMLColumnClose)) 1648 | $FinalReport.Add($(Get-HTMLColumn2of2)) 1649 | $FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Accounts Created in $UserCreatedDays Days or Less")) 1650 | $FinalReport.Add($(Get-HTMLContentDataTable $NewCreatedUsersTable -HideFooter)) 1651 | $FinalReport.Add($(Get-HTMLContentClose)) 1652 | $FinalReport.Add($(Get-HTMLColumnClose)) 1653 | $FinalReport.Add($(Get-HTMLContentClose)) 1654 | 1655 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Security Logs")) 1656 | $FinalReport.Add($(Get-HTMLContentDataTable $securityeventtable -HideFooter)) 1657 | $FinalReport.Add($(Get-HTMLContentClose)) 1658 | 1659 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "UPN Suffixes")) 1660 | $FinalReport.Add($(Get-HTMLContentTable $DomainTable)) 1661 | $FinalReport.Add($(Get-HTMLContentClose)) 1662 | $FinalReport.Add($(Get-HTMLTabContentClose)) 1663 | 1664 | #Groups Report 1665 | $FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[1] -TabHeading ("Report: " + (Get-Date -Format MM-dd-yyyy)))) 1666 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Groups Overivew")) 1667 | $FinalReport.Add($(Get-HTMLContentTable $TOPGroupsTable -HideFooter)) 1668 | $FinalReport.Add($(Get-HTMLContentClose)) 1669 | 1670 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Active Directory Groups")) 1671 | $FinalReport.Add($(Get-HTMLContentDataTable $Table -HideFooter)) 1672 | $FinalReport.Add($(Get-HTMLContentClose)) 1673 | $FinalReport.Add($(Get-HTMLColumn1of2)) 1674 | 1675 | $FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText 'Domain Administrators')) 1676 | $FinalReport.Add($(Get-HTMLContentDataTable $DomainAdminTable -HideFooter)) 1677 | $FinalReport.Add($(Get-HTMLContentClose)) 1678 | $FinalReport.Add($(Get-HTMLColumnClose)) 1679 | $FinalReport.Add($(Get-HTMLColumn2of2)) 1680 | 1681 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText 'Enterprise Administrators')) 1682 | $FinalReport.Add($(Get-HTMLContentDataTable $EnterpriseAdminTable -HideFooter)) 1683 | $FinalReport.Add($(Get-HTMLContentClose)) 1684 | $FinalReport.Add($(Get-HTMLColumnClose)) 1685 | 1686 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Active Directory Groups Chart")) 1687 | $FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 1 -ColumnCount 4)) 1688 | $FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectGroupType -DataSet $GroupTypetable)) 1689 | $FinalReport.Add($(Get-HTMLColumnClose)) 1690 | $FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 2 -ColumnCount 4)) 1691 | $FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectGroupType2 -DataSet $DefaultGrouptable)) 1692 | $FinalReport.Add($(Get-HTMLColumnClose)) 1693 | $FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 3 -ColumnCount 4)) 1694 | $FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectGroupMembersType -DataSet $GroupMembershipTable)) 1695 | $FinalReport.Add($(Get-HTMLColumnClose)) 1696 | $FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 4 -ColumnCount 4)) 1697 | $FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectGroupProtection -DataSet $GroupProtectionTable)) 1698 | $FinalReport.Add($(Get-HTMLColumnClose)) 1699 | $FinalReport.Add($(Get-HTMLContentClose)) 1700 | $FinalReport.Add($(Get-HTMLTabContentClose)) 1701 | 1702 | #Organizational Unit Report 1703 | $FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[2] -TabHeading ("Report: " + (Get-Date -Format MM-dd-yyyy)))) 1704 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Organizational Units")) 1705 | $FinalReport.Add($(Get-HTMLContentDataTable $OUTable -HideFooter)) 1706 | $FinalReport.Add($(Get-HTMLContentClose)) 1707 | 1708 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Organizational Units Charts")) 1709 | $FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 1 -ColumnCount 2)) 1710 | $FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectOUGPOLinks -DataSet $OUGPOTable)) 1711 | $FinalReport.Add($(Get-HTMLColumnClose)) 1712 | $FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 2 -ColumnCount 2)) 1713 | $FinalReport.Add($(Get-HTMLPieChart -ChartObject $PO12 -DataSet $OUProtectionTable)) 1714 | $FinalReport.Add($(Get-HTMLColumnClose)) 1715 | $FinalReport.Add($(Get-HTMLContentclose)) 1716 | $FinalReport.Add($(Get-HTMLTabContentClose)) 1717 | 1718 | #Users Report 1719 | $FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[3] -TabHeading ("Report: " + (Get-Date -Format MM-dd-yyyy)))) 1720 | 1721 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Users Overivew")) 1722 | $FinalReport.Add($(Get-HTMLContentTable $TOPUserTable -HideFooter)) 1723 | $FinalReport.Add($(Get-HTMLContentClose)) 1724 | 1725 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Active Directory Users")) 1726 | $FinalReport.Add($(Get-HTMLContentDataTable $UserTable -HideFooter)) 1727 | $FinalReport.Add($(Get-HTMLContentClose)) 1728 | 1729 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Expiring Items")) 1730 | $FinalReport.Add($(Get-HTMLColumn1of2)) 1731 | $FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Users with Passwords Expiring in less than $DaysUntilPWExpireINT days")) 1732 | $FinalReport.Add($(Get-HTMLContentDataTable $PasswordExpireSoonTable -HideFooter)) 1733 | $FinalReport.Add($(Get-HTMLContentClose)) 1734 | $FinalReport.Add($(Get-HTMLColumnClose)) 1735 | $FinalReport.Add($(Get-HTMLColumn2of2)) 1736 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText 'Accounts Expiring Soon')) 1737 | $FinalReport.Add($(Get-HTMLContentDataTable $ExpiringAccountsTable -HideFooter)) 1738 | $FinalReport.Add($(Get-HTMLContentClose)) 1739 | $FinalReport.Add($(Get-HTMLColumnClose)) 1740 | $FinalReport.Add($(Get-HTMLContentClose)) 1741 | 1742 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Accounts")) 1743 | $FinalReport.Add($(Get-HTMLColumn1of2)) 1744 | $FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Users Haven't Logged on in $Days Days or more")) 1745 | $FinalReport.Add($(Get-HTMLContentDataTable $userphaventloggedonrecentlytable -HideFooter)) 1746 | $FinalReport.Add($(Get-HTMLContentClose)) 1747 | $FinalReport.Add($(Get-HTMLColumnClose)) 1748 | $FinalReport.Add($(Get-HTMLColumn2of2)) 1749 | 1750 | $FinalReport.Add($(Get-HTMLContentOpen -BackgroundShade 1 -HeaderText "Accounts Created in $UserCreatedDays Days or Less")) 1751 | $FinalReport.Add($(Get-HTMLContentDataTable $NewCreatedUsersTable -HideFooter)) 1752 | $FinalReport.Add($(Get-HTMLContentClose)) 1753 | $FinalReport.Add($(Get-HTMLColumnClose)) 1754 | $FinalReport.Add($(Get-HTMLContentClose)) 1755 | 1756 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Users Charts")) 1757 | $FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 1 -ColumnCount 3)) 1758 | $FinalReport.Add($(Get-HTMLPieChart -ChartObject $EnabledDisabledUsersPieObject -DataSet $EnabledDisabledUsersTable)) 1759 | $FinalReport.Add($(Get-HTMLColumnClose)) 1760 | $FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 2 -ColumnCount 3)) 1761 | $FinalReport.Add($(Get-HTMLPieChart -ChartObject $PWExpiresUsersTable -DataSet $PasswordExpirationTable)) 1762 | $FinalReport.Add($(Get-HTMLColumnClose)) 1763 | $FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 3 -ColumnCount 3)) 1764 | $FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectProtectedUsers -DataSet $ProtectedUsersTable)) 1765 | $FinalReport.Add($(Get-HTMLColumnClose)) 1766 | $FinalReport.Add($(Get-HTMLContentClose)) 1767 | $FinalReport.Add($(Get-HTMLTabContentClose)) 1768 | 1769 | #GPO Report 1770 | $FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[4] -TabHeading ("Report: " + (Get-Date -Format MM-dd-yyyy)))) 1771 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Group Policies")) 1772 | $FinalReport.Add($(Get-HTMLContentDataTable $GPOTable -HideFooter)) 1773 | $FinalReport.Add($(Get-HTMLContentClose)) 1774 | $FinalReport.Add($(Get-HTMLTabContentClose)) 1775 | 1776 | #Computers Report 1777 | $FinalReport.Add($(Get-HTMLTabContentopen -TabName $tabarray[5] -TabHeading ("Report: " + (Get-Date -Format MM-dd-yyyy)))) 1778 | 1779 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Computers Overivew")) 1780 | $FinalReport.Add($(Get-HTMLContentTable $TOPComputersTable -HideFooter)) 1781 | $FinalReport.Add($(Get-HTMLContentClose)) 1782 | 1783 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Computers")) 1784 | $FinalReport.Add($(Get-HTMLContentDataTable $ComputersTable -HideFooter)) 1785 | $FinalReport.Add($(Get-HTMLContentClose)) 1786 | 1787 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Computers Charts")) 1788 | $FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 1 -ColumnCount 2)) 1789 | $FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectComputersProtected -DataSet $ComputerProtectedTable)) 1790 | $FinalReport.Add($(Get-HTMLColumnClose)) 1791 | $FinalReport.Add($(Get-HTMLColumnOpen -ColumnNumber 2 -ColumnCount 2)) 1792 | $FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectComputersEnabled -DataSet $ComputersEnabledTable)) 1793 | $FinalReport.Add($(Get-HTMLColumnClose)) 1794 | $FinalReport.Add($(Get-HTMLContentclose)) 1795 | 1796 | $FinalReport.Add($(Get-HTMLContentOpen -HeaderText "Computers Operating System Breakdown")) 1797 | $FinalReport.Add($(Get-HTMLPieChart -ChartObject $PieObjectComputerObjOS -DataSet $GraphComputerOS)) 1798 | $FinalReport.Add($(Get-HTMLContentclose)) 1799 | 1800 | $FinalReport.Add($(Get-HTMLTabContentClose)) 1801 | $FinalReport.Add($(Get-HTMLClosePage)) 1802 | 1803 | $Day = (Get-Date).Day 1804 | $Month = (Get-Date).Month 1805 | $Year = (Get-Date).Year 1806 | $ReportName = ("$Day - $Month - $Year - AD Report") 1807 | 1808 | Save-HTMLReport -ReportContent $FinalReport -ShowReport -ReportName $ReportName -ReportPath $ReportSavePath 1809 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PSHTML-AD-Report 2 | 3 | While I walk you through the report, you can view it for yourself [here](https://thelazyadministrator.com/wp-content/uploads/2018/12/4-12-2018-ADReport.html) 4 | 5 | Interactive HTML report generated with PowerShell to give you an overview of your Active Directory enviornment. 6 | 7 | Requires ReportHTML module but will attempt to install on first run. Requires ActiveDirectory module to be present. 8 | 9 | [If you also want a VMWare report check out this fork](https://github.com/vhoudoverdov/PSHTML-AD-Report) 10 | 11 | ![Overview](https://thelazyadministrator.com/wp-content/uploads/2018/12/groups.png) 12 | 13 | While I walk you through the report, you can view it for yourself [here](https://thelazyadministrator.com/wp-content/uploads/2018/12/4-12-2018-ADReport.html) 14 | 15 | [Blog Link](https://thelazyadministrator.com/2018/12/04/get-an-active-directory-interactive-html-report-with-powershell/) 16 | 17 | ____ 18 | # Report Features 19 | 20 | ## Pie Graphs 21 | The Pie Charts will show you the value, and the count of what you are hovering over. 22 | 23 | ![Pie Graphs](https://thelazyadministrator.com/wp-content/uploads/2018/12/20181204_80611.gif) 24 | 25 | ## Searching 26 | In the top right corner of my table I can search my table for items. Below I just want to see all results with “Brad” 27 | ![Search](https://thelazyadministrator.com/wp-content/uploads/2018/12/search-1.gif) 28 | 29 | ## Header Ordering 30 | By clicking on a different header I can change the sorting of the data. Here I change the data to order it by “Enabled” status, then “Protected from Deletion” and finally “Name”. 31 | ![Header Ordering](https://thelazyadministrator.com/wp-content/uploads/2018/12/headings.gif) 32 | 33 | ____ 34 | 35 | # Dashboard 36 | 37 | ![Dashboard](https://thelazyadministrator.com/wp-content/uploads/2018/12/home.png) 38 | 39 | 40 | 41 | # Groups 42 | 43 | ![Groups](https://thelazyadministrator.com/wp-content/uploads/2018/12/groups-1.png) 44 | 45 | 46 | 47 | # OU's 48 | 49 | ![OUs](https://thelazyadministrator.com/wp-content/uploads/2018/12/OUS.png) 50 | 51 | 52 | 53 | # Users 54 | 55 | ![Users](https://thelazyadministrator.com/wp-content/uploads/2018/12/users.png) 56 | 57 | 58 | 59 | # Group Policy 60 | 61 | ![GPO](https://thelazyadministrator.com/wp-content/uploads/2018/12/gpos.png) 62 | 63 | 64 | # Computers 65 | 66 | ![Computers](https://thelazyadministrator.com/wp-content/uploads/2018/12/computers.png) 67 | 68 | --------------------------------------------------------------------------------