Private/MenuHandlers.ps1
|
# Start-NSPADManager's menu actions. Each gathers what it needs, then calls the public functions; # every change goes through Invoke-NSPStep, so DRY RUN is honoured. function Write-NSPADScreen { param([Parameter(Mandatory)][string]$Title) Clear-NSPConsole Write-NSPConsoleHeader -Title $Title -Subtitle 'AD Manager' Write-Host '' } function Wait-NSPADReturn { Read-Host "`nPress Enter to return to the menu" | Out-Null } function Get-NSPADScaffoldAnswers { # The answers the scaffold plan reads: this server's saved AD answers when they carry scaffold # fields, else optionally a ClientAnswers\<Abbrev>.json file, else $null (generic defaults). $saved = $script:ADAnswers $scaffoldFields = @('Auth_UserGroup_Value', 'VPNFW_DNS_Mode') + @(Get-NSPADPurposeGroupDefault | ForEach-Object AnswersField) if ($saved -and @($scaffoldFields | Where-Object { $saved.PSObject.Properties[$_] }).Count) { $label = if ($saved.PSObject.Properties['CompanyName'] -and $saved.CompanyName) { " for $($saved.CompanyName)" } else { '' } if (Read-NSPConfirm -Prompt "Use the saved answers$($label)?" -DefaultYes) { return $saved } } if (-not (Read-NSPConfirm -Prompt "Read defaults from a client's saved answers file (ClientAnswers\<Abbrev>.json)?")) { return $null } $path = (Read-NSPNonEmpty -Prompt 'Path to the answers file').Trim('"') if (-not (Test-Path -LiteralPath $path)) { Write-Host " '$path' not found - using generic defaults instead." -ForegroundColor Yellow return $null } try { return (Get-Content -LiteralPath $path -Raw | ConvertFrom-Json) } catch { Write-Host " Could not parse '$path' ($($_.Exception.Message)) - using generic defaults instead." -ForegroundColor Yellow return $null } } function Invoke-NSPADMenuPrereqs { Write-NSPADScreen 'Install RSAT / management modules' $st = Get-NSPADPrerequisiteStatus $adText = if ($st.ActiveDirectory) { 'present' } else { 'MISSING - needed for menu 2/3 (group/OU scaffold)' } $gpText = if ($st.GroupPolicy) { 'present' } else { 'MISSING - needed for menu 4/5 (GPO, WMI filters)' } Write-NSPConsoleLine " ActiveDirectory module : $adText" -Role $(if ($st.ActiveDirectory) { 'Success' } else { 'Warning' }) Write-NSPConsoleLine " GroupPolicy module : $gpText" -Role $(if ($st.GroupPolicy) { 'Success' } else { 'Warning' }) Write-Host '' if (Read-NSPConfirm -Prompt 'Proceed?' -DefaultYes) { Install-NSPADPrerequisite } Wait-NSPADReturn } function Invoke-NSPADMenuScaffold { Write-NSPADScreen 'Stand up the VPN group/OU scaffold' if (-not (Get-Command Get-ADOrganizationalUnit -ErrorAction SilentlyContinue)) { Write-NSPConsoleLine ' ActiveDirectory module not available - run menu 1 (Install RSAT) first.' -Role Error Wait-NSPADReturn; return } $clientAnswers = Get-NSPADScaffoldAnswers Write-Host '' Write-NSPConsoleLine ' Pick the base OU everything gets created under:' -Role Heading $baseOU = Select-NSPADOrganizationalUnit if (-not $baseOU) { Write-NSPConsoleLine ' Cancelled - no OU selected.' -Role Muted Wait-NSPADReturn; return } $plan = Get-NSPADScaffoldPlan -ClientAnswers $clientAnswers -BaseOU $baseOU Write-Host "`n About to create:" -ForegroundColor Cyan Show-NSPADScaffoldPlan -Plan $plan if (Read-NSPConfirm -Prompt 'Create/update this scaffold now?' -DefaultYes) { New-NSPADVpnGroupScaffold -Plan $plan Write-NSPConsoleLine "`n Done." -Role Success } Wait-NSPADReturn } function Show-NSPADScaffoldPlan { param([Parameter(Mandatory)]$Plan) Write-Host '' Write-Host " $($Plan.BaseOU)" -ForegroundColor Gray Write-Host ' VPNGroups\' -ForegroundColor White Write-Host " $($Plan.MainGroupName)" -ForegroundColor Green Write-Host ' FWRules\' -ForegroundColor White foreach ($pg in $Plan.PurposeGroups) { Write-Host " $($pg.Name) ($($pg.Key))" -ForegroundColor Green } Write-Host '' } function Invoke-NSPADMenuNestGroup { Write-NSPADScreen 'Nest a group into the shared VPNFW purpose groups' if (-not (Get-Command Get-ADGroup -ErrorAction SilentlyContinue)) { Write-NSPConsoleLine ' ActiveDirectory module not available - run menu 1 (Install RSAT) first.' -Role Error Wait-NSPADReturn; return } Write-NSPConsoleLine ' Pick the FWRules\ OU the purpose groups live under:' -Role Heading $fwRulesOU = Select-NSPADOrganizationalUnit if (-not $fwRulesOU) { Write-NSPConsoleLine ' Cancelled - no OU selected.' -Role Muted Wait-NSPADReturn; return } $purposeGroups = @(Get-ADGroup -SearchBase $fwRulesOU -SearchScope OneLevel -Filter * -ErrorAction SilentlyContinue | Sort-Object Name) if (-not $purposeGroups.Count) { Write-NSPConsoleLine " No groups found directly under '$fwRulesOU' - run menu 2 first, or pick a different OU." -Role Warning Wait-NSPADReturn; return } $memberName = Read-NSPNonEmpty -Prompt 'AD group to nest (exact name)' $memberGroup = Get-ADGroup -Filter "Name -eq '$($memberName.Replace("'", "''"))'" -ErrorAction SilentlyContinue if (-not $memberGroup) { Write-NSPConsoleLine " No group named '$memberName' found - nothing nested." -Role Warning Wait-NSPADReturn; return } Write-Host '' for ($i = 0; $i -lt $purposeGroups.Count; $i++) { Write-Host (' {0}. {1}' -f ($i + 1), $purposeGroups[$i].Name) } Write-Host '' $sel = Read-NSPOptional -Prompt "Numbers to nest '$memberName' into (comma-separated), or blank to cancel" $picked = @($sel -split '[,\s]+' | Where-Object { $_ -match '^\d+$' } | ForEach-Object { [int]$_ - 1 } | Where-Object { $_ -ge 0 -and $_ -lt $purposeGroups.Count } | ForEach-Object { $purposeGroups[$_] }) if (-not $picked.Count) { Write-NSPConsoleLine ' Nothing selected - cancelled.' -Role Muted Wait-NSPADReturn; return } foreach ($pg in $picked) { Add-NSPADGroupMember -GroupIdentity $pg.DistinguishedName -MemberIdentity $memberGroup.DistinguishedName } Wait-NSPADReturn } function Invoke-NSPADMenuAutoEnrollGpo { Write-NSPADScreen 'Push the certificate auto-enrollment GPO' if (-not (Get-Command Get-GPO -ErrorAction SilentlyContinue)) { Write-NSPConsoleLine ' GroupPolicy module not available - run menu 1 (Install RSAT) first.' -Role Error Wait-NSPADReturn; return } $gpoName = Read-NSPNonEmpty -Prompt 'GPO name' -CurrentValue 'NSP - Certificate Auto-Enrollment' Write-Host '' Write-Host " GPO: $gpoName (dedicated - Default Domain Policy is not touched)" -ForegroundColor White Write-Host ' Linked at the domain root.' -ForegroundColor Gray foreach ($v in (Get-NSPADAutoEnrollGpoPlan)) { Write-Host (' [{0}] {1}\{2} = {3} ({4})' -f $v.Hive, $v.Key, $v.ValueName, $v.Value, $v.Type) -ForegroundColor Gray } Write-Host ' AEPolicy 7 = enrolled + renew/update/remove-revoked + update-templates' -ForegroundColor DarkGray if (Read-NSPConfirm -Prompt "`nProceed?" -DefaultYes) { New-NSPADAutoEnrollGpo -GpoName $gpoName } Wait-NSPADReturn } function Invoke-NSPADMenuWmiFilters { Write-NSPADScreen 'Stand up the well-known WMI filters' if (-not (Get-Command Get-GPO -ErrorAction SilentlyContinue)) { Write-NSPConsoleLine ' GroupPolicy module not available - run menu 1 (Install RSAT) first.' -Role Error Wait-NSPADReturn; return } $filters = @(Get-NSPADWellKnownWmiFilter) Write-NSPConsoleLine ' Will create/update:' -Role Heading foreach ($f in $filters) { Write-Host " $($f.Name)" -ForegroundColor Gray } if (-not (Read-NSPConfirm -Prompt "`nProceed?" -DefaultYes)) { Wait-NSPADReturn; return } try { # Written through ADSI (0.1.4) - the BW.Utils module Install-NSPADWmiFilterModule fetched isn't needed. foreach ($f in $filters) { New-NSPADWmiFilter -Filter $f } Write-NSPConsoleLine "`n Done." -Role Success } catch { Write-NSPConsoleLine "`n ERROR: $($_.Exception.Message)" -Role Error } Wait-NSPADReturn } function Invoke-NSPADMenuVpnInventory { Write-NSPADScreen 'Export VPN documentation inventory (read-only)' Write-NSPConsoleLine ' Collects VPN groups (members, nesting, SIDs), client-auth certificate templates' -Role Muted Write-NSPConsoleLine ' (Enroll/AutoEnroll groups), and TameMyCerts OU stamps into one hand-off file.' -Role Muted Write-NSPConsoleLine ' Run on the CA/NPS server when possible: ias.xml and the TameMyCerts policy folder are found automatically.' -Role Muted Write-Host '' $patterns = Read-NSPNonEmpty -Prompt 'Group name patterns (comma-separated)' -CurrentValue 'IKEv2*, VPNFW*, FGT*' $groupPattern = @($patterns -split '\s*,\s*' | Where-Object { $_ }) $npsPath = '' if (-not (Test-Path (Join-Path $env:SystemRoot 'System32\ias\ias.xml'))) { $answer = (Read-NSPOptional -Prompt "Path to a copy of the NPS server's ias.xml (blank to skip - NPS-named groups then rely on the patterns)").Trim('"') if ($answer -and (Test-Path -LiteralPath $answer)) { $npsPath = $answer } } $policyDirectory = '' if (-not (Get-ADInvTameMyCertsDirectory)) { $answer = (Read-NSPOptional -Prompt 'TameMyCerts policy folder (blank to skip - OU stamps are then left out)').Trim('"') if ($answer -and (Test-Path -LiteralPath $answer)) { $policyDirectory = $answer } } $savedCompany = if ($script:ADAnswers -and $script:ADAnswers.PSObject.Properties['CompanyName']) { [string]$script:ADAnswers.CompanyName } else { '' } $company = Read-NSPNonEmpty -Prompt 'Client (company) name for the file' -CurrentValue $savedCompany $outputDirectory = Read-NSPNonEmpty -Prompt 'Output folder' -CurrentValue (Get-NSPToolWorkPath -Tool AD -Kind Responses) try { $result = Export-NSPADVpnInventory -OutputDirectory $outputDirectory -Company $company -GroupPattern $groupPattern -NpsConfigPath $npsPath -PolicyDirectory $policyDirectory Write-Host '' Write-NSPConsoleLine (' Groups: {0} Templates: {1} TameMyCerts policies: {2}' -f $result.Groups, $result.Templates, $result.TameMyCertsPolicies) -Role Success Write-NSPConsoleLine " Written: $($result.Path)" -Role Success Write-NSPConsoleLine " Copy it to the Orchestrator's Staging\<Client>\Inbox\ folder (with the ias.xml for the VPN report)." -Role Heading Write-NSPConsoleLine ' Opening the folder in Explorer (accept the access prompt if one appears).' -Role Muted Open-NSPOutputFolder -Path $result.Path } catch { Write-NSPConsoleLine "`n ERROR: $($_.Exception.Message)" -Role Error } Wait-NSPADReturn } function Invoke-NSPADMenuLegacyCleanup { Write-NSPADScreen 'Clean up old AD-Manager (zip) files' Write-NSPConsoleLine ' Moves answers and hand-off files the zip-era AD-Manager left on this server into' -Role Muted Write-NSPConsoleLine " $(Get-NSPToolWorkPath -Tool AD), then removes the old copies (you are asked first)." -Role Muted $summary = Move-NSPToolLegacyData -Tool AD if ($summary.Found) { $script:ADAnswers = Get-NSPToolAnswers -Tool AD } Wait-NSPADReturn } |