diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index 13308dd..fff8379 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -8,7 +8,7 @@ jobs: publish-to-gallery: runs-on: windows-2019 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set PSRepository to Trusted for PowerShell Gallery shell: pwsh run: | diff --git a/AsBuiltReport.Microsoft.AD.Style.ps1 b/AsBuiltReport.Microsoft.AD.Style.ps1 index 932c374..6e23d75 100644 --- a/AsBuiltReport.Microsoft.AD.Style.ps1 +++ b/AsBuiltReport.Microsoft.AD.Style.ps1 @@ -10,6 +10,7 @@ Style -Name 'Title 3' -Size 12 -Color '1F6BCF' -Align Left Style -Name 'Heading 1' -Size 16 -Color '0078D4' Style -Name 'Heading 2' -Size 14 -Color '00447C' Style -Name 'Heading 3' -Size 13 -Color '0081FF' +Style -Name 'NO TOC Heading 3' -Size 13 -Color '0081FF' Style -Name 'Heading 4' -Size 12 -Color '0077B7' Style -Name 'NO TOC Heading 4' -Size 12 -Color '0077B7' Style -Name 'Heading 5' -Size 11 -Color '1A9BA3' diff --git a/AsBuiltReport.Microsoft.AD.psd1 b/AsBuiltReport.Microsoft.AD.psd1 index 29be034..8feb5a5 100644 --- a/AsBuiltReport.Microsoft.AD.psd1 +++ b/AsBuiltReport.Microsoft.AD.psd1 @@ -12,7 +12,7 @@ RootModule = 'AsBuiltReport.Microsoft.AD.psm1' # Version number of this module. -ModuleVersion = '0.7.14' +ModuleVersion = '0.7.15' # Supported PSEditions # CompatiblePSEditions = @() @@ -117,7 +117,7 @@ PrivateData = @{ ProjectUri = 'https://github.com/AsBuiltReport/AsBuiltReport.Microsoft.AD' # A URL to an icon representing this module. - IconUri = 'https://raw.githubusercontent.com/AsBuiltReport/AsBuiltReport/master/AsBuiltReport.png' + IconUri = 'https://github.com/AsBuiltReport.png' # ReleaseNotes of this module ReleaseNotes = 'https://raw.githubusercontent.com/AsBuiltReport/AsBuiltReport.Microsoft.AD/master/CHANGELOG.md' diff --git a/CHANGELOG.md b/CHANGELOG.md index a9c6a94..4e0601b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # :arrows_clockwise: Microsoft AD As Built Report Changelog +## [0.7.15] - 2023-10-03 + +### Changed + +- Improved verbose logging +- Improved PKI Section + ## [0.7.14] - 2023-07-25 ### Fixed diff --git a/README.md b/README.md index a7caa13..4ffddfe 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

- +

