Add test/Samy.UI.ps1
This commit is contained in:
348
test/Samy.UI.ps1
Normal file
348
test/Samy.UI.ps1
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
# Samy.UI.ps1
|
||||||
|
# Task metadata and UI HTML generation
|
||||||
|
|
||||||
|
# Global task definitions used by UI and headless offboard
|
||||||
|
$Global:SamyTasks = @(
|
||||||
|
# On-Boarding, left column
|
||||||
|
@{ Id='setSVSPowerplan'; Name='setSVSPowerplan'; Label='Set SVS Powerplan'; HandlerFn='Invoke-setSVSPowerPlan'; Page='onboard'; Column='left' },
|
||||||
|
@{ Id='installSVSMSPModule'; Name='installSVSMSPModule'; Label='Install SVSMSP Module'; HandlerFn='Invoke-InstallSVSMSP'; Page='onboard'; Column='left' },
|
||||||
|
@{ Id='installCyberQP'; Name='installCyberQP'; Label='Install CyberQP'; HandlerFn='Invoke-InstallCyberQP'; Page='onboard'; Column='left' },
|
||||||
|
@{ Id='installHelpDesk'; Name='installHelpDesk'; Label='Install HelpDesk'; HandlerFn='Invoke-InstallHelpDesk'; Page='onboard'; Column='left' },
|
||||||
|
@{ Id='installThreatLocker'; Name='installThreatLocker'; Label='Install ThreatLocker'; HandlerFn='Invoke-InstallThreatLocker'; Page='onboard'; Column='left' },
|
||||||
|
@{ Id='installRocketCyber'; Name='installRocketCyber'; Label='Install RocketCyber'; HandlerFn='Invoke-InstallRocketCyber'; Page='onboard'; Column='left' },
|
||||||
|
@{ Id='installDattoRMM'; Name='installDattoRMM'; Label='Install DattoRMM'; HandlerFn='Invoke-InstallDattoRMM'; Page='onboard'; Column='left';
|
||||||
|
SubOptions= @(
|
||||||
|
@{ Value='inputVar'; Label='Copy Site Variables' },
|
||||||
|
@{ Value='rmm'; Label='Install RMM Agent' },
|
||||||
|
@{ Value='exe'; Label='Download Executable' }
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
# On-Boarding, right column
|
||||||
|
@{ Id='enableBitLocker'; Name='EnableBitLocker'; Label='Enable BitLocker'; HandlerFn='Set-SVSBitLocker'; Page='onboard'; Column='right' },
|
||||||
|
@{ Id='setEdgeDefaultSearch'; Name='setedgedefaultsearch'; Label='Set Edge Default Search'; Tooltip='Will configure Edge to use Google as default search provider'; HandlerFn='Invoke-SetEdgeDefaultSearchEngine'; Page='onboard'; Column='right' },
|
||||||
|
|
||||||
|
# Off-Boarding
|
||||||
|
@{ Id='offUninstallCyberQP'; Name='offUninstallCyberQP'; Label='Uninstall CyberQP'; HandlerFn='Invoke-UninstallCyberQP'; Page='offboard' },
|
||||||
|
@{ Id='offUninstallHelpDesk'; Name='offUninstallHelpDesk'; Label='Uninstall HelpDesk'; HandlerFn='Invoke-UninstallHelpDesk'; Page='offboard' },
|
||||||
|
@{ Id='offUninstallThreatLocker'; Name='offUninstallThreatLocker'; Label='Uninstall ThreatLocker'; HandlerFn='Invoke-UninstallThreatLocker'; Page='offboard' },
|
||||||
|
@{ Id='offUninstallRocketCyber'; Name='offUninstallRocketCyber'; Label='Uninstall RocketCyber'; HandlerFn='Invoke-UninstallRocketCyber'; Page='offboard' },
|
||||||
|
@{ Id='offCleanupSVSMSPModule'; Name='offCleanupSVSMSPModule'; Label='Cleanup SVSMSP Toolkit'; HandlerFn='Invoke-CleanupSVSMSP'; Page='offboard' },
|
||||||
|
|
||||||
|
# Tweaks
|
||||||
|
@{ Id='disableAnimations'; Name='disableAnimations'; Label='Disable Animations'; HandlerFn='Disable-Animations'; Page='tweaks' },
|
||||||
|
|
||||||
|
# SVS Apps
|
||||||
|
@{ Id='wingetLastpass'; Name='wingetLastpass'; Label='LastPass Desktop App'; HandlerFn='Install-WingetLastPass'; Page='SVSApps' },
|
||||||
|
@{ Id='wingetChrome'; Name='wingetChrome'; Label='Google Chrome'; HandlerFn='Invoke-InstallChrome'; Page='SVSApps' },
|
||||||
|
@{ Id='wingetAcrobat'; Name='wingetAcrobat'; Label='Adobe Acrobat Reader (64-bit)'; HandlerFn='Invoke-InstallAcrobat'; Page='SVSApps' }
|
||||||
|
)
|
||||||
|
|
||||||
|
Write-LogHybrid "Tasks by page: onboard=$(
|
||||||
|
($Global:SamyTasks | Where-Object Page -eq 'onboard').Count
|
||||||
|
) offboard=$(
|
||||||
|
($Global:SamyTasks | Where-Object Page -eq 'offboard').Count
|
||||||
|
) tweaks=$(
|
||||||
|
($Global:SamyTasks | Where-Object Page -eq 'tweaks').Count
|
||||||
|
) apps=$(
|
||||||
|
($Global:SamyTasks | Where-Object Page -eq 'SVSApps').Count
|
||||||
|
)" Info UI -LogToEvent
|
||||||
|
|
||||||
|
function Publish-Checkboxes {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)][string]$Page,
|
||||||
|
[string]$Column
|
||||||
|
)
|
||||||
|
|
||||||
|
$tasks = $Global:SamyTasks | Where-Object Page -EQ $Page
|
||||||
|
|
||||||
|
if (-not [string]::IsNullOrEmpty($Column)) {
|
||||||
|
$tasks = $tasks | Where-Object Column -EQ $Column
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
$tasks |
|
||||||
|
ForEach-Object {
|
||||||
|
$taskId = $_.Id
|
||||||
|
$tooltip = if ($_.PSObject.Properties.Name -contains 'Tooltip' -and $_.Tooltip) {
|
||||||
|
" title='$($_.Tooltip)'"
|
||||||
|
} else { '' }
|
||||||
|
|
||||||
|
$html = "<label$tooltip><input type='checkbox' id='$taskId' name='$($_.Name)' data-column='$Column'> $($_.Label)</label>"
|
||||||
|
|
||||||
|
if ($_.SubOptions) {
|
||||||
|
$subHtml = (
|
||||||
|
$_.SubOptions |
|
||||||
|
ForEach-Object {
|
||||||
|
"<label style='margin-left:20px; display:block;'>
|
||||||
|
<input type='checkbox' class='sub-option-$taskId' name='$($_.Value)' value='$($_.Value)'> $($_.Label)
|
||||||
|
</label>"
|
||||||
|
}
|
||||||
|
) -join "`n"
|
||||||
|
|
||||||
|
$html += @"
|
||||||
|
<div id='${taskId}OptionsContainer' style='display:none; margin-top:4px;'>
|
||||||
|
$subHtml
|
||||||
|
</div>
|
||||||
|
"@
|
||||||
|
}
|
||||||
|
|
||||||
|
$html
|
||||||
|
}
|
||||||
|
) -join "`n"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-ModuleVersionHtml {
|
||||||
|
$mod = Get-Module -ListAvailable -Name SVSMSP | Sort-Object Version -Descending | Select-Object -First 1
|
||||||
|
|
||||||
|
$branchDisplay = switch ($Script:SamyBranch.ToLower()) {
|
||||||
|
'main' { 'Main / Stable' }
|
||||||
|
'beta' { 'Beta' }
|
||||||
|
default { $Script:SamyBranch }
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mod) {
|
||||||
|
return "<div style='color:#bbb; font-size:0.9em; margin-top:1em;'>
|
||||||
|
Module Version: $($mod.Version)<br>
|
||||||
|
UI Branch: $branchDisplay
|
||||||
|
</div>"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<div style='color:#f66;'>SVSMSP_Module not found</div>"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-RemoteText {
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)][string]$Url
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
$resp = Invoke-WebRequest -Uri $Url -UseBasicParsing -ErrorAction Stop
|
||||||
|
return $resp.Content
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-LogHybrid "Get-RemoteText failed for ${Url}: $($_.Exception.Message)" Warning UI -LogToEvent
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-UIHtml {
|
||||||
|
param([string]$Page = 'onboard')
|
||||||
|
if (-not $Page) { $Page = 'onboard' }
|
||||||
|
|
||||||
|
$onboardLeft = Publish-Checkboxes -Page 'onboard' -Column 'left'
|
||||||
|
$onboardRight = Publish-Checkboxes -Page 'onboard' -Column 'right'
|
||||||
|
$offboard = Publish-Checkboxes -Page 'offboard' -Column ''
|
||||||
|
$tweaks = Publish-Checkboxes -Page 'tweaks' -Column ''
|
||||||
|
$apps = Publish-Checkboxes -Page 'SVSApps' -Column ''
|
||||||
|
|
||||||
|
$tasksJsAll = (
|
||||||
|
$Global:SamyTasks | ForEach-Object {
|
||||||
|
" { id: '$($_.Id)', handler: '/$($_.Name)', label: '$($_.Label)' }"
|
||||||
|
}
|
||||||
|
) -join ",`n"
|
||||||
|
|
||||||
|
$cssContent = Get-RemoteText -Url $Script:SamyCssUrl
|
||||||
|
$jsContent = Get-RemoteText -Url $Script:SamyJsUrl
|
||||||
|
|
||||||
|
if ($cssContent) {
|
||||||
|
$pattern = 'background-image:\s*url\("SAMY\.png"\);?'
|
||||||
|
$replacement = "background-image: url('$Script:SamyBgLogoUrl');"
|
||||||
|
$cssContent = [regex]::Replace($cssContent, $pattern, $replacement)
|
||||||
|
}
|
||||||
|
|
||||||
|
$htmlTemplate = @"
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<title>Script Automation Monkey</title>
|
||||||
|
<link rel="icon" href="$Script:SamyFaviconUrl">
|
||||||
|
<style>
|
||||||
|
$cssContent
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="logo-container">
|
||||||
|
<div class="logo-left">
|
||||||
|
<img src="$Script:SamyTopLogoUrl" alt="SVS Logo">
|
||||||
|
{{moduleVersion}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="tagline" class="tagline">
|
||||||
|
Script Automation Monkey (Yeah!)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="samyHint" class="samy-hint"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="sidebar">
|
||||||
|
<button class="tab-button" data-tab="onboardTab">On-Boarding</button>
|
||||||
|
<button class="tab-button" data-tab="offboardTab">Off-Boarding</button>
|
||||||
|
<button class="tab-button" data-tab="tweaksTab">Tweaks</button>
|
||||||
|
<button class="tab-button" data-tab="SVSAppsTab">SVS APPs</button>
|
||||||
|
<button class="tab-button" data-tab="devicesTab">Devices</button>
|
||||||
|
|
||||||
|
<div id="status-box" style="margin-top: 1em; font-family: monospace;"></div>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div id="onboardTab" class="tab-content">
|
||||||
|
<h2>On-Boarding</h2>
|
||||||
|
<h3 class="subtitle">This new deployment method ensures everything is successfully deployed with greater ease!</h3>
|
||||||
|
|
||||||
|
<div class="columns-container">
|
||||||
|
<div class="checkbox-group column">
|
||||||
|
<h3>SVSMSP Stack</h3>
|
||||||
|
<label><input type="checkbox" id="selectAllLeftCheckbox" onclick="toggleColumn('left')"> Select All</label>
|
||||||
|
{{onboardLeftColumn}}
|
||||||
|
</div>
|
||||||
|
<div class="checkbox-group column">
|
||||||
|
<h3>Optional</h3>
|
||||||
|
<label><input type="checkbox" id="selectAllRightCheckbox" onclick="toggleColumn('right')"> Select All</label>
|
||||||
|
{{onboardRightColumn}}
|
||||||
|
|
||||||
|
<div class="option">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="chkRenameComputer" data-column="right">
|
||||||
|
Rename Computer
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="renameComputerBlock" style="display:none; margin-left: 24px; margin-top: 6px;">
|
||||||
|
<label for="txtNewComputerName">New computer name:</label>
|
||||||
|
<input type="text" id="txtNewComputerName" placeholder="e.g. CORP-LAP-123" />
|
||||||
|
<small style="display:block; margin-top:4px;">
|
||||||
|
(Max 15 chars; letters, numbers, and hyphens only.)
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="PasswordContainer" style="display:none; margin-bottom:1em;">
|
||||||
|
<label for="Password">Enter Password:</label>
|
||||||
|
<div style="display:flex; gap:5px;">
|
||||||
|
<input type="password" id="Password" placeholder="Enter Password" style="flex:1;" />
|
||||||
|
<button onclick="fetchSites()" class="go-button">GO!</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="dattoRmmContainer" style="display:none; margin-bottom:1em;">
|
||||||
|
<label for="dattoDropdown">Select a Datto RMM site:</label>
|
||||||
|
<select id="dattoDropdown" style="width:100%;">
|
||||||
|
<option disabled selected>Fetching sites...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="offboardTab" class="tab-content">
|
||||||
|
<h2>Off-Boarding</h2>
|
||||||
|
<div class="columns-container">
|
||||||
|
<div class="checkbox-group column">
|
||||||
|
<h3>Remove Stack</h3>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="offboardSelectAll" onclick="toggleOffboardAll()">
|
||||||
|
Select All
|
||||||
|
</label>
|
||||||
|
{{offboardCheckboxes}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="tweaksTab" class="tab-content">
|
||||||
|
<h2>Tweaks</h2>
|
||||||
|
<div class="columns-container">
|
||||||
|
<div class="checkbox-group column">
|
||||||
|
<h3>Tweaks</h3>
|
||||||
|
{{tweaksCheckboxes}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="SVSAppsTab" class="tab-content">
|
||||||
|
<h2>SVS APPs</h2>
|
||||||
|
<div class="columns-container">
|
||||||
|
<div class="checkbox-group column">
|
||||||
|
<h3>Applications</h3>
|
||||||
|
{{appsCheckboxes}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="devicesTab" class="tab-content">
|
||||||
|
<h2>Devices</h2>
|
||||||
|
<h3 class="subtitle">Manage printers and other client devices.</h3>
|
||||||
|
|
||||||
|
<div id="printerPasswordContainer" style="margin-bottom:1em;">
|
||||||
|
<label for="PrinterPassword">Enter Printer Password:</label>
|
||||||
|
<div style="display:flex; gap:5px;">
|
||||||
|
<input type="password"
|
||||||
|
id="PrinterPassword"
|
||||||
|
placeholder="Enter printer password"
|
||||||
|
style="flex:1;" />
|
||||||
|
<button onclick="fetchPrinters()" class="go-button">Get Printers</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="printerClientContainer" style="display:none; margin-bottom:1em;">
|
||||||
|
<label for="printerClientDropdown">Select Client:</label>
|
||||||
|
<select id="printerClientDropdown" style="width:100%;">
|
||||||
|
<option disabled selected>Fetch printers first...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="printerListContainer" style="display:none; margin-bottom:1em;">
|
||||||
|
<label>Printers for selected client:</label>
|
||||||
|
<small style="display:block; margin-bottom:4px; opacity:0.8;">
|
||||||
|
Check the printers to install, and mark one as "Make default" (optional).
|
||||||
|
</small>
|
||||||
|
|
||||||
|
<div id="printerCheckboxContainer"
|
||||||
|
style="max-height:200px; overflow-y:auto; border:1px solid #444; padding:6px; border-radius:4px;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button id="installPrintersButton"
|
||||||
|
class="go-button"
|
||||||
|
style="margin-top:8px;"
|
||||||
|
onclick="installSelectedPrinters()">
|
||||||
|
Install Selected Printers
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.SAMY_TASKS = [
|
||||||
|
{{tasksJsAll}}
|
||||||
|
];
|
||||||
|
window.SAMY_DEFAULT_PAGE = "{{defaultPage}}";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$jsContent
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="fixed-buttons">
|
||||||
|
<button class="exit-button" onclick="endSession()">Exit</button>
|
||||||
|
<button class="run-button" onclick="triggerInstall()">Run Selected</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"@
|
||||||
|
|
||||||
|
$html = $htmlTemplate
|
||||||
|
$html = $html.Replace('{{moduleVersion}}', (Get-ModuleVersionHtml))
|
||||||
|
$html = $html.Replace('{{onboardLeftColumn}}', $onboardLeft)
|
||||||
|
$html = $html.Replace('{{onboardRightColumn}}', $onboardRight)
|
||||||
|
$html = $html.Replace('{{offboardCheckboxes}}', $offboard)
|
||||||
|
$html = $html.Replace('{{tweaksCheckboxes}}', $tweaks)
|
||||||
|
$html = $html.Replace('{{appsCheckboxes}}', $apps)
|
||||||
|
$html = $html.Replace('{{tasksJsAll}}', $tasksJsAll)
|
||||||
|
$html = $html.Replace('{{defaultPage}}', $Page)
|
||||||
|
|
||||||
|
return $html
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user