Policies: ADMX-Presentation-Matching robuster (Typ normalisieren + Fallbacks)

- @odata.type-Vergleich normalisiert (fuehrendes '#' egal) -> Text-Presentations
  wurden sonst wegen Formatunterschied nicht zugeordnet.
- Zusaetzlicher Fallback: hat die Ziel-Definition genau eine Presentation, wird
  sie genutzt (deckt Ein-Feld-Settings wie Textboxen ab).
- Definitions-Auflösung: classType zuerst (User/Device nicht verwechseln), dann
  categoryPath bevorzugen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-09-23 12:56:15 +02:00
co-authored by Claude Opus 4.8
parent c1751bec4d
commit 0e66e268f6
+18 -9
View File
@@ -510,12 +510,12 @@ function Resolve-TargetGpDefinition {
} catch { $cands = @() } } catch { $cands = @() }
} }
if (@($cands).Count -eq 0) { return $null } if (@($cands).Count -eq 0) { return $null }
$narrow = @($cands) | Where-Object { # classType zuerst eingrenzen (User- vs. Device-Variante nie verwechseln),
((-not $ct) -or ([string](Get-PolicyProp $_ 'classType') -eq $ct)) -and # dann innerhalb dessen categoryPath bevorzugen; sonst erster Treffer.
((-not $cat) -or ([string](Get-PolicyProp $_ 'categoryPath') -eq $cat)) $pool = @($cands) | Where-Object { (-not $ct) -or ([string](Get-PolicyProp $_ 'classType') -eq $ct) }
} if (@($pool).Count -eq 0) { $pool = @($cands) }
$match = @($narrow) | Select-Object -First 1 $match = @($pool) | Where-Object { $cat -and ([string](Get-PolicyProp $_ 'categoryPath') -eq $cat) } | Select-Object -First 1
if (-not $match) { $match = @($cands) | Select-Object -First 1 } if (-not $match) { $match = @($pool) | Select-Object -First 1 }
return $match return $match
} }
@@ -524,19 +524,28 @@ function Resolve-TargetGpDefinition {
# (in Definitions-Reihenfolge; $Counter zaehlt je Typ mit). # (in Definitions-Reihenfolge; $Counter zaehlt je Typ mit).
function Resolve-TargetPresentationId { function Resolve-TargetPresentationId {
param($TargetPres, $SrcPresentation, [hashtable]$Counter) param($TargetPres, $SrcPresentation, [hashtable]$Counter)
# @odata.type-Format normalisieren: Graph liefert mal '#microsoft.graph.X',
# mal 'microsoft.graph.X' -> fuehrendes '#' weg, klein. Sonst schlaegt der
# String-Vergleich fehl und Text-Presentations werden nicht zugeordnet.
$norm = { param($t) ([string]$t).TrimStart('#').ToLower() }
$srcLabel = [string](Get-PolicyProp $SrcPresentation 'label') $srcLabel = [string](Get-PolicyProp $SrcPresentation 'label')
$srcType = [string](Get-PolicyProp $SrcPresentation '@odata.type') $srcType = & $norm (Get-PolicyProp $SrcPresentation '@odata.type')
# 1) label + Typ
if ($srcLabel) { if ($srcLabel) {
$m = @($TargetPres) | Where-Object { $m = @($TargetPres) | Where-Object {
([string](Get-PolicyProp $_ 'label') -eq $srcLabel) -and ([string](Get-PolicyProp $_ 'label') -eq $srcLabel) -and
([string](Get-PolicyProp $_ '@odata.type') -eq $srcType) ((& $norm (Get-PolicyProp $_ '@odata.type')) -eq $srcType)
} | Select-Object -First 1 } | Select-Object -First 1
if ($m) { return [string](Get-PolicyProp $m 'id') } if ($m) { return [string](Get-PolicyProp $m 'id') }
} }
# 2) i-te Ziel-Presentation gleichen Typs (in Reihenfolge)
$idx = 0; if ($Counter.ContainsKey($srcType)) { $idx = [int]$Counter[$srcType] } $idx = 0; if ($Counter.ContainsKey($srcType)) { $idx = [int]$Counter[$srcType] }
$sameType = @($TargetPres) | Where-Object { [string](Get-PolicyProp $_ '@odata.type') -eq $srcType } $sameType = @($TargetPres) | Where-Object { (& $norm (Get-PolicyProp $_ '@odata.type')) -eq $srcType }
$Counter[$srcType] = $idx + 1 $Counter[$srcType] = $idx + 1
if ($idx -lt @($sameType).Count) { return [string](Get-PolicyProp $sameType[$idx] 'id') } if ($idx -lt @($sameType).Count) { return [string](Get-PolicyProp $sameType[$idx] 'id') }
# 3) Letzter Fallback: hat die Ziel-Definition genau EINE Presentation, nimm sie
# (deckt Ein-Feld-Settings wie Textboxen zuverlaessig ab).
if (@($TargetPres).Count -eq 1) { return [string](Get-PolicyProp $TargetPres[0] 'id') }
return $null return $null
} }