Private/Get-AS2GoSettings.ps1

function Get-AS2GoSettings {
    [CmdletBinding()]
    param(
        [switch]$ReadOnly = $false
    )


    ################################################################################
    ##### #####
    ##### Read & Update global AS2Go Settings from JSON file #####
    ##### #####
    ################################################################################

    $CurrentFunction = Get-FunctionName
    Write-Log -Message "### Start Function $CurrentFunction ###"
    $StartRunTime = (Get-Date).ToString($Script:DateFormatLog)
    #################### main code | out- host #####################

    Invoke-Output -T Header -M "Verify and Update global AS2Go Settings"

    # -------------------------------
    # Helper: build settings definition
    # -------------------------------
    function New-AS2GoSetting {
        param(
            [Parameter(Mandatory)][int]$Index,
            [Parameter(Mandatory)][string]$Label,
            [Parameter(Mandatory)][string]$Key,
            [ValidateSet('Text', 'ADObject', 'Folder')]
            [string]$InputType = 'Text',
            [string]$ScriptVar # optional: name of $Script: variable to sync
        )
        [pscustomobject]@{
            Index     = $Index
            Label     = $Label
            Key       = $Key
            InputType = $InputType
            ScriptVar = $ScriptVar
            Value     = $null
        }
    }

    # -------------------------------
    # Helper: read all config keys once
    # -------------------------------
    function Read-AS2GoConfig {
        param(
            [Parameter(Mandatory)][object[]]$Settings
        )
        $cfg = [ordered]@{}
        foreach ($s in $Settings) {
            try {
                $cfg[$s.Key] = Get-KeyValue -key $s.Key
            }
            catch {
                $cfg[$s.Key] = $null
            }
        }
        return $cfg
    }

    # -------------------------------
    # Helper: assign values to $Settings from config hashtable
    # -------------------------------
    function Update-AS2GoSettingValues {
        param(
            [Parameter(Mandatory)][object[]]$Settings,
            [Parameter(Mandatory)][hashtable]$Config
        )
        foreach ($s in $Settings) {
            $s.Value = $Config[$s.Key]
        }
    }

    # -------------------------------
    # Helper: display settings table
    # -------------------------------
    function Show-AS2GoSettingsTable {
        param(
            [Parameter(Mandatory)][object[]]$Settings
        )
        foreach ($s in $Settings | Sort-Object Index) {
            "{0,3}: {1,-30} = {2}" -f $s.Index, $s.Label, $s.Value | Write-Host
        }
    }

    # -------------------------------
    # Helper: edit one setting (UI input)
    # -------------------------------
    function Edit-AS2GoSetting {
        param(
            [Parameter(Mandatory)]$Setting
        )

        Write-Host ""
        Write-Host (" Change value for '{0}' = {1}" -f $Setting.Label.Trim(), $Setting.Value) -ForegroundColor $Script:FGCCommand

        $newValue = $null
        switch ($Setting.InputType) {
            'ADObject' {
                $newValue = Select-ADObject
            }
            'Folder' {
                $newValue = Get-FolderPath -InitialDirectory 'C:\' -Description 'Please select the tools folder (with mimikatz.exe)'
            }
            default {
                $newValue = Invoke-Output -Type Input -Message "Please enter the new value"
            }
        }

        if ($null -ne $newValue -and ($newValue.ToString().Trim()).Length -gt 0) {
            Set-KeyValue -Key $Setting.Key -NewValue $newValue
        }
        else {
            Write-Host " No value provided. Nothing changed." -ForegroundColor Yellow
        }
    }

    # -------------------------------
    # Settings definition (single source of truth)
    # Keep the Index numbers stable (your UI references them)
    # -------------------------------
    $Settings = @(
        (New-AS2GoSetting -Index 0  -Label "Logon Server / DC"          -Key "myDC"          -InputType Text    -ScriptVar "ASDC"),
        (New-AS2GoSetting -Index 1  -Label "Victim PC"                  -Key "myViPC"        -InputType Text    -ScriptVar "ASVictimMaschine"),
        (New-AS2GoSetting -Index 2  -Label "Admin PC"                   -Key "mySAW"         -InputType Text    -ScriptVar "ASSAW"),
        (New-AS2GoSetting -Index 3  -Label "Application Server"         -Key "myAppServer"   -InputType Text    -ScriptVar "ASAppServer"),
        (New-AS2GoSetting -Index 4  -Label "Help Desk Group"            -Key "globalHelpDesk"-InputType Text    -ScriptVar "ASHelpDesk"),
        (New-AS2GoSetting -Index 5  -Label "MDI Honeytoken"             -Key "honeytoken"    -InputType Text    -ScriptVar "ASHoneyToken"),
        (New-AS2GoSetting -Index 6  -Label "Domain Name"                -Key "fqdn"          -InputType Text    -ScriptVar "ASDomain"),
        (New-AS2GoSetting -Index 7  -Label "Domain SID"                 -Key "DomainSID"     -InputType Text    -ScriptVar "ASDomainSID"),
        (New-AS2GoSetting -Index 8  -Label "NTLM Hash Helpdesk"         -Key "pthntml"       -InputType Text    -ScriptVar "ASPtHntml"),
        (New-AS2GoSetting -Index 9  -Label "NTLM Hash krbtgt"           -Key "krbtgtntml"    -InputType Text    -ScriptVar "ASKrbtgtNtml"),
        (New-AS2GoSetting -Index 10 -Label "Seconds to reboot"          -Key "time2reboot"   -InputType Text    -ScriptVar "ASTime2Reboot"),
        (New-AS2GoSetting -Index 11 -Label "AD Search Base"             -Key "MySearchBase"  -InputType ADObject -ScriptVar "ASSearchBase"),
        (New-AS2GoSetting -Index 12 -Label "OU for BD User"             -Key "BDUsersOU"     -InputType ADObject -ScriptVar "ASOUofBackDoorUser"),
        (New-AS2GoSetting -Index 13 -Label "Tickets UNC Path (suffix)"  -Key "ticketsPath"   -InputType Text    -ScriptVar "ASTicketsUNCPath"),
        (New-AS2GoSetting -Index 14 -Label "Tickets Directory"          -Key "ticketsDir"    -InputType Text    -ScriptVar "ASTicketsDirectory"),
        (New-AS2GoSetting -Index 15 -Label "NTDS Dit File (Backup)"     -Key "OfflineDITFile"-InputType Text    -ScriptVar "ASOfflineDITFile"),
        (New-AS2GoSetting -Index 16 -Label "Tools (e.g. mimikatz)"      -Key "Tools"         -InputType Folder  -ScriptVar "ASTools"),
        (New-AS2GoSetting -Index 17 -Label "OpenSSL start path"         -Key "OpenSSL"       -InputType Text    -ScriptVar "ASOPenSSL")
    )

    # -------------------------------
    # Prompt
    # -------------------------------
    $title = "Verify and Update Global AS2Go Settings"
    $message = "Are all values correct?"
    $Options = @(
        [pscustomobject] @{ Label = "&Yes"; Help = "Yes - All values are correct."; Value = "Yes" },
        [pscustomobject] @{ Label = "&No"; Help = "No - At least one value is wrong."; Value = "No" },
        [pscustomobject] @{ Label = "&Skip"; Help = "Skip this task."; Value = "Quit" }
    )

    $firstRun = $true
    $repeat = $Script:Yes

    do {
        if (-not $firstRun) {
            Clear-Host
            Invoke-Output -Type Info -message "Updated Values"
        }
        $firstRun = $false

        # -------------------------------
        # Dynamic defaults (AD + local env) — set once per loop
        # -------------------------------
        $Domain = $null
        try { $Domain = Get-ADDomain } catch { }

        if ($Domain) {
            try { Set-KeyValue -Key "fqdn"      -NewValue $Domain.DNSRoot } catch { }
            try { Set-KeyValue -Key "DomainSID" -NewValue $Domain.DomainSID.Value } catch { }
        }

        # env defaults
        try { Set-KeyValue -Key "myViPC" -NewValue $env:COMPUTERNAME } catch { }
        try {
            if ($env:LOGONSERVER -and $env:LOGONSERVER.Length -gt 2) {
                Set-KeyValue -Key "myDC" -NewValue $env:LOGONSERVER.Substring(2)
            }
        }
        catch { }

        # -------------------------------
        # Read config once, apply normalization rules, re-read if changed
        # -------------------------------
        $Config = Read-AS2GoConfig -Settings $Settings

        # Normalize: BDUsersOU placeholder -> actual UsersContainer (if domain is available)
        if ($Domain) {
            $bd = [string]$Config["BDUsersOU"]
            if ($bd -and ($bd -ieq "CN=Users,DC=xxx,DC=xxx")) {
                try { Set-KeyValue -Key "BDUsersOU" -NewValue $Domain.UsersContainer } catch { }
                $Config = Read-AS2GoConfig -Settings $Settings
            }
        }

        # Normalize: Tools path placeholder ".\tools" -> resolve if possible (otherwise keep as-is)
        $tools = [string]$Config["Tools"]
        if ($tools -and ($tools -ieq ".\tools")) {
            try {
                $resolved = Resolve-Path ".\tools" -ErrorAction Stop
                Set-KeyValue -Key "Tools" -NewValue $resolved.Path
                $Config = Read-AS2GoConfig -Settings $Settings
            }
            catch {
                # keep ".\tools" if not resolvable
            }
        }

        # apply config to settings values
        Update-AS2GoSettingValues -Settings $Settings -Config $Config

        # Sync $Script: variables (so existing code keeps working)
        foreach ($s in $Settings) {
            if ($s.ScriptVar) {
                Set-Variable -Scope Script -Name $s.ScriptVar -Value $s.Value -Force
            }
        }

        if ($ReadOnly) {
            # Return a rich object in readonly mode (useful for callers)
            $runtime = Get-RunTime -StartRunTime $StartRunTime
            Write-Log -Message " Run Time: $runtime [h] ###"
            Write-Log -Message "### End Function $CurrentFunction ###"

            return [pscustomobject]@{
                Settings = $Settings | Sort-Object Index
                Config   = $Config
            }
        }

        # Show settings
        Show-AS2GoSettingsTable -Settings $Settings

        $decision = Show-DecisionPrompt -Message $message -Options $Options -Default 0 -Title $title

        switch ($decision) {
            "Yes" { $repeat = $Script:No }
            "Quit" {
                Write-Log -Message "Skipped AS2Go Settings verification/update!"
                $repeat = $Script:No
            }
            "No" {
                # Ask which setting index to edit
                $defaultIndex = 10
                $question = "Please enter the desired setting number. Default "
                $answer = Get-Answer -question $question -defaultValue $defaultIndex

                $idx = $defaultIndex
                if ($answer -match '^\d{1,2}$') {
                    $idx = [int]$answer
                }

                $target = $Settings | Where-Object { $_.Index -eq $idx } | Select-Object -First 1
                if (-not $target) {
                    Write-Host " Invalid setting number '$idx'." -ForegroundColor Yellow
                }
                else {
                    try {
                        Edit-AS2GoSetting -Setting $target
                    }
                    catch {
                        Write-Host " Failed to update setting '$($target.Label)'." -ForegroundColor Red
                    }
                }

                # loop continues -> values will be reloaded & displayed
            }
            default {
                # Safety: treat unknown as quit
                $repeat = $Script:No
            }
        }

        Clear-Host
    } until ($repeat -eq $Script:No)

    $runtime = Get-RunTime -StartRunTime $StartRunTime
    Write-Log -Message " Run Time: $runtime [h] ###"
    Write-Log -Message "### End Function $CurrentFunction ###"

    # Return final snapshot (useful for automation/tests)
    #return [pscustomobject]@{
    # Settings = $Settings | Sort-Object Index
    # Config = (Read-AS2GoConfig -Settings $Settings)
    #}
}


