<#
.SYNOPSIS
Creates or uses a dedicated LIAM test account and delegates limited AD and NTFS rights for validation.

.DESCRIPTION
Use this script to verify whether the reduced LIAM service-user permissions are sufficient.
Run with -WhatIf first, then without -WhatIf, configure the account in LIAM, and execute the relevant workflows.

Requirements:
- RSAT ActiveDirectory module
- Run as an account allowed to create users and edit ACLs on the target OU and NTFS paths
#>

[CmdletBinding(SupportsShouldProcess = $true)]
param(
    [Parameter(Mandatory = $true)]
    [string]$SamAccountName,

    [Parameter(Mandatory = $true)]
    [string]$TargetGroupOuDN,

    [string[]]$ReadSearchBaseDNs = @(),

    [string[]]$NtfsReadAclPaths = @(),

    [string[]]$NtfsManageAclPaths = @(),

    [string[]]$NtfsCreateParentPaths = @(),

    [switch]$CreateUser,

    [switch]$GrantDeleteGroupObjects
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

Import-Module ActiveDirectory -ErrorAction Stop

function Get-SchemaGuid {
    param(
        [Parameter(Mandatory = $true)]
        [string]$LdapDisplayName
    )

    $schemaNc = (Get-ADRootDSE).schemaNamingContext
    $object = Get-ADObject -SearchBase $schemaNc `
        -LDAPFilter "(lDAPDisplayName=$LdapDisplayName)" `
        -Properties schemaIDGUID

    if (-not $object) {
        throw "Schema object not found: $LdapDisplayName"
    }

    return [Guid]::new([byte[]]$object.schemaIDGUID)
}

function Add-LiamAdAccessRule {
    param(
        [Parameter(Mandatory = $true)]
        [string]$TargetDN,

        [Parameter(Mandatory = $true)]
        [System.Security.Principal.IdentityReference]$Identity,

        [Parameter(Mandatory = $true)]
        [System.DirectoryServices.ActiveDirectoryRights]$Rights,

        [Parameter(Mandatory = $true)]
        [System.Security.AccessControl.AccessControlType]$AccessType,

        [Guid]$ObjectType = [Guid]::Empty,

        [System.DirectoryServices.ActiveDirectorySecurityInheritance]$Inheritance = [System.DirectoryServices.ActiveDirectorySecurityInheritance]::None,

        [Guid]$InheritedObjectType = [Guid]::Empty
    )

    $entry = [ADSI]"LDAP://$TargetDN"
    $acl = $entry.ObjectSecurity

    if ($InheritedObjectType -ne [Guid]::Empty) {
        $rule = [System.DirectoryServices.ActiveDirectoryAccessRule]::new(
            $Identity,
            $Rights,
            $AccessType,
            $ObjectType,
            $Inheritance,
            $InheritedObjectType
        )
    }
    elseif ($ObjectType -ne [Guid]::Empty) {
        $rule = [System.DirectoryServices.ActiveDirectoryAccessRule]::new(
            $Identity,
            $Rights,
            $AccessType,
            $ObjectType
        )
    }
    else {
        $rule = [System.DirectoryServices.ActiveDirectoryAccessRule]::new(
            $Identity,
            $Rights,
            $AccessType,
            $Inheritance
        )
    }

    $acl.AddAccessRule($rule)

    if ($PSCmdlet.ShouldProcess($TargetDN, "Add AD ACL: $Rights / $ObjectType / $Inheritance")) {
        $entry.ObjectSecurity = $acl
        $entry.CommitChanges()
    }
}

function Grant-LiamNtfsRights {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Path,

        [Parameter(Mandatory = $true)]
        [string]$Account,

        [Parameter(Mandatory = $true)]
        [System.Security.AccessControl.FileSystemRights]$Rights,

        [System.Security.AccessControl.InheritanceFlags]$InheritanceFlags = "ContainerInherit,ObjectInherit",

        [System.Security.AccessControl.PropagationFlags]$PropagationFlags = "None"
    )

    if (-not (Test-Path -LiteralPath $Path)) {
        throw "Path not found: $Path"
    }

    $acl = Get-Acl -LiteralPath $Path
    $rule = [System.Security.AccessControl.FileSystemAccessRule]::new(
        $Account,
        $Rights,
        $InheritanceFlags,
        $PropagationFlags,
        [System.Security.AccessControl.AccessControlType]::Allow
    )

    $acl.AddAccessRule($rule)

    if ($PSCmdlet.ShouldProcess($Path, "Grant NTFS rights '$Rights' to '$Account'")) {
        Set-Acl -LiteralPath $Path -AclObject $acl
    }
}

