From 9b5e88f2adc228a61a0837b76079aebbdf8a3df2 Mon Sep 17 00:00:00 2001
From: Friedrich Weinmann <FriedrichWeinmann@users.noreply.github.com>
Date: Fri, 13 Dec 2024 09:52:51 +0100
Subject: [PATCH] schema attribute handling update

---
 ForestManagement/ForestManagement.psd1        |  4 +--
 ForestManagement/changelog.md                 |  5 ++++
 .../functions/schema/Test-FMSchema.ps1        | 29 +++++++++++++++++--
 .../internal/configurations/configuration.ps1 |  1 +
 4 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/ForestManagement/ForestManagement.psd1 b/ForestManagement/ForestManagement.psd1
index 725d566..7f0c964 100644
--- a/ForestManagement/ForestManagement.psd1
+++ b/ForestManagement/ForestManagement.psd1
@@ -3,7 +3,7 @@
 	RootModule = 'ForestManagement.psm1'
 	
 	# Version number of this module.
-	ModuleVersion = '1.5.76'
+	ModuleVersion = '1.5.78'
 	
 	# ID used to uniquely identify this module
 	GUID = '7de4379d-17c8-48d3-bd6d-93279aef64bb'
@@ -26,7 +26,7 @@
 	# Modules that must be imported into the global environment prior to importing
 	# this module
 	RequiredModules   = @(
-		@{ ModuleName = 'PSFramework'; ModuleVersion = '1.10.318' }
+		@{ ModuleName = 'PSFramework'; ModuleVersion = '1.12.346' }
 		
 		# Additional Dependencies, cannot declare due to bug in dependency handling in PS5.1
 		# @{ ModuleName = 'ResolveString'; ModuleVersion = '1.0.0' }
diff --git a/ForestManagement/changelog.md b/ForestManagement/changelog.md
index 214074d..47538cd 100644
--- a/ForestManagement/changelog.md
+++ b/ForestManagement/changelog.md
@@ -1,5 +1,10 @@
 # Changelog
 
+## 1.5.78 (2024-12-13)
+
+- Upd: Schema - significant test performance improvements
+- Upd: Schema - added option to scan _all_ attributes and report any unconfigured ones as "Unmanaged"
+
 ## 1.5.76 (2024-03-05)
 
 - Fix: Exchange Schema - invoke fails on validating sites.
diff --git a/ForestManagement/functions/schema/Test-FMSchema.ps1 b/ForestManagement/functions/schema/Test-FMSchema.ps1
index c02cdaa..dbe1da7 100644
--- a/ForestManagement/functions/schema/Test-FMSchema.ps1
+++ b/ForestManagement/functions/schema/Test-FMSchema.ps1
@@ -74,9 +74,13 @@
 		# Pick up termination flag from Stop-PSFFunction and interrupt if begin failed to connect
 		if (Test-PSFFunctionInterrupt) { return }
 
+		$allAttributes = Get-ADObject @parameters -LDAPFilter "(attributeID=*)" -SearchBase $rootDSE.schemaNamingContext -ErrorAction Ignore -Properties *
+		$allClasses = Get-ADObject @parameters -LDAPFilter "(objectClass=classSchema)" -SearchBase $rootDSE.schemaNamingContext -ErrorAction Ignore -Properties *
+
+		#region Process Configuration
 		foreach ($schemaSetting in (Get-FMSchema)) {
 			$schemaObject = $null
-			$schemaObject = Get-ADObject @parameters -LDAPFilter "(attributeID=$($schemaSetting.OID))" -SearchBase $rootDSE.schemaNamingContext -ErrorAction Ignore -Properties *
+			$schemaObject = $allAttributes.Where{ $_.attributeID -eq $schemaSetting.OID }[0]
 
 			if (-not $schemaObject) {
 				# If we already want to disable the attribute, no need to create it
@@ -147,7 +151,7 @@
 			}
 
 			if (-not $schemaSetting.IsDefunct -and $schemaSetting.PSObject.Properties.Name -contains 'MayBeContainedIn') {
-				$mayContain = Get-ADObject @parameters -LDAPFilter "(mayContain=$($schemaSetting.LdapDisplayName))" -SearchBase $rootDSE.schemaNamingContext
+				$mayContain = $allClasses.Where{ $_.MayContain -contains $schemaSetting.LdapDisplayName }
 				if (-not $mayContain -and $schemaSetting.MayBeContainedIn) {
 					$null = $changes.Add((New-AdcChange -Property MayContain -NewValue $schemaSetting.MayBeContainedIn -Identity $schemaObject.DistinguishedName -Type Schema -ToString $mayContainToString))
 				}
@@ -163,7 +167,7 @@
 			}
 
 			if (-not $schemaSetting.IsDefunct -and $schemaSetting.PSObject.Properties.Name -contains 'MustBeContainedIn') {
-				$mustContain = Get-ADObject @parameters -LDAPFilter "(mustContain=$($schemaSetting.LdapDisplayName))" -SearchBase $rootDSE.schemaNamingContext
+				$mustContain = $allClasses.Where{ $_.mustContain -contains $schemaSetting.LdapDisplayName }
 				if (-not $mustContain -and $schemaSetting.MustBeContainedIn) {
 					$null = $changes.Add((New-AdcChange -Property MustContain -NewValue $schemaSetting.MustBeContainedIn -Identity $schemaObject.DistinguishedName -Type Schema -ToString $mustContainToString))
 				}
@@ -191,5 +195,24 @@
 				}
 			}
 		}