@@ -85,7 +85,7 @@ This report does not support Linux or Mac due to the fact that the ActiveDirecto A Microsoft AD As Built Report can be generated with Active Directory Enterprise Forest level privileges. Since this report relies extensively on the WinRM component, you should make sure that it is enabled and configured. [Reference](https://docs.microsoft.com/en-us/windows/win32/winrm/installation-and-configuration-for-windows-remote-management) -Due to a limitation of the WinRM component, a domain-joined machine is needed, also it is required to use the FQDN of the DC instead of its IP address. +Due to a limitation of the WinRM component, a domain-joined machine is needed, also it is required to use the FQDN of the DC instead of it's IP address. [Reference](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_remote_troubleshooting?view=powershell-7.1#how-to-use-an-ip-address-in-a-remote-command) ## :package: Module Installation @@ -222,7 +222,7 @@ PS C:\> New-AsBuiltReport -Report Microsoft.AD -Target 'admin-dc-01v.contoso.loc - Issues with WinRM when using the IP address instead of the "Fully Qualified Domain Name". - This project relies heavily on the remote connection function through WinRM. For this reason the use of a Windows 10 client is specifically used as a jumpbox. -- The report provides the ability to extract the configuration of the DHCP/DNS services. In order to obtain this information it is required that the servers running these services have powershell modules installed for each service (RSAT-DNS-Server & RSAT-AD-PowerShell). +- The report provides the ability to extract the configuration of the DNS services. In order to obtain this information it is required that the servers running these services have powershell modules installed for each service (RSAT-DNS-Server & RSAT-AD-PowerShell). - This report assumes that the DNS Server service is running on the same server where Domain Controller is running (Cohost). - In some cases when trying to update the report, an error similar to this is generated: - "PackageManagement\Install-Package : Authenticode issuer 'CN="xyz, INC.", O="xyz, INC.", L=San Jose, S=California on the previusly-installed module 'PSPKI'. If you still want to install or update, use -SkipPublisherCheck parameter." diff --git a/Src/Private/Get-AbrADCAAIA.ps1 b/Src/Private/Get-AbrADCAAIA.ps1 index 2f89ddc..602a41f 100644 --- a/Src/Private/Get-AbrADCAAIA.ps1 +++ b/Src/Private/Get-AbrADCAAIA.ps1 @@ -5,7 +5,7 @@ function Get-AbrADCAAIA { .DESCRIPTION .NOTES - Version: 0.7.13 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -28,7 +28,7 @@ function Get-AbrADCAAIA { process { if ($CA) { - Section -Style Heading4 "Authority Information Access (AIA)" { + Section -Style Heading3 "Authority Information Access (AIA)" { Paragraph "The following section provides the Certification Authority Authority Information Access information." BlankLine try { diff --git a/Src/Private/Get-AbrADCACRLSetting.ps1 b/Src/Private/Get-AbrADCACRLSetting.ps1 index 9a8f95c..20ea08a 100644 --- a/Src/Private/Get-AbrADCACRLSetting.ps1 +++ b/Src/Private/Get-AbrADCACRLSetting.ps1 @@ -5,7 +5,7 @@ function Get-AbrADCACRLSetting { .DESCRIPTION .NOTES - Version: 0.7.13 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -28,10 +28,10 @@ function Get-AbrADCACRLSetting { process { try { - Section -Style Heading4 "Certificate Revocation List (CRL)" { + Section -Style Heading3 "Certificate Revocation List (CRL)" { Paragraph "The following section provides the Certification Authority CRL Distribution Point information." BlankLine - Section -Style Heading5 "CRL Validity Period" { + Section -Style Heading4 "CRL Validity Period" { $OutObj = @() try { Write-PscriboMessage "Collecting AD CA CRL Validity Period information on $($CA.Name)." @@ -67,7 +67,7 @@ function Get-AbrADCACRLSetting { $OutObj | Sort-Object -Property 'CA Name' | Table @TableParams } try { - Section -Style Heading5 "CRL Flags Settings" { + Section -Style Heading4 "CRL Flags Settings" { $OutObj = @() try { Write-PscriboMessage "Collecting AD CA CRL Distribution Point information on $($CA.Name)." @@ -105,7 +105,7 @@ function Get-AbrADCACRLSetting { Write-PscriboMessage -IsWarning "CRL Validity Period Section: $($_.Exception.Message)" } try { - Section -Style Heading5 "CRL Distribution Point" { + Section -Style Heading4 "CRL Distribution Point" { Paragraph "The following section provides the Certification Authority CRL Distribution Point information." BlankLine try { @@ -157,7 +157,7 @@ function Get-AbrADCACRLSetting { Write-PscriboMessage -IsWarning "$($_.Exception.Message) (CRL Distribution Point)" } try { - Section -Style Heading4 "AIA and CDP Health Status" { + Section -Style Heading3 "AIA and CDP Health Status" { Paragraph "The following section is intended to perform Certification Authority health status checking by CA certificate chain status and validating all CRL Distribution Point (CDP) and Authority Information Access (AIA) URLs for each certificate in the chain." BlankLine $OutObj = @() diff --git a/Src/Private/Get-AbrADCACryptographyConfig.ps1 b/Src/Private/Get-AbrADCACryptographyConfig.ps1 index 73d858f..545e238 100644 --- a/Src/Private/Get-AbrADCACryptographyConfig.ps1 +++ b/Src/Private/Get-AbrADCACryptographyConfig.ps1 @@ -5,7 +5,7 @@ function Get-AbrADCACryptographyConfig { .DESCRIPTION .NOTES - Version: 0.7.9 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -30,7 +30,7 @@ function Get-AbrADCACryptographyConfig { if ($CA) { $CryptoConfig = Get-CACryptographyConfig -CertificationAuthority $CA if ($CryptoConfig) { - Section -Style Heading4 "Cryptography Configuration" { + Section -Style Heading3 "Cryptography Configuration" { Paragraph "The following section provides the Certification Authority Cryptography Configuration information." BlankLine $OutObj = @() diff --git a/Src/Private/Get-AbrADCAKeyRecoveryAgent.ps1 b/Src/Private/Get-AbrADCAKeyRecoveryAgent.ps1 index 7efc814..760d92b 100644 --- a/Src/Private/Get-AbrADCAKeyRecoveryAgent.ps1 +++ b/Src/Private/Get-AbrADCAKeyRecoveryAgent.ps1 @@ -5,7 +5,7 @@ function Get-AbrADCAKeyRecoveryAgent { .DESCRIPTION .NOTES - Version: 0.7.9 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -31,7 +31,6 @@ function Get-AbrADCAKeyRecoveryAgent { try { $KRA = Get-CAKRACertificate -CertificationAuthority $CA if ($KRA.Certificate) { - Write-PscriboMessage "Collecting Key Recovery Agent Certificate Certificate information of $($KRA.DisplayName)." $inObj = [ordered] @{ 'CA Name' = $KRA.DisplayName 'Server Name' = $KRA.ComputerName.ToString().ToUpper().Split(".")[0] @@ -45,7 +44,7 @@ function Get-AbrADCAKeyRecoveryAgent { } if ($OutObj) { - Section -Style Heading4 "Key Recovery Agent Certificate" { + Section -Style Heading3 "Key Recovery Agent Certificate" { Paragraph "The following section provides the Key Recovery Agent certificate used to encrypt user's certificate private key and store it in CA database. In the case when user cannot access his or her certificate private key it is possible to recover it by Key Recovery Agent if Key Archival procedure was taken against particular certificate." BlankLine foreach ($Item in $OutObj) { diff --git a/Src/Private/Get-AbrADCARoot.ps1 b/Src/Private/Get-AbrADCARoot.ps1 index c5cbe3a..852c823 100644 --- a/Src/Private/Get-AbrADCARoot.ps1 +++ b/Src/Private/Get-AbrADCARoot.ps1 @@ -5,7 +5,7 @@ function Get-AbrADCARoot { .DESCRIPTION .NOTES - Version: 0.7.9 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -24,10 +24,8 @@ function Get-AbrADCARoot { process { try { - Write-PscriboMessage "Discovering Active Directory Certification Authority information in $($ForestInfo.toUpper())." - Write-PscriboMessage "Discovered '$(($CAs | Measure-Object).Count)' Active Directory Certification Authority in domain $ForestInfo." if ($CAs | Where-Object {$_.IsRoot -like 'True'}) { - Section -Style Heading3 "Enterprise Root Certificate Authority" { + Section -Style Heading2 "Enterprise Root Certificate Authority" { Paragraph "The following section provides the Enterprise Root CA information." BlankLine $OutObj = @() @@ -40,6 +38,9 @@ function Get-AbrADCARoot { 'Config String' = $CA.ConfigString 'Operating System' = $CA.OperatingSystem 'Certificate' = $CA.Certificate + 'Auditing' = &{ + (Find-AuditingIssue -ADCSObjects (Get-ADCSObject $ForestInfo) | Where-Object {$_.Name -eq $CA.DisplayName}).Issue + } 'Status' = $CA.ServiceStatus } $OutObj += [pscustomobject]$inobj @@ -47,6 +48,7 @@ function Get-AbrADCARoot { if ($HealthCheck.CA.Status) { $OutObj | Where-Object { $_.'Service Status' -notlike 'Running'} | Set-Style -Style Critical -Property 'Service Status' + $OutObj | Where-Object { $_.'Auditing' -notlike 'Running'} | Set-Style -Style Critical -Property 'Auditing' } $TableParams = @{ diff --git a/Src/Private/Get-AbrADCASecurity.ps1 b/Src/Private/Get-AbrADCASecurity.ps1 index c236508..ca10db9 100644 --- a/Src/Private/Get-AbrADCASecurity.ps1 +++ b/Src/Private/Get-AbrADCASecurity.ps1 @@ -5,7 +5,7 @@ function Get-AbrADCASecurity { .DESCRIPTION .NOTES - Version: 0.7.9 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -31,7 +31,7 @@ function Get-AbrADCASecurity { try { $CFP = Get-CertificateValidityPeriod -CertificationAuthority $CA if ($CFP) { - Section -Style Heading4 "Certificate Validity Period" { + Section -Style Heading3 "Certificate Validity Period" { Paragraph "The following section provides the Certification Authority Certificate Validity Period information." BlankLine $OutObj = @() @@ -66,7 +66,7 @@ function Get-AbrADCASecurity { try { $ACLs = Get-CertificationAuthorityAcl -CertificationAuthority $CA if ($ACLs) { - Section -Style Heading5 "Access Control List (ACL)" { + Section -Style Heading4 "Access Control List (ACL)" { $OutObj = @() try { Write-PscriboMessage "Collecting Certification Authority Access Control List information of $($CA.Name)." @@ -98,7 +98,7 @@ function Get-AbrADCASecurity { } $OutObj | Sort-Object -Property 'DC Name' | Table @TableParams try { - Section -Style Heading6 "Access Rights" { + Section -Style Heading5 "Access Rights" { $OutObj = @() Write-PscriboMessage "Collecting AD Certification Authority Access Control List information of $($CA.Name)." foreach ($ACL in $ACLs.Access) { diff --git a/Src/Private/Get-AbrADCASubordinate.ps1 b/Src/Private/Get-AbrADCASubordinate.ps1 index 884f291..a5d014a 100644 --- a/Src/Private/Get-AbrADCASubordinate.ps1 +++ b/Src/Private/Get-AbrADCASubordinate.ps1 @@ -5,7 +5,7 @@ function Get-AbrADCASubordinate { .DESCRIPTION .NOTES - Version: 0.7.9 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -24,10 +24,10 @@ function Get-AbrADCASubordinate { process { try { - Write-PscriboMessage "Discovering Active Directory Certification Authority information in $($ForestInfo.toUpper())." + Write-PscriboMessage "Discovering Active Directory CA Enterprise Subordinate information in $($ForestInfo.toUpper())." if ($CAs | Where-Object {$_.IsRoot -like 'False'}) { Write-PscriboMessage "Discovered '$(($CAs | Measure-Object).Count)' Active Directory Certification Authority in domain $ForestInfo." - Section -Style Heading3 "Enterprise Subordinate Certificate Authority" { + Section -Style Heading2 "Enterprise Subordinate Certificate Authority" { Paragraph "The following section provides the Enterprise Subordinate CA information." BlankLine $OutObj = @() @@ -41,12 +41,16 @@ function Get-AbrADCASubordinate { 'Config String' = $CA.ConfigString 'Operating System' = $CA.OperatingSystem 'Certificate' = $CA.Certificate + 'Auditing' = &{ + (Find-AuditingIssue -ADCSObjects (Get-ADCSObject $ForestInfo) | Where-Object {$_.Name -eq $CA.DisplayName}).Issue + } 'Status' = $CA.ServiceStatus } $OutObj = [pscustomobject]$inobj if ($HealthCheck.CA.Status) { $OutObj | Where-Object { $_.'Service Status' -notlike 'Running'} | Set-Style -Style Critical -Property 'Service Status' + $OutObj | Where-Object { $_.'Auditing' -notlike 'Running'} | Set-Style -Style Critical -Property 'Auditing' } $TableParams = @{ diff --git a/Src/Private/Get-AbrADCASummary.ps1 b/Src/Private/Get-AbrADCASummary.ps1 index f0ff697..ca9e35c 100644 --- a/Src/Private/Get-AbrADCASummary.ps1 +++ b/Src/Private/Get-AbrADCASummary.ps1 @@ -25,9 +25,7 @@ function Get-AbrADCASummary { process { $OutObj = @() if ($ForestInfo) { - Write-PscriboMessage "Discovering Active Directory Certification Authority information in $($ForestInfo.toUpper())." foreach ($CA in $CAs) { - Write-PscriboMessage "Discovered '$(($CAs | Measure-Object).Count)' Active Directory Certification Authority in domain $ForestInfo." try { Write-PscriboMessage "Collecting AD Certification Authority Summary information of $($CA.DisplayName)." $inObj = [ordered] @{ diff --git a/Src/Private/Get-AbrADCATemplate.ps1 b/Src/Private/Get-AbrADCATemplate.ps1 index 0e86981..e7b1619 100644 --- a/Src/Private/Get-AbrADCATemplate.ps1 +++ b/Src/Private/Get-AbrADCATemplate.ps1 @@ -5,7 +5,7 @@ function Get-AbrADCATemplate { .DESCRIPTION .NOTES - Version: 0.7.9 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -30,7 +30,7 @@ function Get-AbrADCATemplate { $Templates = Get-CATemplate -CertificationAuthority $CA.ComputerName | Select-Object -ExpandProperty Templates if ($Templates) { try { - Section -Style Heading4 "Certificate Template Summary" { + Section -Style Heading3 "Certificate Template Summary" { Paragraph "The following section provides the certificate templates that are assigned to a specified Certification Authority (CA). CA server can issue certificates only based on assigned templates." BlankLine $OutObj = @() @@ -61,14 +61,14 @@ function Get-AbrADCATemplate { $OutObj | Sort-Object -Property 'Template Name' | Table @TableParams if ($InfoLevel.CA -ge 3) { try { - Section -Style Heading5 "Issued Certificate Template ACLs" { + Section -Style Heading4 "Issued Certificate Template ACLs" { Paragraph "The following section provides the certificate templates Access Control List that are assigned to a specified Certification Authority (CA)." BlankLine foreach ($Template in $Templates) { try { $Rights = Get-CertificateTemplateAcl -Template $Template.Name | Select-Object -ExpandProperty Access if ($Rights) { - Section -ExcludeFromTOC -Style NOTOCHeading6 "$($Template.DisplayName)" { + Section -ExcludeFromTOC -Style NOTOCHeading5 "$($Template.DisplayName)" { $OutObj = @() foreach ($Right in $Rights) { try { @@ -110,11 +110,10 @@ function Get-AbrADCATemplate { try { $Templates = Get-CertificateTemplate if ($Templates) { - Section -Style Heading5 "Certificate Template In Active Directory" { + Section -Style Heading4 "Certificate Template In Active Directory" { Paragraph "The following section provides registered certificate templates from Active Directory." BlankLine $OutObj = @() - Write-PscriboMessage "Discovered '$(($Templates | Measure-Object).Count)' Certification Authority Template in domain $ForestInfo." foreach ($Template in $Templates) { try { Write-PscriboMessage "Collecting $($Template.DisplayName) Certificate Template In Active Directory." diff --git a/Src/Private/Get-AbrADDCDiag.ps1 b/Src/Private/Get-AbrADDCDiag.ps1 index c3701cd..c65d6ff 100644 --- a/Src/Private/Get-AbrADDCDiag.ps1 +++ b/Src/Private/Get-AbrADDCDiag.ps1 @@ -5,7 +5,7 @@ function Get-AbrADDCDiag { .DESCRIPTION .NOTES - Version: 0.7.7 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -32,10 +32,9 @@ function Get-AbrADDCDiag { process { if ($DC) { try { - Write-PscriboMessage "Discovering Active Directory DCDiag information for DC $DC." $DCDIAG = Invoke-DcDiag -DomainController $DC if ($DCDIAG) { - Section -ExcludeFromTOC -Style NOTOCHeading5 $($DC.ToString().split('.')[0].ToUpper()) { + Section -ExcludeFromTOC -Style NOTOCHeading4 $($DC.ToString().split('.')[0].ToUpper()) { $OutObj = @() $Description = @{ "Advertising" = "Validates this Domain Controller can be correctly located through the KDC service. It does not validate the Kerberos tickets answer or the communication through the TCP and UDP port 88.", 'High' @@ -90,6 +89,8 @@ function Get-AbrADDCDiag { } $OutObj | Sort-Object -Property 'Entity' | Table @TableParams } + } else { + Write-PscriboMessage -IsWarning "No DCDiag information found in $DC, disabling the section." } } catch { diff --git a/Src/Private/Get-AbrADDCRoleFeature.ps1 b/Src/Private/Get-AbrADDCRoleFeature.ps1 index 1881067..d3acbdc 100644 --- a/Src/Private/Get-AbrADDCRoleFeature.ps1 +++ b/Src/Private/Get-AbrADDCRoleFeature.ps1 @@ -5,7 +5,7 @@ function Get-AbrADDCRoleFeature { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -28,12 +28,10 @@ function Get-AbrADDCRoleFeature { } process { - Write-PscriboMessage "Collecting AD Domain Controller Role & Features information for domain $Domain" try { $DCPssSession = New-PSSession $DC -Credential $Credential -Authentication $Options.PSDefaultAuthentication -Name 'ADDCRoleFeature' if ($DCPssSession) { - Write-PscriboMessage "Discovered Active Directory DC Role & Features information of $DC." - Section -ExcludeFromTOC -Style NOTOCHeading6 $($DC.ToString().ToUpper().Split(".")[0]) { + Section -ExcludeFromTOC -Style NOTOCHeading5 $($DC.ToString().ToUpper().Split(".")[0]) { $OutObj = @() $Features = Invoke-Command -Session $DCPssSession -ScriptBlock {Get-WindowsFeature | Where-Object {$_.installed -eq "True" -and $_.FeatureType -eq 'Role'}} Remove-PSSession -Session $DCPssSession @@ -53,9 +51,7 @@ function Get-AbrADDCRoleFeature { } if ($HealthCheck.DomainController.BestPractice) { - $OutObj | Where-Object {$_.'Name' -notin @('Active Directory Domain Services','DNS Server','File and Storage Services','DHCP Server')} | Set-Style -Style Warning - } $TableParams = @{ diff --git a/Src/Private/Get-AbrADDFSHealth.ps1 b/Src/Private/Get-AbrADDFSHealth.ps1 index bcaf560..2fb4eaa 100644 --- a/Src/Private/Get-AbrADDFSHealth.ps1 +++ b/Src/Private/Get-AbrADDFSHealth.ps1 @@ -5,7 +5,7 @@ function Get-AbrADDFSHealth { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -35,13 +35,12 @@ function Get-AbrADDFSHealth { } Else {$DFS = Get-WinADDFSHealth -Domain $Domain -Credential $Credential} Write-PscriboMessage "Discovered AD Domain DFS Health information from $Domain." if ($DFS) { - Section -ExcludeFromTOC -Style NOTOCHeading5 'Sysvol Replication Status' { + Section -ExcludeFromTOC -Style NOTOCHeading4 'Sysvol Replication Status' { Paragraph "The following section details the sysvol folder replication status for Domain $($Domain.ToString().ToUpper())." BlankLine $OutObj = @() foreach ($DCStatus in $DFS) { try { - Write-PscriboMessage "Collecting DFS information from $($Domain)." $inObj = [ordered] @{ 'DC Name' = $DCStatus.DomainController 'Replication Status' = $DCStatus.ReplicationState @@ -96,6 +95,8 @@ function Get-AbrADDFSHealth { BlankLine } } + } else { + Write-PscriboMessage -IsWarning "No DFS information found in $Domain, disabling the section." } } catch { @@ -113,7 +114,7 @@ function Get-AbrADDFSHealth { 'TotalSize'= '{0:N2}' -f ((($_.group | Measure-Object length -Sum).Sum) /1MB) } } | Sort-Object -Descending -Property 'Totalsize'} if ($SYSVOLFolder) { - Section -ExcludeFromTOC -Style NOTOCHeading5 'Sysvol Content Status' { + Section -ExcludeFromTOC -Style NOTOCHeading4 'Sysvol Content Status' { Paragraph "The following section details domain $($Domain.ToString().ToUpper()) sysvol health status." BlankLine $OutObj = @() @@ -155,6 +156,8 @@ function Get-AbrADDFSHealth { } } } + } else { + Write-PscriboMessage -IsWarning "No SYSVOL folder information found in $Domain, disabling the section." } if ($DCPssSession) { Remove-PSSession -Session $DCPssSession @@ -175,7 +178,7 @@ function Get-AbrADDFSHealth { 'TotalSize'= '{0:N2}' -f ((($_.group | Measure-Object length -Sum).Sum) /1MB) } } | Sort-Object -Descending -Property 'Totalsize'} if ($NetlogonFolder) { - Section -ExcludeFromTOC -Style NOTOCHeading5 'Netlogon Content Status' { + Section -ExcludeFromTOC -Style NOTOCHeading4 'Netlogon Content Status' { Paragraph "The following section details domain $($Domain.ToString().ToUpper()) netlogon health status." BlankLine $OutObj = @() @@ -217,6 +220,8 @@ function Get-AbrADDFSHealth { } } } + } else { + Write-PscriboMessage -IsWarning "No NETLOGON folder information found in $Domain, disabling the section." } if ($DCPssSession) { Remove-PSSession -Session $DCPssSession diff --git a/Src/Private/Get-AbrADDNSInfrastructure.ps1 b/Src/Private/Get-AbrADDNSInfrastructure.ps1 index a6a77fc..3fd6487 100644 --- a/Src/Private/Get-AbrADDNSInfrastructure.ps1 +++ b/Src/Private/Get-AbrADDNSInfrastructure.ps1 @@ -5,7 +5,7 @@ function Get-AbrADDNSInfrastructure { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -31,7 +31,7 @@ function Get-AbrADDNSInfrastructure { try { $DCs = Invoke-Command -Session $TempPssSession {Get-ADDomain -Identity $using:Domain | Select-Object -ExpandProperty ReplicaDirectoryServers | Where-Object {$_ -notin ($using:Options).Exclude.DCs}} if ($DCs) { - Section -Style Heading4 "Infrastructure Summary" { + Section -Style Heading3 "Infrastructure Summary" { Paragraph "The following section provides a summary of the DNS Infrastructure configuration." BlankLine $OutObj = @() @@ -70,12 +70,12 @@ function Get-AbrADDNSInfrastructure { #---------------------------------------------------------------------------------------------# if ($InfoLevel.DNS -ge 2) { try { - Section -Style Heading5 "Application Directory Partition" { + Section -Style Heading4 "Application Directory Partition" { Paragraph "The following section provides Directory Partition information." BlankLine foreach ($DC in $DCs) { if (Test-Connection -ComputerName $DC -Quiet -Count 2) { - Section -ExcludeFromTOC -Style NOTOCHeading6 $($DC.ToString().ToUpper().Split(".")[0]) { + Section -ExcludeFromTOC -Style NOTOCHeading5 $($DC.ToString().ToUpper().Split(".")[0]) { $OutObj = @() Write-PscriboMessage "Collecting Directory Partition information from $($DC)." try { @@ -129,7 +129,7 @@ function Get-AbrADDNSInfrastructure { #---------------------------------------------------------------------------------------------# if ($InfoLevel.DNS -ge 2) { try { - Section -Style Heading5 "Response Rate Limiting (RRL)" { + Section -Style Heading4 "Response Rate Limiting (RRL)" { $OutObj = @() foreach ($DC in $DCs) { if (Test-Connection -ComputerName $DC -Quiet -Count 2) { @@ -174,7 +174,7 @@ function Get-AbrADDNSInfrastructure { #---------------------------------------------------------------------------------------------# if ($InfoLevel.DNS -ge 2) { try { - Section -Style Heading5 "Scavenging Options" { + Section -Style Heading4 "Scavenging Options" { $OutObj = @() foreach ($DC in $DCs) { if (Test-Connection -ComputerName $DC -Quiet -Count 2) { @@ -236,7 +236,7 @@ function Get-AbrADDNSInfrastructure { # DNS Forwarder Section # #---------------------------------------------------------------------------------------------# try { - Section -Style Heading5 "Forwarder Options" { + Section -Style Heading4 "Forwarder Options" { $OutObj = @() foreach ($DC in $DCs) { if (Test-Connection -ComputerName $DC -Quiet -Count 2) { @@ -306,12 +306,12 @@ function Get-AbrADDNSInfrastructure { #---------------------------------------------------------------------------------------------# if ($InfoLevel.DNS -ge 2) { try { - Section -Style Heading5 "Root Hints" { + Section -Style Heading4 "Root Hints" { Paragraph "The following section provides Root Hints information from domain $($Domain)." BlankLine foreach ($DC in $DCs) { if (Test-Connection -ComputerName $DC -Quiet -Count 2) { - Section -ExcludeFromTOC -Style NOTOCHeading6 $($DC.ToString().ToUpper().Split(".")[0]) { + Section -ExcludeFromTOC -Style NOTOCHeading5 $($DC.ToString().ToUpper().Split(".")[0]) { $OutObj = @() Write-PscriboMessage "Collecting Root Hint information from $($DC)." try { @@ -396,7 +396,7 @@ function Get-AbrADDNSInfrastructure { if (($OutObj | Where-Object { $_.'IPv4 Address'.Count -gt 1 }) -or ($OutObj | Where-Object { $_.'IPv6 Address'.Count -gt 1 })) { Paragraph { Text "Corrective Actions:" -Bold - Text "Duplicate IP Address found in the talbe of the DNS root hints servers. The DNS console does not show the duplicate Root Hint servers; you can only see them using the DNS PowerShell cmdlets. While there is a dnscmd utility to replace the Root Hints file, Using PowerShell is the best way to remediate this issue." + Text "Duplicate IP Address found in the table of the DNS root hints servers. The DNS console does not show the duplicate Root Hint servers; you can only see them using the DNS PowerShell cmdlets. While there is a dnscmd utility to replace the Root Hints file, Using PowerShell is the best way to remediate this issue." } } } @@ -414,7 +414,7 @@ function Get-AbrADDNSInfrastructure { #---------------------------------------------------------------------------------------------# if ($InfoLevel.DNS -ge 2) { try { - Section -Style Heading5 "Zone Scope Recursion" { + Section -Style Heading4 "Zone Scope Recursion" { $OutObj = @() foreach ($DC in $DCs) { if (Test-Connection -ComputerName $DC -Quiet -Count 2) { @@ -463,4 +463,4 @@ function Get-AbrADDNSInfrastructure { end {} -} \ No newline at end of file +} diff --git a/Src/Private/Get-AbrADDNSZone.ps1 b/Src/Private/Get-AbrADDNSZone.ps1 index 0a1a6c8..b90d1df 100644 --- a/Src/Private/Get-AbrADDNSZone.ps1 +++ b/Src/Private/Get-AbrADDNSZone.ps1 @@ -5,7 +5,7 @@ function Get-AbrADDNSZone { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -33,7 +33,7 @@ function Get-AbrADDNSZone { try { $DNSSetting = Get-DnsServerZone -CimSession $TempCIMSession -ComputerName $DC | Where-Object {$_.IsReverseLookupZone -like "False" -and $_.ZoneType -notlike "Forwarder"} if ($DNSSetting) { - Section -Style Heading4 "$($DC.ToString().ToUpper().Split(".")[0]) DNS Zones" { + Section -Style Heading3 "$($DC.ToString().ToUpper().Split(".")[0]) DNS Zones" { $OutObj = @() Write-PscriboMessage "Discovered Actve Directory Domain Controller: $DC. (Domain Name System Zone)" foreach ($Zones in $DNSSetting) { @@ -88,16 +88,20 @@ function Get-AbrADDNSZone { Write-PscriboMessage -IsWarning $($_.Exception.Message) } } + } else { + Write-PscriboMessage -IsWarning "No Zone Delegation information found, disabling the section." } } catch { Write-PscriboMessage -IsWarning "$($_.Exception.Message) (Zone Delegation Item)" } } + } else { + Write-PscriboMessage -IsWarning "No Zone Delegation information found in $DC, disabling the section." } if ($OutObj) { - Section -Style Heading5 "Zone Delegation" { + Section -Style Heading4 "Zone Delegation" { $TableParams = @{ Name = "Zone Delegations - $($Domain.ToString().ToUpper())" @@ -120,7 +124,7 @@ function Get-AbrADDNSZone { try { $DNSSetting = Invoke-Command -Session $DCPssSession {Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DNS Server\Zones\*" | Get-ItemProperty | Where-Object {$_ -match 'SecondaryServers'}} if ($DNSSetting) { - Section -Style Heading5 "Zone Transfers" { + Section -Style Heading4 "Zone Transfers" { $OutObj = @() foreach ($Zone in $DNSSetting) { try { @@ -166,6 +170,8 @@ function Get-AbrADDNSZone { } } } + } else { + Write-PscriboMessage -IsWarning "No Zone Transfer information found in $DC, disabling the section." } } catch { @@ -175,7 +181,7 @@ function Get-AbrADDNSZone { try { $DNSSetting = Get-DnsServerZone -CimSession $TempCIMSession -ComputerName $DC | Where-Object {$_.IsReverseLookupZone -like "True"} if ($DNSSetting) { - Section -Style Heading5 "Reverse Lookup Zone" { + Section -Style Heading4 "Reverse Lookup Zone" { $OutObj = @() Write-PscriboMessage "Discovered Actve Directory Domain Controller: $DC (Domain Name System Zone)" foreach ($Zones in $DNSSetting) { @@ -207,6 +213,8 @@ function Get-AbrADDNSZone { } $OutObj | Sort-Object -Property 'Zone Name' | Table @TableParams } + } else { + Write-PscriboMessage -IsWarning "No Reverse lookup zone information found in $DC, disabling the section." } } catch { @@ -215,7 +223,7 @@ function Get-AbrADDNSZone { try { $DNSSetting = Get-DnsServerZone -CimSession $TempCIMSession -ComputerName $DC | Where-Object {$_.IsReverseLookupZone -like "False" -and $_.ZoneType -like "Forwarder"} if ($DNSSetting) { - Section -Style Heading5 "Conditional Forwarder" { + Section -Style Heading4 "Conditional Forwarder" { $OutObj = @() Write-PscriboMessage "Discovered Actve Directory Domain Controller: $DC. (Domain Name System Conditional Forwarder)" foreach ($Zones in $DNSSetting) { @@ -245,6 +253,8 @@ function Get-AbrADDNSZone { } $OutObj | Sort-Object -Property 'Zone Name' | Table @TableParams } + } else { + Write-PscriboMessage -IsWarning "No Conditional forwarder zone information found in $DC, disabling the section." } } catch { @@ -256,7 +266,7 @@ function Get-AbrADDNSZone { $DNSSetting = Get-DnsServerZone -CimSession $TempCIMSession -ComputerName $DC | Where-Object {$_.IsReverseLookupZone -like "False" -and $_.ZoneType -eq "Primary"} | Select-Object -ExpandProperty ZoneName $Zones = Get-DnsServerZoneAging -CimSession $TempCIMSession -Name $DNSSetting -ComputerName $DC if ($Zones) { - Section -Style Heading5 "Zone Scope Aging" { + Section -Style Heading4 "Zone Scope Aging" { $OutObj = @() foreach ($Settings in $Zones) { try { @@ -300,6 +310,8 @@ function Get-AbrADDNSZone { } } } + } else { + Write-PscriboMessage -IsWarning "No Zone Aging property information found in $DC, disabling the section." } } catch { diff --git a/Src/Private/Get-AbrADDomainController.ps1 b/Src/Private/Get-AbrADDomainController.ps1 index 9a57d73..6a2a059 100644 --- a/Src/Private/Get-AbrADDomainController.ps1 +++ b/Src/Private/Get-AbrADDomainController.ps1 @@ -5,7 +5,7 @@ function Get-AbrADDomainController { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -83,10 +83,9 @@ function Get-AbrADDomainController { try { Write-PscriboMessage "Collecting AD Domain Controller Hardware information for domain $Domain" - Section -Style Heading5 'Hardware Inventory' { + Section -Style Heading4 'Hardware Inventory' { Paragraph "The following section provides detailed Domain Controller hardware information for domain $($Domain.ToString().ToUpper())." BlankLine - Write-PscriboMessage "Discovering Active Directory Domain Controller information in $Domain." $DCHWInfo = @() foreach ($DC in $DCs) { if (Test-Connection -ComputerName $DC -Quiet -Count 2) { @@ -133,7 +132,7 @@ function Get-AbrADDomainController { if ($InfoLevel.Domain -ge 2) { foreach ($DCHW in $DCHWInfo) { - Section -ExcludeFromTOC -Style NOTOCHeading6 $($DCHW.Name.ToString().ToUpper()) { + Section -ExcludeFromTOC -Style NOTOCHeading5 $($DCHW.Name.ToString().ToUpper()) { if ($HealthCheck.DomainController.Diagnostic) { if ([int]([regex]::Matches($DCHW.'Physical Memory', "\d+(\.*\d+)").value) -lt 8) { $DCHW | Set-Style -Style Warning -Property 'Physical Memory' @@ -182,7 +181,7 @@ function Get-AbrADDomainController { Text "Best Practice:" -Bold Text "Microsoft recommend putting enough RAM 8GB+ to load the entire DIT into memory, plus accommodate the operating system and other installed applications, such as anti-virus, backup software, monitoring, and so on." } - } + } } } } @@ -194,7 +193,7 @@ function Get-AbrADDomainController { # DNS IP Section # #---------------------------------------------------------------------------------------------# try { - Section -Style Heading5 "DNS IP Configuration" { + Section -Style Heading4 "DNS IP Configuration" { $OutObj = @() foreach ($DC in $DCs) { if (Test-Connection -ComputerName $DC -Quiet -Count 2) { @@ -295,9 +294,8 @@ function Get-AbrADDomainController { try { Write-PscriboMessage "Collecting AD Domain Controller NTDS information." - Section -Style Heading5 'NTDS Information' { + Section -Style Heading4 'NTDS Information' { $OutObj = @() - Write-PscriboMessage "Discovering Active Directory Domain Controller information in $Domain." foreach ($DC in $DCs) { if (Test-Connection -ComputerName $DC -Quiet -Count 2) { try { @@ -341,9 +339,8 @@ function Get-AbrADDomainController { } try { Write-PscriboMessage "Collecting AD Domain Controller Time Source information." - Section -Style Heading5 'Time Source Information' { + Section -Style Heading4 'Time Source Information' { $OutObj = @() - Write-PscriboMessage "Discovering Active Directory Domain Controller information in $Domain." foreach ($DC in $DCs) { if (Test-Connection -ComputerName $DC -Quiet -Count 2) { try { @@ -398,7 +395,7 @@ function Get-AbrADDomainController { if ($HealthCheck.DomainController.Diagnostic) { try { Write-PscriboMessage "Collecting AD Domain Controller SRV Records Status." - Section -Style Heading5 'SRV Records Status' { + Section -Style Heading4 'SRV Records Status' { $OutObj = @() Write-PscriboMessage "Discovering Active Directory Domain Controller SRV Records Status in $Domain." foreach ($DC in $DCs) { @@ -520,7 +517,7 @@ function Get-AbrADDomainController { $DCPssSession = New-PSSession $DC -Credential $Credential -Authentication $Options.PSDefaultAuthentication -Name 'DomainControllersFileShares' $Shares = Invoke-Command -Session $DCPssSession { Get-SmbShare | Where-Object { $_.Description -ne 'Default share' -and $_.Description -notmatch 'Remote' -and $_.Name -ne 'NETLOGON' -and $_.Name -ne 'SYSVOL' } } if ($Shares) { - Section -ExcludeFromTOC -Style NOTOCHeading6 $($DC.ToString().ToUpper().Split(".")[0]) { + Section -ExcludeFromTOC -Style NOTOCHeading5 $($DC.ToString().ToUpper().Split(".")[0]) { $FSObj = @() foreach ($Share in $Shares) { $inObj = [ordered] @{ @@ -558,7 +555,7 @@ function Get-AbrADDomainController { } if ($OutObj) { - Section -Style Heading5 "File Shares" { + Section -Style Heading4 "File Shares" { Paragraph "The following domain controllers have non-default file shares." $OutObj Paragraph "Health Check:" -Bold -Underline @@ -577,7 +574,6 @@ function Get-AbrADDomainController { if ($HealthCheck.DomainController.Software) { try { Write-PscriboMessage "Collecting additional software running on the Domain Controller." - Write-PscriboMessage "Discovering Active Directory Domain Controller information in $Domain." $DCObj = @() $DCObj += foreach ($DC in $DCs) { if (Test-Connection -ComputerName $DC -Quiet -Count 2) { @@ -597,7 +593,7 @@ function Get-AbrADDomainController { } if ( $Software ) { - Section -ExcludeFromTOC -Style NOTOCHeading6 $($DC.ToString().ToUpper().Split(".")[0]) { + Section -ExcludeFromTOC -Style NOTOCHeading5 $($DC.ToString().ToUpper().Split(".")[0]) { $OutObj = @() foreach ($APP in $Software) { try { @@ -642,7 +638,7 @@ function Get-AbrADDomainController { } } if ($DCObj) { - Section -Style Heading5 'Installed Software' { + Section -Style Heading4 'Installed Software' { Paragraph "The following section provides a summary of additional software running on Domain Controllers from domain $($Domain.ToString().ToUpper())." BlankLine $DCObj @@ -665,7 +661,7 @@ function Get-AbrADDomainController { Remove-PSSession -Session $DCPssSession if ( $Updates ) { - Section -ExcludeFromTOC -Style NOTOCHeading6 $($DC.ToString().ToUpper().Split(".")[0]) { + Section -ExcludeFromTOC -Style NOTOCHeading5 $($DC.ToString().ToUpper().Split(".")[0]) { $OutObj = @() foreach ($Update in $Updates) { try { @@ -709,7 +705,7 @@ function Get-AbrADDomainController { } } if ($DCObj) { - Section -Style Heading5 'Missing Windows Updates' { + Section -Style Heading4 'Missing Windows Updates' { Paragraph "The following section provides a summary of pending/missing windows updates on Domain Controllers from domain $($Domain.ToString().ToUpper())." BlankLine $DCObj diff --git a/Src/Private/Get-AbrADDomainLastBackup.ps1 b/Src/Private/Get-AbrADDomainLastBackup.ps1 index 18cc68b..5cbf876 100644 --- a/Src/Private/Get-AbrADDomainLastBackup.ps1 +++ b/Src/Private/Get-AbrADDomainLastBackup.ps1 @@ -5,7 +5,7 @@ function Get-AbrADDomainLastBackup { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -33,7 +33,7 @@ function Get-AbrADDomainLastBackup { $LastBackups = Get-WinADLastBackup -Domain $Domain -Credential $Credential Write-PscriboMessage "Discovered last taken backup information of domain $Domain." if ($LastBackups) { - Section -ExcludeFromTOC -Style NOTOCHeading5 'Naming Context Last Backup' { + Section -ExcludeFromTOC -Style NOTOCHeading4 'Naming Context Last Backup' { Paragraph "The following section details naming context last backup time for Domain $($Domain.ToString().ToUpper())." BlankLine $OutObj = @() @@ -78,6 +78,8 @@ function Get-AbrADDomainLastBackup { } } } + } else { + Write-PscriboMessage -IsWarning "No Naming context last backup information found in $Domain, disabling the section." } } catch { diff --git a/Src/Private/Get-AbrADDomainObject.ps1 b/Src/Private/Get-AbrADDomainObject.ps1 index 4d10b1e..d108775 100644 --- a/Src/Private/Get-AbrADDomainObject.ps1 +++ b/Src/Private/Get-AbrADDomainObject.ps1 @@ -5,7 +5,7 @@ function Get-AbrADDomainObject { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -29,7 +29,7 @@ function Get-AbrADDomainObject { process { try { - Section -Style Heading4 'Domain Object Stats' { + Section -Style Heading3 'Domain Object Stats' { if ($Domain) { Write-PScriboMessage "Collecting the Active Directory Object Count of domain $Domain." try { @@ -104,7 +104,7 @@ function Get-AbrADDomainObject { } } if ($OutObj) { - Section -ExcludeFromTOC -Style NOTOCHeading5 'Computers' { + Section -ExcludeFromTOC -Style NOTOCHeading3 'Computers' { if ($chartFileItem) { Image -Text 'Computers Object - Diagram' -Align 'Center' -Percent 100 -Path $chartFileItem } @@ -175,7 +175,7 @@ function Get-AbrADDomainObject { } } if ($OutObj) { - Section -ExcludeFromTOC -Style NOTOCHeading5 'Domain Controller' { + Section -ExcludeFromTOC -Style NOTOCHeading3 'Domain Controller' { if ($chartFileItem) { Image -Text 'Domain Controller Object - Diagram' -Align 'Center' -Percent 100 -Path $chartFileItem } @@ -247,7 +247,7 @@ function Get-AbrADDomainObject { } } if ($OutObj) { - Section -ExcludeFromTOC -Style NOTOCHeading5 'Users' { + Section -ExcludeFromTOC -Style NOTOCHeading3 'Users' { if ($chartFileItem) { Image -Text 'Users Object - Diagram' -Align 'Center' -Percent 100 -Path $chartFileItem } @@ -393,7 +393,7 @@ function Get-AbrADDomainObject { } } if ($OutObj) { - Section -Style Heading4 'Status of Users Accounts' { + Section -Style Heading3 'Status of Users Accounts' { if ($chartFileItem) { Image -Text 'Status of Users Accounts - Diagram' -Align 'Center' -Percent 100 -Path $chartFileItem } @@ -404,7 +404,7 @@ function Get-AbrADDomainObject { Write-PScriboMessage -IsWarning $($_.Exception.Message) } try { - Section -Style Heading4 'Privileged Groups' { + Section -Style Heading3 'Privileged Groups' { $OutObj = @() if ($Domain) { Write-PScriboMessage "Collecting Privileged Group in Active Directory." @@ -491,7 +491,7 @@ function Get-AbrADDomainObject { Write-PScriboMessage "Collecting Privileged Group $($Group.Name) with SID $($Group.SID)" $GroupObjects = Invoke-Command -Session $TempPssSession { Get-ADGroupMember -Server $using:DC -Identity ($using:Group).Name -Recursive -ErrorAction SilentlyContinue | ForEach-Object {Get-ADUser -Filter 'SamAccountName -eq $_.SamAccountName' -Server $using:DC -Property SamAccountName,objectClass,LastLogonDate,passwordNeverExpires,Enabled -SearchBase (Get-ADDomain -Identity $using:Domain).distinguishedName }} if ($GroupObjects) { - Section -ExcludeFromTOC -Style NOTOCHeading5 "$($Group.Name) ($(($GroupObjects | Measure-Object).count) Members)" { + Section -ExcludeFromTOC -Style NOTOCHeading4 "$($Group.Name) ($(($GroupObjects | Measure-Object).count) Members)" { $OutObj = @() foreach ($GroupObject in $GroupObjects) { $inObj = [ordered] @{ @@ -683,7 +683,7 @@ function Get-AbrADDomainObject { } } if ($OutObj) { - Section -Style Heading4 'Status of Computer Accounts' { + Section -Style Heading3 'Status of Computer Accounts' { if ($chartFileItem -and ($OutObj.'Total' | Measure-Object -Sum).Sum -ne 0) { Image -Text 'Status of Computer Accounts - Diagram' -Align 'Center' -Percent 100 -Path $chartFileItem } @@ -695,7 +695,7 @@ function Get-AbrADDomainObject { Write-PScriboMessage -IsWarning $($_.Exception.Message) } try { - Section -Style Heading4 'Operating Systems Count' { + Section -Style Heading3 'Operating Systems Count' { $OutObj = @() if ($Domain) { Write-PScriboMessage "Collecting Operating Systems in Active Directory." @@ -743,7 +743,7 @@ function Get-AbrADDomainObject { Write-PScriboMessage -IsWarning $($_.Exception.Message) } try { - Section -Style Heading4 'Default Domain Password Policy' { + Section -Style Heading3 'Default Domain Password Policy' { $OutObj = @() if ($Domain) { Write-PScriboMessage "Collecting the Active Directory Default Domain Password Policy of domain $Item." @@ -789,7 +789,7 @@ function Get-AbrADDomainObject { $DCPDC = Invoke-Command -Session $TempPssSession { Get-ADDomain -Identity $using:Item | Select-Object -ExpandProperty PDCEmulator } $PasswordPolicy = Invoke-Command -Session $TempPssSession { Get-ADFineGrainedPasswordPolicy -Server $using:DCPDC -Filter { Name -like "*" } -Properties * -SearchBase (Get-ADDomain -Identity $using:Domain).distinguishedName } | Sort-Object -Property Name if ($PasswordPolicy) { - Section -Style Heading4 'Fined Grained Password Policies' { + Section -Style Heading3 'Fined Grained Password Policies' { $FGPPInfo = @() foreach ($FGPP in $PasswordPolicy) { try { @@ -821,7 +821,7 @@ function Get-AbrADDomainObject { if ($InfoLevel.Domain -ge 2) { foreach ($FGPP in $FGPPInfo) { - Section -Style NOTOCHeading5 -ExcludeFromTOC "$($FGPP.Name)" { + Section -Style NOTOCHeading4 -ExcludeFromTOC "$($FGPP.Name)" { $TableParams = @{ Name = "Fined Grained Password Policies - $($FGPP.Name)" List = $true @@ -860,7 +860,7 @@ function Get-AbrADDomainObject { $DomainInfo = Invoke-Command -Session $TempPssSession { Get-ADDomain $using:Domain -ErrorAction Stop } $DCPDC = Invoke-Command -Session $TempPssSession { Get-ADDomain -Identity $using:Item | Select-Object -ExpandProperty PDCEmulator } $LAPS = Invoke-Command -Session $TempPssSession { Get-ADObject -Server $using:DCPDC "CN=ms-Mcs-AdmPwd,CN=Schema,CN=Configuration,$(($using:DomainInfo).DistinguishedName)" } | Sort-Object -Property Name - Section -Style Heading4 'Local Administrator Password Solution' { + Section -Style Heading3 'Windows LAPS ' { $LAPSInfo = @() try { $inObj = [ordered] @{ @@ -886,7 +886,7 @@ function Get-AbrADDomainObject { if ($InfoLevel.Domain -ge 2) { foreach ($LAP in $LAPSInfo) { $TableParams = @{ - Name = "Local Administrator Password Solution - $($Domain.ToString().ToUpper())" + Name = "Windows LAPS - $($Domain.ToString().ToUpper())" List = $true ColumnWidths = 40, 60 } @@ -897,7 +897,7 @@ function Get-AbrADDomainObject { } } else { $TableParams = @{ - Name = "Local Administrator Password Solution - $($Domain.ToString().ToUpper())" + Name = "Windows LAPS - $($Domain.ToString().ToUpper())" List = $false Columns = 'Name', 'Domain Name', 'Enabled' ColumnWidths = 34, 33, 33 @@ -920,7 +920,7 @@ function Get-AbrADDomainObject { } } } catch { - Write-PScriboMessage -IsWarning "$($_.Exception.Message) (Local Administrator Password Solution)" + Write-PScriboMessage -IsWarning "$($_.Exception.Message) (Windows LAPS)" } try { @@ -930,7 +930,7 @@ function Get-AbrADDomainObject { Write-PScriboMessage "Collecting the Active Directory Group Managed Service Accounts from DC $DC." $GMSA = Invoke-Command -Session $TempPssSession { Get-ADServiceAccount -Server $using:DC -Filter * -Properties * } if ($GMSA) { - Section -Style Heading4 'gMSA identities' { + Section -Style Heading3 'gMSA Identities' { $GMSAInfo = @() foreach ($Account in $GMSA) { try { @@ -992,7 +992,7 @@ function Get-AbrADDomainObject { if ($InfoLevel.Domain -ge 2) { foreach ($Account in $GMSAInfo) { - Section -Style NOTOCHeading5 -ExcludeFromTOC "$($Account.Name)" { + Section -Style NOTOCHeading4 -ExcludeFromTOC "$($Account.Name)" { $TableParams = @{ Name = "gMSA - $($Account.Name)" List = $true diff --git a/Src/Private/Get-AbrADDuplicateObject.ps1 b/Src/Private/Get-AbrADDuplicateObject.ps1 index 656db77..e4c5e76 100644 --- a/Src/Private/Get-AbrADDuplicateObject.ps1 +++ b/Src/Private/Get-AbrADDuplicateObject.ps1 @@ -5,7 +5,7 @@ function Get-AbrADDuplicateObject { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -33,7 +33,7 @@ function Get-AbrADDuplicateObject { $Objects = Get-WinADDuplicateObject -Domain $Domain -Credential $Credential Write-PscriboMessage "Discovered AD Duplicate Objects information from $Domain." if ($Objects) { - Section -ExcludeFromTOC -Style NOTOCHeading5 'Duplicate Objects' { + Section -ExcludeFromTOC -Style NOTOCHeading4 'Duplicate Objects' { Paragraph "The following section details Duplicate Objects discovered on Domain $($Domain.ToString().ToUpper())." BlankLine $OutObj = @() @@ -74,6 +74,8 @@ function Get-AbrADDuplicateObject { Text "Ensure there aren't any duplicate object." } } + } else { + Write-PscriboMessage -IsWarning "No Duplicate object information found in $Domain, disabling the section." } } catch { diff --git a/Src/Private/Get-AbrADDuplicateSPN.ps1 b/Src/Private/Get-AbrADDuplicateSPN.ps1 index 3b8f9a8..a5c017d 100644 --- a/Src/Private/Get-AbrADDuplicateSPN.ps1 +++ b/Src/Private/Get-AbrADDuplicateSPN.ps1 @@ -5,7 +5,7 @@ function Get-AbrADDuplicateSPN { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -33,7 +33,7 @@ function Get-AbrADDuplicateSPN { $SPNs = Get-WinADDuplicateSPN -Domain $Domain -Credential $Credential Write-PscriboMessage "Discovered AD Duplicate SPN information from $Domain." if ($SPNs) { - Section -ExcludeFromTOC -Style NOTOCHeading5 'Duplicate SPN' { + Section -ExcludeFromTOC -Style NOTOCHeading4 'Duplicate SPN' { Paragraph "The following section details Duplicate SPN discovered on Domain $($Domain.ToString().ToUpper())." BlankLine $OutObj = @() @@ -75,6 +75,8 @@ function Get-AbrADDuplicateSPN { } } } + } else { + Write-PscriboMessage -IsWarning "No Duplicate SPN information found in $Domain, disabling the section." } } catch { diff --git a/Src/Private/Get-AbrADFSMO.ps1 b/Src/Private/Get-AbrADFSMO.ps1 index ed47da4..746c0c3 100644 --- a/Src/Private/Get-AbrADFSMO.ps1 +++ b/Src/Private/Get-AbrADFSMO.ps1 @@ -5,7 +5,7 @@ function Get-AbrADFSMO { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -34,7 +34,7 @@ function Get-AbrADFSMO { if ($DomainData -and $ForestData) { $DC = Invoke-Command -Session $TempPssSession {(Get-ADDomain -Identity $using:Domain).ReplicaDirectoryServers | Select-Object -First 1} $DCPssSession = New-PSSession $DC -Credential $Credential -Authentication $Options.PSDefaultAuthentication -Name 'FSMORoles' - Section -Style Heading4 'FSMO Roles' { + Section -Style Heading3 'FSMO Roles' { $IsInfraMasterGC = (Invoke-Command -Session $DCPssSession {Get-ADDomainController -Identity ($using:DomainData).InfrastructureMaster}).IsGlobalCatalog $OutObj = @() try { diff --git a/Src/Private/Get-AbrADForest.ps1 b/Src/Private/Get-AbrADForest.ps1 index a6e4bd0..87f6098 100644 --- a/Src/Private/Get-AbrADForest.ps1 +++ b/Src/Private/Get-AbrADForest.ps1 @@ -166,6 +166,8 @@ function Get-AbrADForest { } } } + } else { + Write-PscriboMessage -IsWarning "No Certificate Authority Root information found in $ForestInfo, disabling the section." } Write-PscriboMessage "Discovering certificate authority issuers on forest $ForestInfo." $ConfigNCDN = $Data.PartitionsContainer.Split(',') | Select-Object -Skip 1 @@ -198,6 +200,8 @@ function Get-AbrADForest { } $OutObj | Sort-Object -Property 'Name' | Table @TableParams } + } else { + Write-PscriboMessage -IsWarning "No Certificate Authority Issuer information found, disabling the section." } } } @@ -257,6 +261,8 @@ function Get-AbrADForest { } } + } else { + Write-PscriboMessage -IsWarning "No Optional Feature information found in $ForestInfo, disabling the section." } } } diff --git a/Src/Private/Get-AbrADGPO.ps1 b/Src/Private/Get-AbrADGPO.ps1 index 4825f8f..769a87c 100644 --- a/Src/Private/Get-AbrADGPO.ps1 +++ b/Src/Private/Get-AbrADGPO.ps1 @@ -5,7 +5,7 @@ function Get-AbrADGPO { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -29,7 +29,7 @@ function Get-AbrADGPO { process { try { - Section -Style Heading5 "Group Policy Objects" { + Section -Style Heading4 "Group Policy Objects" { Paragraph "The following section provides a summary of the Group Policy Objects for domain $($Domain.ToString().ToUpper())." BlankLine $OutObj = @() @@ -111,7 +111,7 @@ function Get-AbrADGPO { if ($InfoLevel.Domain -ge 2) { try { foreach ($GPO in $GPOs) { - Section -ExcludeFromTOC -Style NOTOCHeading6 "$($GPO.DisplayName)" { + Section -ExcludeFromTOC -Style NOTOCHeading5 "$($GPO.DisplayName)" { try { [xml]$Links = Invoke-Command -Session $TempPssSession -ScriptBlock {$using:GPO | Get-GPOReport -Domain $using:Domain -ReportType XML} Write-PscriboMessage "Collecting Active Directory Group Policy Objects '$($GPO.DisplayName)'. (Group Policy Objects)" @@ -210,7 +210,7 @@ function Get-AbrADGPO { Remove-PSSession -Session $DCPssSession } if ($WmiFilters) { - Section -Style Heading6 "WMI Filters" { + Section -Style Heading5 "WMI Filters" { $OutObj = @() foreach ($WmiFilter in $WmiFilters) { Write-PscriboMessage "Discovered wmi filter information on $Domain. (WMI Filters)" @@ -238,6 +238,8 @@ function Get-AbrADGPO { $OutObj | Table @TableParams } } + } else { + Write-PscriboMessage -IsWarning "No WMI Filter information found in $Domain, disabling the section." } } catch { @@ -248,7 +250,7 @@ function Get-AbrADGPO { $PATH = "\\$Domain\SYSVOL\$Domain\Policies\PolicyDefinitions" $CentralStore = Invoke-Command -Session $TempPssSession -ScriptBlock {Test-Path $using:PATH} if ($PATH) { - Section -Style Heading6 "Central Store Repository" { + Section -Style Heading5 "Central Store Repository" { $OutObj = @() Write-PscriboMessage "Discovered Active Directory Central Store information on $Domain. (Central Store)" $inObj = [ordered] @{ @@ -281,6 +283,8 @@ function Get-AbrADGPO { } } } + } else { + Write-PscriboMessage -IsWarning "No GPO Central Store information found in $Domain, disabling the section." } } catch { @@ -318,7 +322,7 @@ function Get-AbrADGPO { } } if ($OutObj) { - Section -Style Heading6 "User Logon/Logoff Script" { + Section -Style Heading5 "Logon/Logoff Script" { if ($HealthCheck.Domain.GPO) { $OutObj | Where-Object { $_.'GPO Status' -like 'All Settings Disabled'} | Set-Style -Style Warning -Property 'GPO Status' } @@ -334,6 +338,8 @@ function Get-AbrADGPO { } $OutObj | Sort-Object -Property 'GPO Name' | Table @TableParams } + } else { + Write-PscriboMessage -IsWarning "No GPO Logon/Logoff script information found in $Domain, disabling the section." } } catch { @@ -371,7 +377,7 @@ function Get-AbrADGPO { } } if ($OutObj) { - Section -Style Heading6 "Computer Startup/Shutdown Script" { + Section -Style Heading5 "Startup/Shutdown Script" { if ($HealthCheck.Domain.GPO) { $OutObj | Where-Object { $_.'GPO Status' -like 'All Settings Disabled'} | Set-Style -Style Warning -Property 'GPO Status' } @@ -388,6 +394,8 @@ function Get-AbrADGPO { $OutObj | Sort-Object -Property 'GPO Name' | Table @TableParams } + } else { + Write-PscriboMessage -IsWarning "No GPO Computer Startup/Shutdown script information found in $Domain, disabling the section." } } catch { @@ -420,7 +428,7 @@ function Get-AbrADGPO { } } if ($OutObj) { - Section -Style Heading6 "Unlinked GPO" { + Section -Style Heading5 "Unlinked GPO" { if ($HealthCheck.Domain.GPO) { $OutObj | Set-Style -Style Warning } @@ -442,6 +450,8 @@ function Get-AbrADGPO { Text "Remove Unused GPO from Active Directory." } } + } else { + Write-PscriboMessage -IsWarning "No Unlinked Group Policy Objects information found in $Domain, disabling the section." } } catch { @@ -471,7 +481,7 @@ function Get-AbrADGPO { } } if ($OutObj) { - Section -Style Heading6 "Empty GPOs" { + Section -Style Heading5 "Empty GPOs" { if ($HealthCheck.Domain.GPO) { $OutObj | Set-Style -Style Warning } @@ -493,6 +503,8 @@ function Get-AbrADGPO { Text "No User and Computer parameters are set: Remove Unused GPO in Active Directory." } } + } else { + Write-PscriboMessage -IsWarning "No Empty GPO information found in $Domain, disabling the section." } } catch { @@ -527,7 +539,7 @@ function Get-AbrADGPO { } if ($OutObj) { - Section -Style Heading6 "Enforced GPO" { + Section -Style Heading5 "Enforced GPO" { if ($HealthCheck.Domain.GPO) { $OutObj | Set-Style -Style Warning } @@ -550,6 +562,8 @@ function Get-AbrADGPO { } } + } else { + Write-PscriboMessage -IsWarning "No Enforced GPO information found in $Domain, disabling the section." } } catch { @@ -579,7 +593,7 @@ function Get-AbrADGPO { $OrphanGPOs += $MissingADGPOs $OrphanGPOs += $MissingSYSVOLGPOs if ($OrphanGPOs) { - Section -Style Heading6 "Orphaned GPO" { + Section -Style Heading5 "Orphaned GPO" { Paragraph "The following table summarizes the group policy objects that are orphaned or missing in the AD database or in the SYSVOL directory." BlankLine $OutObj = @() @@ -649,6 +663,8 @@ function Get-AbrADGPO { } } } + } else { + Write-PscriboMessage -IsWarning "No Orphaned GPO information found in $Domain, disabling the section." } } catch { diff --git a/Src/Private/Get-AbrADInfrastructureService.ps1 b/Src/Private/Get-AbrADInfrastructureService.ps1 index e2b69d7..25a8e9d 100644 --- a/Src/Private/Get-AbrADInfrastructureService.ps1 +++ b/Src/Private/Get-AbrADInfrastructureService.ps1 @@ -5,7 +5,7 @@ function Get-AbrADInfrastructureService { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -28,13 +28,12 @@ function Get-AbrADInfrastructureService { } process { - Write-PscriboMessage "Discovering AD Domain Controller Infrastructure Services information for $DC." try { $DCPssSession = New-PSSession $DC -Credential $Credential -Authentication $Options.PSDefaultAuthentication -Name 'DomainControllerInfrastructureServices' $Available = Invoke-Command -Session $DCPssSession -ScriptBlock {Get-Service "W32Time" | Select-Object DisplayName, Name, Status} if ($Available) { Write-PscriboMessage "Discovered Active Directory DC Infrastructure Services information of $DC." - Section -ExcludeFromTOC -Style NOTOCHeading6 $($DC.ToString().ToUpper().Split(".")[0]) { + Section -ExcludeFromTOC -Style NOTOCHeading5 $($DC.ToString().ToUpper().Split(".")[0]) { $OutObj = @() if ($DC) { $Services = @('CertSvc','DHCPServer','DNS','DFS Replication','Intersite Messaging','Kerberos Key Distribution Center','NetLogon','Active Directory Domain Services','W32Time','ADWS','RPCSS','EVENTSYSTEM','DNSCACHE','SAMSS','WORKSTATION','Spooler') @@ -80,6 +79,8 @@ function Get-AbrADInfrastructureService { } } } + } else { + Write-PscriboMessage -IsWarning "No Infrastructure Services Status information found in $DC, disabling the section." } if ($DCPssSession) { Remove-PSSession -Session $DCPssSession diff --git a/Src/Private/Get-AbrADKerberosAudit.ps1 b/Src/Private/Get-AbrADKerberosAudit.ps1 index 3e905e7..05c3af3 100644 --- a/Src/Private/Get-AbrADKerberosAudit.ps1 +++ b/Src/Private/Get-AbrADKerberosAudit.ps1 @@ -5,7 +5,7 @@ function Get-AbrADKerberosAudit { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -34,7 +34,7 @@ function Get-AbrADKerberosAudit { $Unconstrained = Invoke-Command -Session $TempPssSession {Get-ADComputer -Filter { (TrustedForDelegation -eq $True) -AND (PrimaryGroupID -ne '516') -AND (PrimaryGroupID -ne '521') } -Server $using:DC -Searchbase (Get-ADDomain -Identity $using:Domain).distinguishedName} Write-PscriboMessage "Discovered Unconstrained Kerberos Delegation information from $Domain." if ($Unconstrained) { - Section -ExcludeFromTOC -Style NOTOCHeading5 'Unconstrained Kerberos Delegation' { + Section -ExcludeFromTOC -Style NOTOCHeading4 'Unconstrained Kerberos Delegation' { Paragraph "The following section provide a summary of unconstrained kerberos delegation on Domain $($Domain.ToString().ToUpper())." BlankLine $OutObj = @() @@ -73,12 +73,14 @@ function Get-AbrADKerberosAudit { Text "Ensure there aren't any unconstrained kerberos delegation in Active Directory." } } + } else { + Write-PscriboMessage -IsWarning "No Unconstrained Kerberos Delegation information found in $Domain, disabling the section." } try { $KRBTGT = $Users | Where-Object {$_.Name -eq 'krbtgt'} Write-PscriboMessage "Discovered Unconstrained Kerberos Delegation information from $Domain." if ($KRBTGT) { - Section -ExcludeFromTOC -Style NOTOCHeading5 'KRBTGT Account Audit' { + Section -ExcludeFromTOC -Style NOTOCHeading4 'KRBTGT Account Audit' { Paragraph "The following section provide a summary of KRBTGT account on Domain $($Domain.ToString().ToUpper())." BlankLine $OutObj = @() @@ -117,6 +119,8 @@ function Get-AbrADKerberosAudit { Text "Microsoft advises changing the krbtgt account password at regular intervals to keep the environment more secure." } } + } else { + Write-PscriboMessage -IsWarning "No KRBTGT Account Audit information found in $Domain, disabling the section." } } catch { @@ -127,7 +131,7 @@ function Get-AbrADKerberosAudit { $ADMIN = $Users | Where-Object {$_.SID -eq $SID} Write-PscriboMessage "Discovered Unconstrained Kerberos Delegation information from $Domain." if ($ADMIN) { - Section -ExcludeFromTOC -Style NOTOCHeading5 'Administrator Account Audit' { + Section -ExcludeFromTOC -Style NOTOCHeading4 'Administrator Account Audit' { Paragraph "The following section provide a summary of Administrator account on Domain $($Domain.ToString().ToUpper())." BlankLine $OutObj = @() @@ -167,6 +171,8 @@ function Get-AbrADKerberosAudit { Text "Microsoft advises changing the administrator account password at regular intervals to keep the environment more secure." } } + } else { + Write-PscriboMessage -IsWarning "No Administrator Account Audit information found in $Domain, disabling the section." } } catch { diff --git a/Src/Private/Get-AbrADOU.ps1 b/Src/Private/Get-AbrADOU.ps1 index dc79b86..bec4b4c 100644 --- a/Src/Private/Get-AbrADOU.ps1 +++ b/Src/Private/Get-AbrADOU.ps1 @@ -5,7 +5,7 @@ function Get-AbrADOU { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -30,10 +30,9 @@ function Get-AbrADOU { process { try { $DC = Invoke-Command -Session $TempPssSession -ScriptBlock {Get-ADDomainController -Discover -Domain $using:Domain | Select-Object -ExpandProperty HostName} - Write-PscriboMessage "Discovered Active Directory Organizational Unit information on DC $DC. (Organizational Unit)" $OUs = Invoke-Command -Session $TempPssSession -ScriptBlock {Get-ADOrganizationalUnit -Server $using:DC -Properties * -Searchbase (Get-ADDomain -Identity $using:Domain).distinguishedName -Filter *} if ($OUs) { - Section -Style Heading4 "Organizational Units" { + Section -Style Heading3 "Organizational Units" { Paragraph "The following section provides a summary of Active Directory Organizational Unit information." BlankLine $OutObj = @() @@ -89,7 +88,6 @@ function Get-AbrADOU { try { $OutObj = @() $DC = Invoke-Command -Session $TempPssSession {(Get-ADDomain -Identity $using:Domain).ReplicaDirectoryServers | Select-Object -First 1} - Write-PscriboMessage "Discovered Active Directory Domain Controller $DC in $Domain. (Group Policy Objects)" $OUs = Invoke-Command -Session $TempPssSession -ScriptBlock {Get-ADOrganizationalUnit -Server $using:DC -Filter * | Select-Object -Property DistinguishedName} if ($OUs) { Write-PscriboMessage "Discovered Active Directory Group Policy Objects information on $Domain. (Group Policy Objects)" @@ -114,7 +112,7 @@ function Get-AbrADOU { } } if ($OutObj) { - Section -ExcludeFromTOC -Style NOTOCHeading4 "GPO Blocked Inheritance" { + Section -ExcludeFromTOC -Style NOTOCHeading3 "GPO Blocked Inheritance" { if ($HealthCheck.Domain.GPO) { $OutObj | Set-Style -Style Warning } @@ -144,6 +142,8 @@ function Get-AbrADOU { } } } + } else { + Write-PscriboMessage -IsWarning "No Organizational Units information found in $Domain, disabling the section." } } catch { diff --git a/Src/Private/Get-AbrADSecurityAssessment.ps1 b/Src/Private/Get-AbrADSecurityAssessment.ps1 index 044fb71..f9e324c 100644 --- a/Src/Private/Get-AbrADSecurityAssessment.ps1 +++ b/Src/Private/Get-AbrADSecurityAssessment.ps1 @@ -5,7 +5,7 @@ function Get-AbrADSecurityAssessment { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -131,7 +131,7 @@ function Get-AbrADSecurityAssessment { } } if ($OutObj) { - Section -ExcludeFromTOC -Style NOTOCHeading5 'Account Security Assessment' { + Section -ExcludeFromTOC -Style NOTOCHeading4 'Account Security Assessment' { Paragraph "The following section provide a summary of the Account Security Assessment on Domain $($Domain.ToString().ToUpper())." BlankLine if ($chartFileItem) { @@ -145,6 +145,8 @@ function Get-AbrADSecurityAssessment { Text "Ensure there aren't any account with weak security posture."} } } + } else { + Write-PscriboMessage -IsWarning "No Domain users information found in $Domain, disabling the section." } } catch { @@ -154,7 +156,7 @@ function Get-AbrADSecurityAssessment { try { Write-PscriboMessage "Discovered Privileged Users information from $Domain." if ($PrivilegedUsers) { - Section -ExcludeFromTOC -Style NOTOCHeading5 'Privileged Users Assessment' { + Section -ExcludeFromTOC -Style NOTOCHeading4 'Privileged Users Assessment' { Paragraph "The following section details probable AD Admin accounts (user accounts with AdminCount set to 1) on Domain $($Domain.ToString().ToUpper())" BlankLine $OutObj = @() @@ -200,6 +202,8 @@ function Get-AbrADSecurityAssessment { Text "Ensure there aren't any account with weak security posture." } } + } else { + Write-PscriboMessage -IsWarning "No Privileged User Assessment information found in $Domain, disabling the section." } } catch { @@ -209,7 +213,7 @@ function Get-AbrADSecurityAssessment { Write-PscriboMessage "Discovered Inactive Privileged Accounts information from $Domain." $InactivePrivilegedUsers = $PrivilegedUsers | Where-Object {($_.LastLogonDate -le (Get-Date).AddDays(-30)) -AND ($_.PasswordLastSet -le (Get-Date).AddDays(-365)) -and ($_.SamAccountName -ne 'krbtgt') -and ($_.SamAccountName -ne 'Administrator') } if ($InactivePrivilegedUsers) { - Section -ExcludeFromTOC -Style NOTOCHeading5 'Inactive Privileged Accounts' { + Section -ExcludeFromTOC -Style NOTOCHeading4 'Inactive Privileged Accounts' { Paragraph "The following section details privileged accounts with the following filter (LastLogonDate >=30 days and PasswordLastSet >= 365 days) on Domain $($Domain.ToString().ToUpper())" BlankLine $OutObj = @() @@ -259,6 +263,8 @@ function Get-AbrADSecurityAssessment { Text "Unused or underutilized accounts in highly privileged groups, outside of any break-glass emergency accounts like the default Administrator account, should have their AD Admin privileges removed." } } + } else { + Write-PscriboMessage -IsWarning "No Inactive Privileged Accounts information found in $Domain, disabling the section." } } catch { @@ -269,7 +275,7 @@ function Get-AbrADSecurityAssessment { $UserSPNs = Invoke-Command -Session $TempPssSession {Get-ADUser -ResultPageSize 1000 -Server $using:Domain -filter {ServicePrincipalName -like '*'} -Properties AdminCount,PasswordLastSet,LastLogonDate,ServicePrincipalName,TrustedForDelegation,TrustedtoAuthForDelegation} Write-PscriboMessage "Discovered Service Accounts information from $Domain." if ($UserSPNs) { - Section -ExcludeFromTOC -Style NOTOCHeading5 'Service Accounts Assessment' { + Section -ExcludeFromTOC -Style NOTOCHeading4 'Service Accounts Assessment' { Paragraph "The following section details probable AD Service Accounts (user accounts with SPNs) on Domain $($Domain.ToString().ToUpper())" BlankLine $OutObj = @() @@ -323,6 +329,8 @@ function Get-AbrADSecurityAssessment { } } } + } else { + Write-PscriboMessage -IsWarning "No Service Accounts Assessment information found in $Domain, disabling the section." } } catch { @@ -331,7 +339,5 @@ function Get-AbrADSecurityAssessment { } } } - end {} - } \ No newline at end of file diff --git a/Src/Private/Get-AbrADSite.ps1 b/Src/Private/Get-AbrADSite.ps1 index a515cad..d9721af 100644 --- a/Src/Private/Get-AbrADSite.ps1 +++ b/Src/Private/Get-AbrADSite.ps1 @@ -5,7 +5,7 @@ function Get-AbrADSite { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -28,7 +28,6 @@ function Get-AbrADSite { if ($Site) { Section -Style Heading3 'Sites' { $OutObj = @() - Write-PscriboMessage "Discovered Active Directory Sites information of forest $ForestInfo" foreach ($Item in $Site) { try { Write-PscriboMessage "Collecting '$($Item.Name)' Site" @@ -84,6 +83,7 @@ function Get-AbrADSite { BlankLine if ($OutObj | Where-Object { $_.'Subnets' -eq 'No subnet assigned'}) { Paragraph { + Write-PscriboMessage "Discovered Active Directory Sites information of forest $ForestInfo" Text -Bold "Corrective Actions:" Text "Ensure Sites have an associated subnet. If subnets are not associated with AD Sites users in the AD Sites might choose a remote domain controller for authentication which in turn might result in excessive use of a remote domain controller."} } @@ -146,6 +146,8 @@ function Get-AbrADSite { } } } + } else { + Write-PscriboMessage -IsWarning "No Connection Objects information found in $Domain, disabling the section." } } catch { @@ -273,6 +275,8 @@ function Get-AbrADSite { BlankLine } } + } else { + Write-PscriboMessage -IsWarning "No Missing Subnets in AD information found in $Domain, disabling the section." } } catch { @@ -280,6 +284,8 @@ function Get-AbrADSite { } } } + } else { + Write-PscriboMessage -IsWarning "No Site Subnets information found in $Domain, disabling the section." } } catch { @@ -370,6 +376,8 @@ function Get-AbrADSite { } } } + } else { + Write-PscriboMessage -IsWarning "No Site Links information found in $Domain, disabling the section." } } catch { @@ -452,12 +460,16 @@ function Get-AbrADSite { BlankLine } } + } else { + Write-PscriboMessage -IsWarning "No Sysvol Replication information found in $Domain, disabling the section." } } catch { Write-PscriboMessage -IsWarning "Sysvol Replication Table Section: $($_.Exception.Message)" } } + } else { + Write-PscriboMessage -IsWarning "No Sites information found in $Domain, disabling the section." } } catch { diff --git a/Src/Private/Get-AbrADSiteReplication.ps1 b/Src/Private/Get-AbrADSiteReplication.ps1 index 010c0db..03bf23c 100644 --- a/Src/Private/Get-AbrADSiteReplication.ps1 +++ b/Src/Private/Get-AbrADSiteReplication.ps1 @@ -5,7 +5,7 @@ function Get-AbrADSiteReplication { .DESCRIPTION .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -24,11 +24,9 @@ function Get-AbrADSiteReplication { ) begin { - Write-PscriboMessage "Collecting AD Domain Sites Replication information." } process { - Write-PscriboMessage "Collecting AD Domain Sites Replication Summary. (Sites Replication Connection)" $DCs = Invoke-Command -Session $TempPssSession -ScriptBlock {Get-ADDomain -Identity $using:Domain | Select-Object -ExpandProperty ReplicaDirectoryServers} if ($DCs) { Write-PscriboMessage "Discovering Active Directory Sites Replication information on $Domain. (Sites Replication)" @@ -81,11 +79,11 @@ function Get-AbrADSiteReplication { } if ($ReplInfo) { if ($InfoLevel.Domain -ge 2) { - Section -Style Heading5 'Replication Connection' { + Section -Style Heading4 'Replication Connection' { Paragraph "The following section provides detailed information about Replication Connection." BlankLine foreach ($Repl in ($ReplInfo | Sort-Object -Property 'Replicate From Directory Server')) { - Section -Style NOTOCHeading5 -ExcludeFromTOC "Site: $($Repl.'From Site'): From: $($Repl.'From Server') To: $($Repl.'To Server')" { + Section -Style NOTOCHeading4 -ExcludeFromTOC "Site: $($Repl.'From Site'): From: $($Repl.'From Server') To: $($Repl.'To Server')" { $TableParams = @{ Name = "Replication Connection - $($Repl.'To Server')" List = $true @@ -99,7 +97,7 @@ function Get-AbrADSiteReplication { } } } else { - Section -Style Heading5 'Replication Connection' { + Section -Style Heading4 'Replication Connection' { Paragraph "The following section provide connection objects to source server ." BlankLine $TableParams = @{ @@ -114,6 +112,8 @@ function Get-AbrADSiteReplication { $ReplInfo | Sort-Object -Property 'Replicate From Directory Server' | Table @TableParams } } + } else { + Write-PscriboMessage -IsWarning "No Replication Connection information found in $Domain, disabling the section." } } catch { @@ -128,7 +128,7 @@ function Get-AbrADSiteReplication { Write-PscriboMessage "Discovered Active Directory Replication Status on $Domain. (Replication Status)" $RepStatus = Invoke-Command -Session $DCPssSession -ScriptBlock {repadmin /showrepl /repsto /csv | ConvertFrom-Csv} if ($RepStatus) { - Section -Style Heading5 'Replication Status' { + Section -Style Heading4 'Replication Status' { $OutObj = @() Write-PscriboMessage "Collecting Active Directory Replication Status from $($Domain). (Replication Status)" foreach ($Status in $RepStatus) { @@ -172,6 +172,8 @@ function Get-AbrADSiteReplication { BlankLine } } + } else { + Write-PscriboMessage -IsWarning "No Replication Status information found in $Domain, disabling the section." } if ($DCPssSession) { Remove-PSSession -Session $DCPssSession diff --git a/Src/Private/Get-AbrADTrust.ps1 b/Src/Private/Get-AbrADTrust.ps1 index c365a25..751bc32 100644 --- a/Src/Private/Get-AbrADTrust.ps1 +++ b/Src/Private/Get-AbrADTrust.ps1 @@ -5,7 +5,7 @@ function Get-AbrADTrust { .DESCRIPTION .NOTES - Version: 0.7.11 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -34,9 +34,8 @@ function Get-AbrADTrust { $DC = Invoke-Command -Session $TempPssSession {(Get-ADDomain -Identity $using:Domain).ReplicaDirectoryServers | Select-Object -First 1} $Trusts = Invoke-Command -Session $TempPssSession {Get-ADTrust -Filter * -Server $using:DC} if ($Trusts) { - Section -Style Heading4 'Domain and Trusts' { + Section -Style Heading3 'Domain and Trusts' { $TrustInfo = @() - Write-PScriboMessage "Discovered created trusts in domain $Domain" foreach ($Trust in $Trusts) { try { Write-PscriboMessage "Collecting Active Directory Domain Trust information from $($Trust.Name)" @@ -62,7 +61,7 @@ function Get-AbrADTrust { if ($InfoLevel.Domain -ge 2) { foreach ($Trust in $TrustInfo) { - Section -Style NOTOCHeading5 -ExcludeFromTOC "$($Trust.Name)" { + Section -Style NOTOCHeading4 -ExcludeFromTOC "$($Trust.Name)" { $TableParams = @{ Name = "Trusts - $($Trust.Name)" List = $true @@ -87,6 +86,8 @@ function Get-AbrADTrust { $TrustInfo | Table @TableParams } } + } else { + Write-PscriboMessage -IsWarning "No Domain Trust information found in $Domain, disabling the section." } } catch { diff --git a/Src/Private/Get-AbrDNSSection.ps1 b/Src/Private/Get-AbrDNSSection.ps1 new file mode 100644 index 0000000..9f03a5b --- /dev/null +++ b/Src/Private/Get-AbrDNSSection.ps1 @@ -0,0 +1,76 @@ +function Get-AbrDNSSection { + <# + .SYNOPSIS + Used by As Built Report to build Microsoft AD DNS Section. + .DESCRIPTION + + .NOTES + Version: 0.7.15 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PscriboMessage "Discovering DNS server information from $ForestInfo." + } + + process { + if ($InfoLevel.DNS -ge 1) { + Section -Style Heading1 "DNS Configuration" { + if ($Options.ShowDefinitionInfo) { + Paragraph "The Domain Name System (DNS) is a hierarchical and decentralized naming system for computers, services, or other resources connected to the Internet or a private network. It associates various information with domain names assigned to each of the participating entities. Most prominently, it translates more readily memorized domain names to the numerical IP addresses needed for locating and identifying computer services and devices with the underlying network protocols." + BlankLine + } + if (!$Options.ShowDefinitionInfo) { + Paragraph "The following section provides a summary of the Active Directory DNS Infrastructure Information." + BlankLine + } + foreach ($Domain in $OrderedDomains.split(" ")) { + if ($Domain) { + try { + # Define Filter option for Domain variable + if ($Options.Include.Domains) { + $DomainFilterOption = $Domain -in $Options.Include.Domains + + } else { + $DomainFilterOption = $Domain -notin $Options.Exclude.Domains + } + if (( $DomainFilterOption ) -and (Invoke-Command -Session $TempPssSession {Get-ADDomain $using:Domain -ErrorAction Stop})) { + Section -Style Heading2 "$($Domain.ToString().ToUpper())" { + Paragraph "The following section provides a configuration summary of the DNS service." + BlankLine + Get-AbrADDNSInfrastructure -Domain $Domain + $DCs = Invoke-Command -Session $TempPssSession {Get-ADDomain $using:Domain | Select-Object -ExpandProperty ReplicaDirectoryServers | Where-Object { $_ -notin ($using:Options).Exclude.DCs}} + foreach ($DC in $DCs){ + if (Test-Connection -ComputerName $DC -Quiet -Count 2) { + $DCPssSession = New-PSSession $DC -Credential $Credential -Authentication $Options.PSDefaultAuthentication -Name 'DDNSInfrastructure' + Get-AbrADDNSZone -Domain $Domain -DC $DC + } + if ($DCPssSession) { + Remove-PSSession -Session $DCPssSession + } + } + } + } else { + Write-PScriboMessage "$($Domain) disabled in Exclude.Domain variable" + } + } + catch { + Write-PscriboMessage -IsWarning "$($_.Exception.Message) (Domain Name System Information)" + continue + } + } + } + } + } + } + end {} +} diff --git a/Src/Private/Get-AbrDomainSection.ps1 b/Src/Private/Get-AbrDomainSection.ps1 new file mode 100644 index 0000000..4d8fbf0 --- /dev/null +++ b/Src/Private/Get-AbrDomainSection.ps1 @@ -0,0 +1,149 @@ +function Get-AbrDomainSection { + <# + .SYNOPSIS + Used by As Built Report to build Microsoft AD Domain Section. + .DESCRIPTION + + .NOTES + Version: 0.7.15 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PscriboMessage "Discovering Domain information from $ForestInfo." + } + + process { + if ($InfoLevel.Domain -ge 1) { + Section -Style Heading1 "AD Domain Configuration" { + if ($Options.ShowDefinitionInfo) { + Paragraph "An Active Directory domain is a collection of objects within a Microsoft Active Directory network. An object can be a single user or a group or it can be a hardware component, such as a computer or printer.Each domain holds a database containing object identity information. Active Directory domains can be identified using a DNS name, which can be the same as an organization's public domain name, a sub-domain or an alternate version (which may end in .local)." + BlankLine + } + if (!$Options.ShowDefinitionInfo) { + Paragraph "The following section provides a summary of the Active Directory Domain Information." + BlankLine + } + + foreach ($Domain in $OrderedDomains.split(" ")) { + if ($Domain) { + # Define Filter option for Domain variable + if ($Options.Include.Domains) { + $DomainFilterOption = $Domain -in $Options.Include.Domains + + } else { + $DomainFilterOption = $Domain -notin $Options.Exclude.Domains + } + try { + if (( $DomainFilterOption ) -and (Invoke-Command -Session $TempPssSession {Get-ADDomain -Identity $using:Domain})) { + Section -Style Heading2 "$($Domain.ToString().ToUpper())" { + Paragraph "The following section provides a summary of the Active Directory Domain Information." + BlankLine + Get-AbrADDomain -Domain $Domain + Get-AbrADFSMO -Domain $Domain + Get-AbrADTrust -Domain $Domain + Get-AbrADDomainObject -Domain $Domain + if ($HealthCheck.Domain.Backup -or $HealthCheck.Domain.DFS -or $HealthCheck.Domain.SPN -or $HealthCheck.Domain.Security -or $HealthCheck.Domain.DuplicateObject) { + Section -Style Heading3 'Health Checks' { + Get-AbrADDomainLastBackup -Domain $Domain + Get-AbrADDFSHealth -Domain $Domain + if ($Domain -like $ADSystem.RootDomain) { + Get-AbrADDuplicateSPN -Domain $ADSystem.RootDomain + } + Get-AbrADSecurityAssessment -Domain $Domain + Get-AbrADKerberosAudit -Domain $Domain + Get-AbrADDuplicateObject -Domain $Domain + } + } + Section -Style Heading3 'Domain Controllers' { + if ($Options.ShowDefinitionInfo) { + Paragraph "A domain controller (DC) is a server computer that responds to security authentication requests within a computer network domain. It is a network server that is responsible for allowing host access to domain resources. It authenticates users, stores user account information and enforces security policy for a domain." + BlankLine + } + if (!$Options.ShowDefinitionInfo) { + Paragraph "The following section provides a summary of the Active Directory Domain Controllers." + BlankLine + } + $DCs = Invoke-Command -Session $TempPssSession {Get-ADDomain -Identity $using:Domain | Select-Object -ExpandProperty ReplicaDirectoryServers | Where-Object { $_ -notin ($using:Options).Exclude.DCs}} | Sort-Object + + if ($DCs) { + + Get-AbrADDomainController -Domain $Domain -Dcs $DCs + + if ($InfoLevel.Domain -ge 2) { + Section -Style Heading4 "Roles" { + Paragraph "The following section provides a summary of installed role & features on $Domain DCs." + foreach ($DC in $DCs){ + $DCStatus = Test-Connection -ComputerName $DC -Quiet -Count 2 + if ($DCStatus -eq $false) { + Write-PScriboMessage -IsWarning "Unable to connect to $DC. Removing it from the $Domain report" + } + if (($DC -notin $Options.Exclude.DCs) -and $DCStatus) { + Get-AbrADDCRoleFeature -DC $DC + } + } + } + } + if ($HealthCheck.DomainController.Diagnostic) { + try { + Section -Style Heading4 'DC Diagnostic' { + Paragraph "The following section provides a summary of the Active Directory DC Diagnostic." + BlankLine + foreach ($DC in $DCs){ + if (($DC -notin $Options.Exclude.DCs) -and (Test-Connection -ComputerName $DC -Quiet -Count 2)) { + Get-AbrADDCDiag -Domain $Domain -DC $DC + } + } + } + } + catch { + Write-PscriboMessage -IsWarning "Error: Connecting to remote server $DC failed: WinRM cannot complete the operation. ('DCDiag Information)" + Write-PscriboMessage -IsWarning $_.Exception.Message + continue + } + } + try { + Section -Style Heading4 "Infrastructure Services" { + Paragraph "The following section provides a summary of the Domain Controller Infrastructure services status." + foreach ($DC in $DCs){ + if (($DC -notin $Options.Exclude.DCs) -and (Test-Connection -ComputerName $DC -Quiet -Count 2)) { + Get-AbrADInfrastructureService -DC $DC + } + } + } + } + catch { + Write-PscriboMessage -IsWarning "Error: Connecting to remote server $DC failed: WinRM cannot complete the operation. (ADInfrastructureService)" + Write-PscriboMessage -IsWarning $_.Exception.Message + continue + } + } + Get-AbrADSiteReplication -Domain $Domain + Get-AbrADGPO -Domain $Domain + Get-AbrADOU -Domain $Domain + } + } + } else { + Write-PScriboMessage "$($Domain) disabled in Exclude.Domain variable" + } + } + catch { + Write-PscriboMessage -IsWarning "$($_.Exception.Message) (Active Directory Domain)" + continue + } + } + } + } + } + } + end {} +} diff --git a/Src/Private/Get-AbrForestSection.ps1 b/Src/Private/Get-AbrForestSection.ps1 new file mode 100644 index 0000000..f135a86 --- /dev/null +++ b/Src/Private/Get-AbrForestSection.ps1 @@ -0,0 +1,63 @@ +function Get-AbrForestSection { + <# + .SYNOPSIS + Used by As Built Report to build Microsoft AD Forest Section. + .DESCRIPTION + + .NOTES + Version: 0.7.15 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PscriboMessage "Discovering Forest information from $Domain." + } + + process { + Section -Style Heading1 "$($ForestInfo.toUpper())" { + Paragraph "The following section provides a summary of the Active Directory Infrastructure configuration for $($ForestInfo)." + BlankLine + Write-PScriboMessage "Forest InfoLevel set at $($InfoLevel.Forest)." + if ($InfoLevel.Forest -ge 1) { + try { + Section -Style Heading2 "Forest Configuration." { + if ($Options.ShowDefinitionInfo) { + Paragraph "The Active Directory framework that holds the objects can be viewed at a number of levels. The forest, tree, and domain are the logical divisions in an Active Directory network. At the top of the structure is the forest. A forest is a collection of trees that share a common global catalog, directory schema, logical structure, and directory configuration. The forest represents the security boundary within which users, computers, groups, and other objects are accessible." + BlankLine + } + if (!$Options.ShowDefinitionInfo) { + Paragraph "The following section provides a summary of the Active Directory Forest Information." + BlankLine + } + try { + Get-AbrADForest + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + try { + Get-AbrADSite + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + } + catch { + Write-PscriboMessage -IsWarning "Error: Unable to retreive Forest: $ForestInfo information." + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + } + } + end {} +} \ No newline at end of file diff --git a/Src/Private/Get-AbrPKISection.ps1 b/Src/Private/Get-AbrPKISection.ps1 new file mode 100644 index 0000000..6790809 --- /dev/null +++ b/Src/Private/Get-AbrPKISection.ps1 @@ -0,0 +1,116 @@ +function Get-AbrPKISection { + <# + .SYNOPSIS + Used by As Built Report to build Microsoft AD PKI Section. + .DESCRIPTION + + .NOTES + Version: 0.7.15 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + Write-PscriboMessage "Discovering PKI infrastructure information from $ForestInfo." + } + + process { + if ($InfoLevel.CA -ge 1) { + try { + $CurrentMachineADDomain = Get-ComputerADDomain -ErrorAction SilentlyContinue + } catch { + Write-PscriboMessage -IsWarning 'Unable to determine current AD Domain' + Write-PscriboMessage -IsWarning $_.Exception.Message + } + if ($CurrentMachineADDomain.Name -in $ADSystem.Domains) { + Write-PScriboMessage "Current PC Domain $($CurrentMachineADDomain.Name) is in the Forrest Domain list of $($ADSystem.Name). Enabling Certificate Authority section" + try { + Write-PScriboMessage "Collecting Certification Authority information from $($System.split(".")[0])" + $Global:CAs = Get-CertificationAuthority -Enterprise + } catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + + if ($CAs) { + try { + Section -Style Heading1 "PKI Configuration" { + if ($Options.ShowDefinitionInfo) { + Paragraph 'In cryptography, a certificate authority or certification authority (CA) is an entity that issues digital certificates. A digital certificate certifies the ownership of a public key by the named subject of the certificate. This allows others (relying parties) to rely upon signatures or on assertions made about the private key that corresponds to the certified public key. A CA acts as a trusted third party trusted both by the subject (owner) of the certificate and by the party relying upon the certificate. The format of these certificates is specified by the X.509 or EMV standard.' + BlankLine + } + if (!$Options.ShowDefinitionInfo) { + Paragraph "The following section provides a summary of the Active Directory PKI Infrastructure Information." + BlankLine + } + try { + Get-AbrADCASummary + } catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + if ($InfoLevel.CA -ge 2) { + try { + Get-AbrADCARoot + Get-AbrADCASubordinate + } catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + foreach ($CA in ($CAs | Where-Object {$_.IsAccessible -notlike 'False'}).ComputerName) { + $CAObject = Get-CertificationAuthority -Enterprise -ComputerName $CA + if ($CAObject) { + Section -Style Heading2 "$($CAObject.DisplayName) Details" { + try { + Get-AbrADCASecurity -CA $CAObject + } catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + try { + Get-AbrADCACryptographyConfig -CA $CAObject + } catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + if ($InfoLevel.CA -ge 2) { + try { + Get-AbrADCAAIA -CA $CAObject + Get-AbrADCACRLSetting -CA $CAObject + } catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + if ($InfoLevel.CA -ge 2) { + try { + Get-AbrADCATemplate -CA $CAObject + } catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + try { + Get-AbrADCAKeyRecoveryAgent -CA $CAObject + } catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + } + } + } + } + } + } + catch { + Write-PscriboMessage -IsWarning $_.Exception.Message + continue + } + } + } else { + Write-PScriboMessage -IsWarning "Current PC Domain $($CurrentMachineADDomain.Name) is not in the Forrest Domain list of $($ADSystem.Name). Disabling Certificate Authority section" + } + } + } + end {} +} diff --git a/Src/Private/SharedUtilsFunctions.ps1 b/Src/Private/SharedUtilsFunctions.ps1 index 13a2607..f8b189f 100644 --- a/Src/Private/SharedUtilsFunctions.ps1 +++ b/Src/Private/SharedUtilsFunctions.ps1 @@ -1737,4 +1737,134 @@ function Get-ComputerADDomain () Write-Verbose -Message 'Calling GetCurrentDomain()' ([DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()) +} + +function Find-AuditingIssue { + <# + .SYNOPSIS + Used by As Built Report to find PKI Server auditing not enabled. + .DESCRIPTION + + .NOTES + Version: 2023.08 + Author: Jake Hildreth + + .EXAMPLE + + .LINK + https://github.com/TrimarcJake/Locksmith + #> + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [array]$ADCSObjects + ) + $ADCSObjects | Where-Object { + ($_.objectClass -eq 'pKIEnrollmentService') -and + ($_.AuditFilter -ne '127') + } | ForEach-Object { + $Issue = New-Object -TypeName pscustomobject + $Issue | Add-Member -MemberType NoteProperty -Name Forest -Value $_.CanonicalName.split('/')[0] -Force + $Issue | Add-Member -MemberType NoteProperty -Name Name -Value $_.Name -Force + $Issue | Add-Member -MemberType NoteProperty -Name DistinguishedName -Value $_.DistinguishedName -Force + if ($_.AuditFilter -match 'CA Unavailable') { + $Issue | Add-Member -MemberType NoteProperty -Name Issue -Value $_.AuditFilter -Force + $Issue | Add-Member -MemberType NoteProperty -Name Fix -Value 'N/A' -Force + $Issue | Add-Member -MemberType NoteProperty -Name Revert -Value 'N/A' -Force + $Issue | Add-Member -MemberType NoteProperty -Name Technique -Value 'DETECT' -Force + } + else { + $AuditValue = Switch ($_.AuditFilter) { + $Null {'Never Configured'} + default {$_.AuditFilter} + } + $Issue | Add-Member -MemberType NoteProperty -Name Issue -Value "Auditing is not fully enabled. Current value is $($AuditValue)" -Force + $Issue | Add-Member -MemberType NoteProperty -Name Fix ` + -Value "certutil -config `'$($_.CAFullname)`' -setreg `'CA\AuditFilter`' 127; Invoke-Command -ComputerName `'$($_.dNSHostName)`' -ScriptBlock { Get-Service -Name `'certsvc`' | Restart-Service -Force }" -Force + $Issue | Add-Member -MemberType NoteProperty -Name Revert ` + -Value "certutil -config $($_.CAFullname) -setreg CA\AuditFilter $($_.AuditFilter); Invoke-Command -ComputerName `'$($_.dNSHostName)`' -ScriptBlock { Get-Service -Name `'certsvc`' | Restart-Service -Force }" -Force + $Issue | Add-Member -MemberType NoteProperty -Name Technique -Value 'DETECT' -Force + } + $Severity = Get-Severity -Issue $Issue + $Issue | Add-Member -MemberType NoteProperty -Name Severity -Value $Severity + $Issue + } +} + + +function Get-ADCSObject { + <# + .SYNOPSIS + Used by As Built Report to find PKI Server auditing not enabled. + .DESCRIPTION + + .NOTES + Version: 2023.08 + Author: Jake Hildreth + + .EXAMPLE + + .LINK + https://github.com/TrimarcJake/Locksmith + #> + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [string]$Target + ) + try { + $ADRoot = Invoke-Command -Session $TempPssSession {(Get-ADRootDSE -Server $Using:Target).defaultNamingContext} + Invoke-Command -Session $TempPssSession {Get-ADObject -Filter * -SearchBase "CN=Public Key Services,CN=Services,CN=Configuration,$Using:ADRoot" -SearchScope 2 -Properties *} + } catch { + Write-PScriboMessage -IsWarning "Unable to find CA auditing information" + } +} + +function get-Severity { + <# + .SYNOPSIS + Used by As Built Report to find PKI Server auditing not enabled. + .DESCRIPTION + + .NOTES + Version: 2023.08 + Author: Spencer Alessi + + + .EXAMPLE + + .LINK + https://github.com/TrimarcJake/Locksmith + #> + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [array]$Issue + ) + foreach ($Finding in $Issue) { + try { + # Auditing + if ($Finding.Technique -eq 'DETECT') { + return 'Medium' + } + # ESC6 + if ($Finding.Technique -eq 'ESC6') { + return 'High' + } + # ESC8 + if ($Finding.Technique -eq 'ESC8') { + return 'High' + } + # ESC1, ESC2, ESC4, ESC5 + $SID = ConvertFrom-IdentityReference -Object $Finding.IdentityReference + if ($SID -match $SafeUsers -or $SID -match $SafeOwners) { + return 'Medium' + } + if (($SID -notmatch $SafeUsers -and $SID -notmatch $SafeOwners) -and ($Finding.ActiveDirectoryRights -match $DangerousRights)) { + return 'Critical' + } + } catch { + Write-Error 'Could not determine issue severity' + } + } } \ No newline at end of file diff --git a/Src/Public/Invoke-AsBuiltReport.Microsoft.AD.ps1 b/Src/Public/Invoke-AsBuiltReport.Microsoft.AD.ps1 index 6b71f09..6ae4312 100644 --- a/Src/Public/Invoke-AsBuiltReport.Microsoft.AD.ps1 +++ b/Src/Public/Invoke-AsBuiltReport.Microsoft.AD.ps1 @@ -5,7 +5,7 @@ function Invoke-AsBuiltReport.Microsoft.AD { .DESCRIPTION Documents the configuration of Microsoft AD in Word/HTML/Text formats using PScribo. .NOTES - Version: 0.7.14 + Version: 0.7.15 Author: Jonathan Colon Twitter: @jcolonfzenpr Github: rebelinux @@ -95,323 +95,25 @@ function Invoke-AsBuiltReport.Microsoft.AD { [array]$ChildDomains = $ADSystem.Domains | Where-Object {$_ -ne $RootDomains} [string]$OrderedDomains = $RootDomains + $ChildDomains - #---------------------------------------------------------------------------------------------# - # Forest Section # - #---------------------------------------------------------------------------------------------# - Section -Style Heading1 "$($ForestInfo.toUpper())" { - Paragraph "The following section provides a summary of the Active Directory Infrastructure configuration for $($ForestInfo)." - BlankLine - Write-PScriboMessage "Forest InfoLevel set at $($InfoLevel.Forest)." - if ($InfoLevel.Forest -ge 1) { - try { - Section -Style Heading2 "Forest Configuration." { - if ($Options.ShowDefinitionInfo) { - Paragraph "The Active Directory framework that holds the objects can be viewed at a number of levels. The forest, tree, and domain are the logical divisions in an Active Directory network. At the top of the structure is the forest. A forest is a collection of trees that share a common global catalog, directory schema, logical structure, and directory configuration. The forest represents the security boundary within which users, computers, groups, and other objects are accessible." - BlankLine - } - if (!$Options.ShowDefinitionInfo) { - Paragraph "The following section provides a summary of the Active Directory Forest Information." - BlankLine - } - try { - Get-AbrADForest - } - catch { - Write-PscriboMessage -IsWarning $_.Exception.Message - } - try { - Get-AbrADSite - } - catch { - Write-PscriboMessage -IsWarning $_.Exception.Message - } - } - } - catch { - Write-PscriboMessage -IsWarning "Error: Unable to retreive Forest: $ForestInfo information." - Write-PscriboMessage -IsWarning $_.Exception.Message - } - } - #---------------------------------------------------------------------------------------------# - # Domain Section # - #---------------------------------------------------------------------------------------------# - - if ($InfoLevel.Domain -ge 1) { - Section -Style Heading2 "AD Domain Configuration" { - if ($Options.ShowDefinitionInfo) { - Paragraph "An Active Directory domain is a collection of objects within a Microsoft Active Directory network. An object can be a single user or a group or it can be a hardware component, such as a computer or printer.Each domain holds a database containing object identity information. Active Directory domains can be identified using a DNS name, which can be the same as an organization's public domain name, a sub-domain or an alternate version (which may end in .local)." - BlankLine - } - if (!$Options.ShowDefinitionInfo) { - Paragraph "The following section provides a summary of the Active Directory Domain Information." - BlankLine - } - - foreach ($Domain in $OrderedDomains.split(" ")) { - if ($Domain) { - # Define Filter option for Domain variable - if ($Options.Include.Domains) { - $DomainFilterOption = $Domain -in $Options.Include.Domains - - } else { - $DomainFilterOption = $Domain -notin $Options.Exclude.Domains - } - try { - if (( $DomainFilterOption ) -and (Invoke-Command -Session $TempPssSession {Get-ADDomain -Identity $using:Domain})) { - Section -Style Heading3 "$($Domain.ToString().ToUpper())" { - Paragraph "The following section provides a summary of the Active Directory Domain Information." - BlankLine - Get-AbrADDomain -Domain $Domain - Get-AbrADFSMO -Domain $Domain - Get-AbrADTrust -Domain $Domain - Get-AbrADDomainObject -Domain $Domain - if ($HealthCheck.Domain.Backup -or $HealthCheck.Domain.DFS -or $HealthCheck.Domain.SPN -or $HealthCheck.Domain.Security -or $HealthCheck.Domain.DuplicateObject) { - Section -Style Heading4 'Health Checks' { - Get-AbrADDomainLastBackup -Domain $Domain - Get-AbrADDFSHealth -Domain $Domain - if ($Domain -like $ADSystem.RootDomain) { - Get-AbrADDuplicateSPN -Domain $ADSystem.RootDomain - } - Get-AbrADSecurityAssessment -Domain $Domain - Get-AbrADKerberosAudit -Domain $Domain - Get-AbrADDuplicateObject -Domain $Domain - } - } - Section -Style Heading4 'Domain Controllers' { - if ($Options.ShowDefinitionInfo) { - Paragraph "A domain controller (DC) is a server computer that responds to security authentication requests within a computer network domain. It is a network server that is responsible for allowing host access to domain resources. It authenticates users, stores user account information and enforces security policy for a domain." - BlankLine - } - if (!$Options.ShowDefinitionInfo) { - Paragraph "The following section provides a summary of the Active Directory Domain Controllers." - BlankLine - } - $DCs = Invoke-Command -Session $TempPssSession {Get-ADDomain -Identity $using:Domain | Select-Object -ExpandProperty ReplicaDirectoryServers | Where-Object { $_ -notin ($using:Options).Exclude.DCs}} | Sort-Object + # Forest Section + Get-AbrForestSection - if ($DCs) { + # Domain Section + Get-AbrDomainSection - Get-AbrADDomainController -Domain $Domain -Dcs $DCs + # DNS Section + Get-AbrDnsSection - if ($InfoLevel.Domain -ge 2) { - Section -Style Heading5 "Roles" { - Paragraph "The following section provides a summary of installed role & features on $Domain DCs." - foreach ($DC in $DCs){ - $DCStatus = Test-Connection -ComputerName $DC -Quiet -Count 2 - if ($DCStatus -eq $false) { - Write-PScriboMessage -IsWarning "Unable to connect to $DC. Removing it from the $Domain report" - } - if (($DC -notin $Options.Exclude.DCs) -and $DCStatus) { - Get-AbrADDCRoleFeature -DC $DC - } - } - } - } - if ($HealthCheck.DomainController.Diagnostic) { - try { - Section -Style Heading5 'DC Diagnostic' { - Paragraph "The following section provides a summary of the Active Directory DC Diagnostic." - BlankLine - foreach ($DC in $DCs){ - if (($DC -notin $Options.Exclude.DCs) -and (Test-Connection -ComputerName $DC -Quiet -Count 2)) { - Get-AbrADDCDiag -Domain $Domain -DC $DC - } - } - } - } - catch { - Write-PscriboMessage -IsWarning "Error: Connecting to remote server $DC failed: WinRM cannot complete the operation. ('DCDiag Information)" - Write-PscriboMessage -IsWarning $_.Exception.Message - continue - } - } - try { - Section -Style Heading5 "Infrastructure Services" { - Paragraph "The following section provides a summary of the Domain Controller Infrastructure services status." - foreach ($DC in $DCs){ - if (($DC -notin $Options.Exclude.DCs) -and (Test-Connection -ComputerName $DC -Quiet -Count 2)) { - Get-AbrADInfrastructureService -DC $DC - } - } - } - } - catch { - Write-PscriboMessage -IsWarning "Error: Connecting to remote server $DC failed: WinRM cannot complete the operation. (ADInfrastructureService)" - Write-PscriboMessage -IsWarning $_.Exception.Message - continue - } - } - Get-AbrADSiteReplication -Domain $Domain - Get-AbrADGPO -Domain $Domain - Get-AbrADOU -Domain $Domain - } - } - } else { - Write-PScriboMessage "$($Domain) disabled in Exclude.Domain variable" - } - } - catch { - Write-PscriboMessage -IsWarning "$($_.Exception.Message) (Active Directory Domain)" - continue - } - } - } - } - } - #---------------------------------------------------------------------------------------------# - # DNS Section # - #---------------------------------------------------------------------------------------------# - if ($InfoLevel.DNS -ge 1) { - Section -Style Heading2 "DNS Configuration" { - if ($Options.ShowDefinitionInfo) { - Paragraph "The Domain Name System (DNS) is a hierarchical and decentralized naming system for computers, services, or other resources connected to the Internet or a private network. It associates various information with domain names assigned to each of the participating entities. Most prominently, it translates more readily memorized domain names to the numerical IP addresses needed for locating and identifying computer services and devices with the underlying network protocols." - BlankLine - } - if (!$Options.ShowDefinitionInfo) { - Paragraph "The following section provides a summary of the Active Directory DNS Infrastructure Information." - BlankLine - } - foreach ($Domain in $OrderedDomains.split(" ")) { - if ($Domain) { - try { - # Define Filter option for Domain variable - if ($Options.Include.Domains) { - $DomainFilterOption = $Domain -in $Options.Include.Domains - - } else { - $DomainFilterOption = $Domain -notin $Options.Exclude.Domains - } - if (( $DomainFilterOption ) -and (Invoke-Command -Session $TempPssSession {Get-ADDomain $using:Domain -ErrorAction Stop})) { - Section -Style Heading3 "$($Domain.ToString().ToUpper())" { - Paragraph "The following section provides a configuration summary of the DNS service." - BlankLine - Get-AbrADDNSInfrastructure -Domain $Domain - $DCs = Invoke-Command -Session $TempPssSession {Get-ADDomain $using:Domain | Select-Object -ExpandProperty ReplicaDirectoryServers | Where-Object { $_ -notin ($using:Options).Exclude.DCs}} - foreach ($DC in $DCs){ - if (Test-Connection -ComputerName $DC -Quiet -Count 2) { - $DCPssSession = New-PSSession $DC -Credential $Credential -Authentication $Options.PSDefaultAuthentication -Name 'DDNSInfrastructure' - Get-AbrADDNSZone -Domain $Domain -DC $DC - } - if ($DCPssSession) { - Remove-PSSession -Session $DCPssSession - } - } - } - } else { - Write-PScriboMessage "$($Domain) disabled in Exclude.Domain variable" - } - } - catch { - Write-PscriboMessage -IsWarning "$($_.Exception.Message) (Domain Name System Information)" - continue - } - } - } - } - } + # PKI Section + Get-AbrPKISection - #---------------------------------------------------------------------------------------------# - # Certificate Authority Section # - #---------------------------------------------------------------------------------------------# - if ($InfoLevel.CA -ge 1) { - try { - $CurrentMachineADDomain = Get-ComputerADDomain -ErrorAction SilentlyContinue - } catch { - Write-PscriboMessage -IsWarning 'Unable to determine current AD Domain' - Write-PscriboMessage -IsWarning $_.Exception.Message - - } - if ($CurrentMachineADDomain.Name -in $ADSystem.Domains) { - Write-PScriboMessage "Current PC Domain $($CurrentMachineADDomain.Name) is in the Forrest Domain list of $($ADSystem.Name). Enabling Certificate Authority section" - try { - Write-PScriboMessage "Collecting Certification Authority information from $($System.split(".")[0])" - $Global:CAs = Get-CertificationAuthority -Enterprise - } - catch { - Write-PscriboMessage -IsWarning $_.Exception.Message - } - - if ($CAs) { - try { - Section -Style Heading2 "CA Configuration" { - if ($Options.ShowDefinitionInfo) { - Paragraph 'In cryptography, a certificate authority or certification authority (CA) is an entity that issues digital certificates. A digital certificate certifies the ownership of a public key by the named subject of the certificate. This allows others (relying parties) to rely upon signatures or on assertions made about the private key that corresponds to the certified public key. A CA acts as a trusted third party trusted both by the subject (owner) of the certificate and by the party relying upon the certificate. The format of these certificates is specified by the X.509 or EMV standard.' - BlankLine - } - if (!$Options.ShowDefinitionInfo) { - Paragraph "The following section provides a summary of the Active Directory PKI Infrastructure Information." - BlankLine - } - try { - Get-AbrADCASummary - } - catch { - Write-PscriboMessage -IsWarning $_.Exception.Message - } - if ($InfoLevel.CA -ge 2) { - try { - Get-AbrADCARoot - Get-AbrADCASubordinate - } - catch { - Write-PscriboMessage -IsWarning $_.Exception.Message - } - } - foreach ($CA in ($CAs | Where-Object {$_.IsAccessible -notlike 'False'}).ComputerName) { - $CAObject = Get-CertificationAuthority -Enterprise -ComputerName $CA - if ($CAObject) { - Section -Style Heading3 "$($CAObject.DisplayName) Details" { - try { - Get-AbrADCASecurity -CA $CAObject - } - catch { - Write-PscriboMessage -IsWarning $_.Exception.Message - } - try { - Get-AbrADCACryptographyConfig -CA $CAObject - } - catch { - Write-PscriboMessage -IsWarning $_.Exception.Message - } - if ($InfoLevel.CA -ge 2) { - try { - Get-AbrADCAAIA -CA $CAObject - Get-AbrADCACRLSetting -CA $CAObject - } - catch { - Write-PscriboMessage -IsWarning $_.Exception.Message - } - } - if ($InfoLevel.CA -ge 2) { - try { - Get-AbrADCATemplate -CA $CAObject - } - catch { - Write-PscriboMessage -IsWarning $_.Exception.Message - } - } - try { - Get-AbrADCAKeyRecoveryAgent -CA $CAObject - } - catch { - Write-PscriboMessage -IsWarning $_.Exception.Message - } - } - } - } - } - } - catch { - Write-PscriboMessage -IsWarning $_.Exception.Message - continue - } - } - } else {Write-PScriboMessage -IsWarning "Current PC Domain $($CurrentMachineADDomain.Name) is not in the Forrest Domain list of $($ADSystem.Name). Disabling Certificate Authority section" - } - } - }#endregion AD Section + # Remove used PSSession Write-PscriboMessage "Clearing PowerShell Session $($TempPssSession.Id)" Remove-PSSession -Session $TempPssSession + + # Remove used CIMSession Write-PscriboMessage "Clearing CIM Session $($TempCIMSession.Id)" Remove-CIMSession -CimSession $TempCIMSession + }#endregion foreach loop }