$domain = Get-ADDomain
$netbiosName = $domain.NetBIOSName
$accountName = "$netbiosName\$SamAccountName"

if ($CreateUser) {
    $existingUser = Get-ADUser -LDAPFilter "(sAMAccountName=$SamAccountName)" -ErrorAction SilentlyContinue
    if (-not $existingUser) {
        $password = Read-Host "Password for $SamAccountName" -AsSecureString

        if ($PSCmdlet.ShouldProcess($SamAccountName, "Create AD user")) {
            New-ADUser `
                -SamAccountName $SamAccountName `
                -Name $SamAccountName `
                -AccountPassword $password `
                -Enabled $true `
                -PasswordNeverExpires $true `
                -ChangePasswordAtLogon $false
        }
    }
}

$user = Get-ADUser -Identity $SamAccountName
$identity = $user.SID

$groupClassGuid = Get-SchemaGuid "group"
$attributeNames = @(
    "cn",
    "sAMAccountName",
    "displayName",
    "groupType",
    "description",
    "managedBy",
    "member"
)

$attributeGuids = @{}
foreach ($name in $attributeNames) {
    $attributeGuids[$name] = Get-SchemaGuid $name
}

Add-LiamAdAccessRule `
    -TargetDN $TargetGroupOuDN `
    -Identity $identity `
    -Rights ([System.DirectoryServices.ActiveDirectoryRights]"ListChildren,ReadProperty") `
    -AccessType Allow `
    -Inheritance All

Add-LiamAdAccessRule `
    -TargetDN $TargetGroupOuDN `
    -Identity $identity `
    -Rights CreateChild `
    -AccessType Allow `
    -ObjectType $groupClassGuid

if ($GrantDeleteGroupObjects) {
    Add-LiamAdAccessRule `
        -TargetDN $TargetGroupOuDN `
        -Identity $identity `
        -Rights DeleteChild `
        -AccessType Allow `
        -ObjectType $groupClassGuid
}

foreach ($attributeName in $attributeNames) {
    Add-LiamAdAccessRule `
        -TargetDN $TargetGroupOuDN `
        -Identity $identity `
        -Rights WriteProperty `
        -AccessType Allow `
        -ObjectType $attributeGuids[$attributeName] `
        -Inheritance Descendents `
        -InheritedObjectType $groupClassGuid
}

foreach ($readBase in $ReadSearchBaseDNs) {
    Add-LiamAdAccessRule `
        -TargetDN $readBase `
        -Identity $identity `
        -Rights ([System.DirectoryServices.ActiveDirectoryRights]"ListChildren,ReadProperty") `
        -AccessType Allow `
        -Inheritance All
}

foreach ($path in $NtfsReadAclPaths) {
    Grant-LiamNtfsRights `
        -Path $path `
        -Account $accountName `
        -Rights ([System.Security.AccessControl.FileSystemRights]"ReadAndExecute,ReadPermissions")
}

foreach ($path in $NtfsManageAclPaths) {
    Grant-LiamNtfsRights `
        -Path $path `
        -Account $accountName `
        -Rights ([System.Security.AccessControl.FileSystemRights]"ReadAndExecute,ReadPermissions,ChangePermissions")
}

foreach ($path in $NtfsCreateParentPaths) {
    Grant-LiamNtfsRights `
        -Path $path `
        -Account $accountName `
        -Rights ([System.Security.AccessControl.FileSystemRights]"ReadAndExecute,ReadPermissions,CreateDirectories") `
        -InheritanceFlags None `
        -PropagationFlags None
}

Write-Host "Delegation finished for $accountName"
Write-Host "Suggested validation:"
Write-Host "1. Configure this account as the LIAM provider credential."
Write-Host "2. Create AD service groups and add members."
Write-Host "3. Read NTFS data areas."
Write-Host "4. Ensure missing NTFS permission groups and ACL entries."
Write-Host "5. Verify that AD deletes and writes outside the target OU fail."
