Update module/Samy.UI.ps1
This commit is contained in:
348
module/Samy.UI.ps1
Normal file
348
module/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