initial commit

This commit is contained in:
Edmond Gebara 2026-07-05 10:34:15 +02:00
commit 87f047f909
54 changed files with 1113120 additions and 0 deletions

377
Process-ADObjects-Base.ps1 Normal file
View file

@ -0,0 +1,377 @@
function writeHeaders
{
################################################################
# --------------------------------------------------------------
# Header für $DAWGruppenAnlegenOutFilePath anlegen
# --------------------------------------------------------------
"Basket.Import.ADGroup.Create" | Out-File $DAWGruppenAnlegenOutFilePath -Encoding "utf8NoBOM"
"GUIMandator" + ";" + "GUIADGroup.Name" + ";" + "GUIADGroup.Description" + ";" + "GUIMandatorADGroupType" + ";" + "GUIADGroup.DisplayName" + ";" + "GUIProcessingNote" + ";" + "OldName" | Out-File $DAWGruppenAnlegenOutFilePath -Append -Encoding "utf8NoBom"
# --------------------------------------------------------------
# Header für $DAWGruppenverwaltungOutFilePath anlegen
# --------------------------------------------------------------
"Basket.Import.ADGroup.ManageMembers" | Out-File "$DAWGruppenverwaltungOutFilePath" -Encoding "utf8NoBom"
"GUIMandator" + ";" + "GUIMandatorADGroupType" + ";" + "GUIADGroup.LDAP" + ";" + "GUIADGroup.ADGroups.Add.LDAPs" + ";" + "GUIADGroup.ADGroups.Rem.LDAPs" + ";" + "GUIADGroup.Accounts.Add.LDAPs" + ";" + "GUIADGroup.Accounts.Rem.LDAPs" + ";" + "GUIProcessingNote" + ";" + "ADObjectType" + ";" + "Quellgruppe" | Out-File $DAWGruppenverwaltungOutFilePath -Encoding "utf8NoBom" -Append
"Basket.Import.ADGroup.ManageMembers" | Out-File "$DAWGruppenverwaltungNeuOutFilePath" -Encoding "utf8NoBom"
"GUIMandator" + ";" + "GUIMandatorADGroupType" + ";" + "GUIADGroup.LDAP" + ";" + "GUIADGroup.ADGroups.Add.LDAPs" + ";" + "GUIADGroup.ADGroups.Rem.LDAPs" + ";" + "GUIADGroup.Accounts.Add.LDAPs" + ";" + "GUIADGroup.Accounts.Rem.LDAPs" + ";" + "GUIProcessingNote" + ";" + "ADObjectType" + ";" + "Quellgruppe" | Out-File $DAWGruppenverwaltungNeuOutFilePath -Encoding "utf8NoBom" -Append
# --------------------------------------------------------------
# Header für $KURSSollProfile anlegen
# --------------------------------------------------------------
"Profilnummer;Name;Beschreibung;Profilverantwortliche OE/Stelle;Info;InfoKurs" | Out-File $KURSSollProfileOutFilePath -Encoding "utf8NoBom"
# --------------------------------------------------------------
# Header für $IstMitarbeiterProfile anlegen
# --------------------------------------------------------------
"Personalnummer;;Profilnummer;Name Berechtigungsprofil" | Out-File "$KURSIstMitarbeiterProfileOutFilePath" -Encoding "utf8NoBom"
################################################################
}
function getObjectMemberships
{
param
(
[Parameter(Mandatory = $true, Position = 0)]
[string] $adObjectEntryName,
[Parameter(Mandatory = $true, Position = 1)]
[string] $memberShipType,
[Parameter(Mandatory = $true, Position = 2)]
[string] $memberShipOriginalType
)
$key = getMembershipIndexKey $adObjectEntryName $memberShipType
$bucket = $ADObjectMembershipsIndexed[$key]
$objectMemberships = if ($null -eq $bucket)
{
@()
}
else
{
@($bucket)
}
$objectMemberships | Add-Member -Force "Origin" $memberShipOriginalType
$objectMemberships | Add-Member -Force "OriginName" $adObjectEntryName
return $objectMemberships
}
function getAllUserMemberships
{
param
(
[Parameter(Mandatory = $true, Position = 0)]
$adObjectEntry
)
$result = [System.Collections.Generic.List[object]]::new()
$result.AddRange(@(getObjectMemberships $adObjectEntry.ObjectName "user" "user"))
$groupMemberships = @(getObjectMemberships $adObjectEntry.ObjectName "group" "group")
foreach ($groupMembership in $groupMemberships)
{
$result.AddRange(@(getObjectMemberships $groupMembership.MemberName "user" "group"))
}
# it's the same, bad odd syntax
# return ,$result.ToArray()
return @($result)
}
function getUsersByMemberGroup
{
<#
.SYNOPSIS
Retrieves the user membership entries for a given group via the
prebuilt membership index (O(1) lookup, exact class match).
.PARAMETER GroupName
The group whose user members are requested (matched against GroupName).
.OUTPUTS
Array of matching membership entries (empty array if none).
Object references are preserved from the index.
#>
param
(
[Parameter(Mandatory = $true, Position = 0)]
[string] $GroupName
)
# BUGFIX 2026-07-02: was indexing the flat array $ADObjectMemberships with a string
# key, which fails silently (non-terminating Int32 conversion error -> $null) and
# dropped ALL indirect (group-inherited) user memberships. Must use the hashtable.
$bucket = $ADObjectMembershipsIndexed[(getMembershipIndexKey $GroupName "user")]
$result = if ($null -eq $bucket)
{
@()
}
else
{
@($bucket)
}
return $result
}
# function getAllUserMemberships
# {
# param([Parameter(Mandatory, Position = 0)] $adObjectEntry)
# $result = [System.Collections.Generic.List[object]]::new()
# $result.AddRange(@(getObjectMemberships $adObjectEntry.ObjectName "user" "user"))
# $groupMemberships = @(getObjectMemberships $adObjectEntry.ObjectName "group" "group")
# foreach ($groupMembership in $groupMemberships)
# {
# $result.AddRange(@(getObjectMemberships $groupMembership.MemberName "user" "group"))
# }
# # ist beides gleich
# # return ,$result.ToArray()
# return @($result)
# }
# function getObjectMemberships
# {
# param
# (
# [Parameter(Mandatory = $true, Position = 0)]
# [String] $adObjectEntryName,
# [Parameter(Mandatory = $true, Position = 1)]
# [string] $memberShipType,
# [Parameter(Mandatory = $true, Position = 2)]
# [string] $memberShipOriginalType
# )
# $objectMemberships = @($ADObjectMemberships | Where-Object {($_.GroupName -ieq $adObjectEntryName) -and ($_.MemberClass -ieq $memberShipType)})
# # this is not very nice - we should only add members if they don´t exist - not just to set the values
# $objectMemberships | Add-Member -Force "Origin" $memberShipOriginalType
# $objectMemberships | Add-Member -Force "OriginName" $adObjectEntryName
# return $objectMemberships
# }
function getMembershipIndexKey
{
param
(
[Parameter(Mandatory = $true, Position = 0)]
[string] $GroupName,
[Parameter(Mandatory = $true, Position = 1)]
[string] $MemberClass
)
return "$GroupName`0$MemberClass".ToLowerInvariant()
}
function newObjectMembershipsIndex
{
<#
.SYNOPSIS
Builds a lookup index over membership entries for O(1) retrieval by
GroupName + MemberClass, replacing repeated linear Where-Object scans.
.PARAMETER ADObjectMemberships
The flat collection of membership entries to index.
.OUTPUTS
Hashtable mapping "<groupname>\0<memberclass>" (lowercased) to a
List[object] of the matching entries. Object references are preserved.
#>
param
(
[Parameter(Mandatory = $true, Position = 0)]
[AllowEmptyCollection()]
$ADObjectMemberships
)
$index = @{}
foreach ($entry in $ADObjectMemberships)
{
# NUL separator avoids key collisions between e.g. "ab"+"c" and "a"+"bc"
$key = getMembershipIndexKey $($entry.GroupName) $($entry.MemberClass)
$key0 = "$($entry.GroupName)`0$($entry.MemberClass)".ToLowerInvariant()
if (-not($key -eq $key0))
{
throw "this is BAAAD"
}
$bucket = $index[$key]
if ($null -eq $bucket)
{
$bucket = [System.Collections.Generic.List[object]]::new()
$index[$key] = $bucket
}
$bucket.Add($entry)
}
return $index
}
function getRoleType
{
param
(
[Parameter(Mandatory = $true, Position = 0)]
$adObjectEntry,
[Parameter(Mandatory = $true, Position = 1)]
[String] $typeTag
)
# $FileSystemAccessEntriesNew = @()
$roleType = "unknown"
# BUGFIX 2026-07-02: 'Sort-Object -Property "Order"' does not resolve hashtable keys on
# Windows PowerShell 5.1 (silent no-op, declaration order preserved). The scriptblock
# form works identically on 5.1 and 7, making rule evaluation order engine-independent.
$relevantRoleTypes = $SPK.GroupManagementMappings | Where-Object {$_.OU -ieq $typeTag} | Sort-Object { [int]$_.Order }
foreach ($relevantRoleType in $relevantRoleTypes)
{
if ($adObjectEntry.OldName -cmatch $relevantRoleType.TagRegExp)
{
$roleType = $relevantRoleType.TypeName
break
}
}
# Ausnahmebehandlungen in Absprache mit N.Zimmer am 21.01.2019
#--------------------------------------------------------------
if (($typeTag -ieq $FI.TypeTagSecurity) -and ($roleType -ieq "unknown"))
{
$roleType = "GPO"
}
#--------------------------------------------------------------
return $roletype
}
function buildPrefixMatcher
{
param(
[Parameter(Mandatory = $true, Position = 0)]
[string]$CsvPath
)
if (-not (Test-Path $CsvPath))
{
throw "Prefix CSV not found: $CsvPath"
}
# length -> HashSet[string] of prefixes with exactly that length
$byLength = [System.Collections.Generic.Dictionary[int, System.Collections.Generic.HashSet[string]]]::new()
# foreach ($row in (Import-Csv -Path $CsvPath))
foreach ($row in $SPK.ProfilPrefixes)
{
$prefix = $row.Prefix
if ([string]::IsNullOrEmpty($prefix))
{
continue
}
$len = $prefix.Length
$bucket = $null
if (-not $byLength.TryGetValue($len, [ref] $bucket))
{
$bucket = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
$byLength[$len] = $bucket
}
[void]$bucket.Add($prefix)
}
# Pre-compute the distinct lengths once, sorted descending so the most specific
# (longest) prefix wins first - mirrors the "specific before generic" ordering
# of a well-formed elseif cascade.
$lengths = $byLength.Keys | Sort-Object -Descending
# Return a small state object carrying both structures.
return [pscustomobject]@{
ByLength = $byLength
Lengths = $lengths
}
}
function testKnownPrefixes
{
param(
[Parameter(Mandatory = $true, Position = 0)]
[string]$Value,
[Parameter(Mandatory = $true, Position = 1)]
$Matcher
)
if ([string]::IsNullOrEmpty($Value))
{
return $false
}
$valueLen = $Value.Length
foreach ($len in $Matcher.Lengths)
{
if ($len -gt $valueLen)
{
continue
} # prefix longer than value -> can't match
$candidate = $Value.Substring(0, $len)
$bucket = $Matcher.ByLength[$len]
if ($bucket.Contains($candidate))
{
return $true # found a known prefix
}
}
return $false
}
# function getNormalizedDirectoryPaths
# {
# $analyzedDirectoryEntries = @()
# # $header = "Verzeichnisname", "Endpunktname", "Gruppe Lesen", "Gruppe Aendern", "Benutzer mit Leserecht", "Benutzer mit Aenderungsrecht", "Rollen mit Leserecht", "Rollen mit Aenderungsrecht", "Verzeichnisart", "normierter Pfad"
# # $directoriesFilePathEntries = Get-Content -Path $DirectoriesFilePath | Select-Object -Skip 1 | ConvertFrom-Csv -Delimiter ";" -Header $header
# # $directoriesFilePathEntries = Get-Content -Path $DirectoriesInFilePath | Select-Object -Skip 1 | ConvertFrom-Csv -Delimiter ";"
# $directoriesFilePathEntries = Get-Content -Path $DirectoriesInFilePath | ConvertFrom-Csv -Delimiter ";"
# # $headers = ($directoriesFilePathEntries | Get-Member -MemberType NoteProperty)
# # $interstingHeader = $headers.Name -match "Gruppe .ndern"
# foreach ($FilePathEntry in $directoriesFilePathEntries)
# {
# $analyzedDirectoryEntries += $FilePathEntry.Name
# }
# }
function postProcess
{
param (
[Parameter(Mandatory = $false, Position = 0)]
[bool]$convertToAscii = $false
)
#########################################################
# just to be sure that nothing happens: comment it out until you know what`s happening here !
#########################################################
# $tmpFilePath = moveToInstituteTmpPath $DAWGruppenAnlegenOutFilePath $true
# $firstlines = Get-Content -Path $tmpFilePath -TotalCount 2
# Get-Content -Path $tmpFilePath -TotalCount 1 | Out-File -Force $DAWGruppenAnlegenOutFilePath
# Get-Content -Path $tmpFilePath | Select-Object -Skip 2 | ConvertFrom-Csv -Delimiter ";" | select 'GUIMandator', 'GUIADGroup.Name', 'GUIADGroup.Description', 'GUIMandatorADGroupType', 'GUIADGroup.DisplayName', 'GUIProcessingNote' | ConvertTo-Csv -Delimiter ';' -NoTypeInformation | Out-File -FilePath $DAWGruppenAnlegenOutFilePath -Encoding UTF8 -Append
# # Import-Csv $tmpFilePath | select 'GUIMandator','GUIADGroup.Name','GUIADGroup.Description','GUIMandatorADGroupType','GUIADGroup.DisplayName','GUIProcessingNote' | Export-Csv -Path $DAWGruppenAnlegenOutFilePath -Delimiter ";" -Encoding UTF8
# $tmpFilePath = moveToInstituteTmpPath $DAWGruppenverwaltungOutFilePath $true
# $firstlines = Get-Content -Path $tmpFilePath -TotalCount 2
# Get-Content -Path $tmpFilePath -TotalCount 1 | Out-File -Force $DAWGruppenverwaltungOutFilePath
# Get-Content -Path $tmpFilePath | Select-Object -Skip 2 | ConvertFrom-Csv -Delimiter ";" | select "GUIMandator", "GUIMandatorADGroupType", "GUIADGroup.LDAP", "GUIADGroup.ADGroups.Add.LDAPs", "GUIADGroup.ADGroups.Rem.LDAPs", "GUIADGroup.Accounts.Add.LDAPs", "GUIADGroup.Accounts.Rem.LDAPs", "GUIProcessingNote" | ConvertTo-Csv -Delimiter ';' -NoTypeInformation | Out-File -FilePath $DAWGruppenverwaltungOutFilePath -Encoding UTF8 -Append
# # Import-Csv $tmpFilePath | select "GUIMandator","GUIMandatorADGroupType","GUIADGroup.LDAP","GUIADGroup.ADGroups.Add.LDAPs","GUIADGroup.ADGroups.Rem.LDAPs","GUIADGroup.Accounts.Add.LDAPs","GUIADGroup.Accounts.Rem.LDAPs","GUIProcessingNote" | Export-Csv -Path $DAWGruppenverwaltungOutFilePath -Delimiter ";" -Encoding UTF8 -NoTypeInformation
# $tmpFilePath = moveToInstituteTmpPath $DAWGruppenverwaltungNeuOutFilePath $true
# $firstlines = Get-Content -Path $tmpFilePath -TotalCount 2
# Get-Content -Path $tmpFilePath -TotalCount 1 | Out-File -Force $DAWGruppenverwaltungNeuOutFilePath
# Get-Content -Path $tmpFilePath | Select-Object -Skip 2 | ConvertFrom-Csv -Delimiter ";" | select "GUIMandator", "GUIMandatorADGroupType", "GUIADGroup.LDAP", "GUIADGroup.ADGroups.Add.LDAPs", "GUIADGroup.ADGroups.Rem.LDAPs", "GUIADGroup.Accounts.Add.LDAPs", "GUIADGroup.Accounts.Rem.LDAPs", "GUIProcessingNote" | ConvertTo-Csv -Delimiter ';' -NoTypeInformation | Out-File -FilePath $DAWGruppenverwaltungNeuOutFilePath -Encoding UTF8 -Append
####################################################### todo ?
# $KURSIstProfileOutFilePath
# $KURSIstProfileBerechtigungenOutFilePath
# $KURSIstStellenBerechtigungenOutFilePath
# $KURSIstStellenProfileOutFilePath
# $KURSIstOEsBerechtigungenOutFilePath
# $KURSIstOEsProfileOutFilePath
# $KURSIstMitarbeiterProfileOutFilePath
# $KURSSollStellenfunktionenOutFilePath
# $KURSSollProfileOutFilePath
# $KURSSollProfileBerechtigungenOutFilePath
# $KURSSollStellenfunktionenBerechtigungenOutFilePath
# $KURSSollStellenfunktionenProfileOutFilePath
####################################################### todo ?
}