function Get-AS2GoSettings_old {

    Param([switch]$ReadOnly = $false)

    $CurrentFunction = Get-FunctionName
    Write-Log -Message "### Start Function $CurrentFunction ###"
    $StartRunTime = (Get-Date).ToString($Script:DateFormatLog)
    #################### main code | out- host #####################

    Invoke-Output -T Header -M "Verify and Update global AS2Go Settings"

    $title = "Verify and Update Global AS2Go Settings"
    $message = "Are all values correct?"

    $Options = @(
        [pscustomobject] @{ Label = "&Yes"; Help = "Yes - All values are correct."; Value = "Yes" },
        [pscustomobject] @{ Label = "&No"; Help = "No - At least one value is wrong."; Value = "No" },
        [pscustomobject] @{ Label = "&Skip"; Help = "Skip this task."; Value = "Quit" }
    )

    $repeat = $Script:Yes
    [bool]$firstrun = $true

    Do {
        If ($firstrun -ne $true) {
            Clear-Host
            Invoke-output -Type H1 "Updated Values"
        }
        else {
            $firstrun = $false
        }

        try {
            $Script:ASDomain = (Get-ADDomain).DNSRoot
            Set-KeyValue -key "fqdn" -NewValue $Script:ASDomain 
        }
        catch {
            <#Do this if a terminating exception happens#>
        }
        
        try {
            $Script:ASDomainSID = (Get-ADDomain).DomainSID.Value
            Set-KeyValue -key "DomainSID" -NewValue $Script:ASDomainSID
        }
        catch {
            <#Do this if a terminating exception happens#>
        }
        
        $Script:ASVictimMaschine = $env:COMPUTERNAME
        $Script:ASDC = $env:LOGONSERVER.Substring(2) 

        #Set-KeyValue -key "fqdn" -NewValue $Script:ASDomain
        #Set-KeyValue -key "DomainSID" -NewValue $Script:ASDomainSID
        Set-KeyValue -key "myViPC" -NewValue $Script:ASVictimMaschine
        Set-KeyValue -key "mydc" -NewValue $Script:ASDC

        #read values from AS2Go.json config file
        $Script:ASDC = Get-KeyValue -key "myDC" 
        $Script:ASSAW = Get-KeyValue -key "mySAW" 
        $Script:ASVictimMaschine = Get-KeyValue -key "myViPC"
        $Script:ASFQDN = Get-KeyValue -key "fqdn"
        $Script:ASPtHntml = Get-KeyValue -key "pthntml"
        $Script:ASKrbtgtNtml = Get-KeyValue -key "krbtgtntml"
        $Script:ASOPenSSL = Get-KeyValue -key "OpenSSL"
        $Script:ASHelpDesk = Get-KeyValue -key "globalHelpDesk"
        $Script:ASTicketsUNCPath = Get-KeyValue -key "ticketsPath"
        $Script:ASTicketsDirectory = Get-KeyValue -key "ticketsDir"
        $Script:ASTime2Reboot = Get-KeyValue -key "time2reboot"
        $Script:ASOUofBackDoorUser = Get-KeyValue -key "BDUsersOU"
        $Script:ASSearchBase = Get-KeyValue -key "MySearchBase"
        $Script:ASOfflineDITFile = Get-KeyValue -key "OfflineDITFile"
        $Script:ASAppServer = Get-KeyValue -key "myAppServer"
        $Script:ASHoneyToken = Get-KeyValue -key  "honeytoken"
        $Script:ASOUofBackDoorUser = Get-KeyValue -key "BDUsersOU"
        $Script:ASTools = Get-Keyvalue -key "Tools"

        if ($ReadOnly) { return }
        
        $temp = Get-KeyValue -key  "Tools"
        If ($temp.tolower() -eq ".\tools") {
            Set-keyValue -key  "Tools" -NewValue $Script:ASTools
            $Script:ASTools = Get-Keyvalue -key "Tools"
        }
        else {
            $Script:ASTools = Get-Keyvalue -key "Tools"
        } 
        
        $temp = Get-KeyValue -key  "BDUsersOU"
        If ($temp.tolower() -eq "CN=Users,DC=xxx,DC=xxx".ToLower()) {
            Set-keyValue -key  "BDUsersOU" -NewValue (Get-ADDomain).UsersContainer
            $Script:ASOUofBackDoorUser = Get-KeyValue -key "BDUsersOU"
        }
        else {
            $Script:ASOUofBackDoorUser = Get-KeyValue -key "BDUsersOU"
        }

        # fill the arrays
        $MyParameter = @("Logon Server / DC ", `
                "Victim PC ", `
                "Admin PC ", `
                "Application Server ", `
                "Help Desk Group ", `
                "MDI Honeytoken ", `
                "Domain Name ", `
                "Domain siD ", `
                "NTML Hash Helpdesk ", `
                "NTML Hash krbtgt ", `
                "Seconds to reboot ", `
                "AD Search Base ", `
                "OU for BD User ", `
                "Tickets UNC Path (suffix) ", `
                "Tickets Directory ", `
                "NTDS Dit File (Backup) ", `
                "Tools (e.g. mimikatz) ", `
                "OpenSSL start path ")

        $MyValue = @($Script:ASDC, `
                $Script:ASVictimMaschine, `
                $Script:ASSAW, `
                $Script:ASAppServer, `
                $Script:ASHelpDesk, `
                $Script:ASHoneyToken, `
                $Script:ASDomain, `
                $Script:ASDomainSID, `
                $Script:ASPtHntml, `
                $Script:ASKrbtgtNtml, `
                $Script:ASTime2Reboot, `
                $Script:ASSearchBase, `
                $Script:ASOUofBackDoorUser, `
                $Script:ASTicketsUNCPath, `
                $Script:ASTicketsDirectory, `
                $Script:ASOfflineDITFile, `
                $Script:ASTools, `
                $Script:ASOPenSSL)

        $MyKey = @("myDC", `
                "myViPC", `
                "mySAW", `
                "myAppServer", `
                "globalHelpDesk", `
                "honeytoken", `
                "DomainName", `
                "DomainSID", `
                "pthntml", `
                "krbtgtntml", `
                "time2reboot", `
                "MySearchBase", `
                "BDUsersOU", `
                "ticketsUNCPath", `
                "ticketsDir", `
                "OfflineDITFile", `
                "Tools", `
                "OpenSSL")

        for ($counter = 0; $counter -lt $MyParameter.Length; $counter++ ) {
            write-host ([string]$counter).PadLeft(4, ' ') ":" $MyParameter.Get($counter) " = " $MyValue.Get($counter)
        }

        $decision = Show-DecisionPrompt -Message $message  -Options $Options -Default 0 -Title $title

        switch ($decision) {

            "Yes" {
                $repeat = $Script:No
            }
            "No" {

                $counter = 10

                if ($prompt -match '^(\d|\d\d)$') {
                    If ([int]$prompt -gt 0 -and [int]$prompt -lt 20) {
                        $counter = $prompt
                    }
                    else {
                        $question = "Please enter the desired setting number. Default "
                        $counter = Get-Answer -question $question -defaultValue $counter
                    }
                }
                else {
                    $question = "Please enter the desired setting number. Default "
                    $counter = Get-Answer -question $question -defaultValue $counter
                }

                try {

                    write-host "`n Change value for '$($MyParameter.Get($counter).trim())' = $($MyValue.Get($counter))" -ForegroundColor $Script:FGCCommand
                
                    If ($counter -match '^(11|12)$') {
                        $result = Select-ADObject
                        $newvaulue = $result
                    }
                    elseif ($counter -match '^(16)$') {
                        $newvaulue = Get-FolderPath -InitialDirectory 'C:\' -Description 'Please select the tools folder (with mimikatz.exe)'
                    }
                    else {
                        $newvaulue = Invoke-Output -Type Input -Message "Please enter the new value"
                    }
                    Set-KeyValue -key $MyKey.Get($counter)  -NewValue $newvaulue
                }
                catch {
                    write-host  "$counter = Wrong Input"
                }
                Finally {
                    Get-AS2GoSettings
                }
            }
            "Quit" {
                Write-Log -Message "Skipped AS2Go Lab Setup!"
                $repeat = $Script:No
            }
        }

        $firstrun = $false
        clear-host
    } Until ($repeat -eq $no)

    ######################## main code ############################
    $runtime = Get-RunTime -StartRunTime $StartRunTime
    Write-Log -Message " Run Time: $runtime [h] ###"
    Write-Log -Message "### End Function $CurrentFunction ###"
}