+		#endregion Process Configuration
+
+		#region Process AD Only
+		if (-not (Get-PSFConfigValue -FullName 'ForestManagement.Schema.Attributes.ReportUnconfigured')) { return }
+		$unconfigured = $allAttributes | Where-Object attributeID -NotIn (Get-FMSchema).OID
+		foreach ($unexpectedAttribute in $unconfigured) {
+			if ($unexpectedAttribute.IsDefunct) { continue }
+			[PSCustomObject]@{
+				PSTypeName    = 'ForestManagement.Schema.TestResult'
+				Type          = 'Unmanaged'
+				ObjectType    = 'Schema'
+				Identity      = $unexpectedAttribute.AdminDisplayName
+				Changed       = $null
+				Server        = $forest.SchemaMaster
+				ADObject      = $unexpectedAttribute
+				Configuration = $null
+			}
+		}
+		#endregion Process AD Only
 	}
 }
\ No newline at end of file
diff --git a/ForestManagement/internal/configurations/configuration.ps1 b/ForestManagement/internal/configurations/configuration.ps1
index 89e7480..e355b69 100644
--- a/ForestManagement/internal/configurations/configuration.ps1
+++ b/ForestManagement/internal/configurations/configuration.ps1
@@ -29,3 +29,4 @@ Set-PSFConfig -Module 'ForestManagement' -Name 'Schema.Account.AutoDisable' -Val
 Set-PSFConfig -Module 'ForestManagement' -Name 'Schema.Account.AutoGrant' -Value $false -Initialize -Validation bool -Description 'Whether the account to use for performing the schema update should be added to the schema admins group before use.'
 Set-PSFConfig -Module 'ForestManagement' -Name 'Schema.Account.AutoRevoke' -Value $false -Initialize -Validation bool -Description 'Whether the account to use for performing the schema update should be removed from the schema admins group after use.'
 Set-PSFConfig -Module 'ForestManagement' -Name 'Schema.Password.AutoReset' -Value $false -Initialize -Validation bool -Description 'Whether the password of the used account should be reset before & after use.'
+Set-PSFConfig -Module 'ForestManagement' -Name 'Schema.Attributes.ReportUnconfigured' -Value $false -Initialize -Validation bool -Description 'Whether Schema attributes that were not configured should be reported as a test finding.'