Add per-feature toggles to PS scripts and Go TUI
- 02-software.ps1: wrap wingetInstalls, pdfDefault, ateraAgent in Get-Feature guards - 03-system-registry.ps1: add Get-Feature, restructure into 5 gated blocks (systemTweaks, edgePolicies, oneDriveUninstall, powercfg, proxyDisable) - 04-default-profile.ps1: add Get-Feature, wrap taskbarTweaks, startMenuTweaks, explorerTweaks; add missing explorerTweaks code (ShowRecent, ShowFrequent, FullPath) - 11-dell-update.ps1: add Get-Feature, split update run by drivers/bios feature flags - runner.go: add Feature/StepFeatures/SelectableItem/AllSelectableItems for TUI - config.go: add Features type and defaults for all 4 gated steps - tui.go: use AllSelectableItems for MultiSelect, build Features map in startRun, remove unused stepFeaturesMap variable - xetup.exe: Windows amd64 build Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a10a3a8aa2
commit
5b53b2a0d6
8 changed files with 590 additions and 378 deletions
|
|
@ -13,6 +13,7 @@ type Config struct {
|
||||||
Activation Activation `json:"activation"`
|
Activation Activation `json:"activation"`
|
||||||
Software Software `json:"software"`
|
Software Software `json:"software"`
|
||||||
Steps map[string]bool `json:"steps"`
|
Steps map[string]bool `json:"steps"`
|
||||||
|
Features Features `json:"features"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Deployment struct {
|
type Deployment struct {
|
||||||
|
|
@ -40,6 +41,11 @@ type Software struct {
|
||||||
Install []SoftwareItem `json:"install"`
|
Install []SoftwareItem `json:"install"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Features holds per-step, per-feature toggle flags.
|
||||||
|
// Keys: stepID -> featureID -> enabled.
|
||||||
|
// A missing key defaults to true (feature enabled).
|
||||||
|
type Features map[string]map[string]bool
|
||||||
|
|
||||||
// DefaultConfig returns a config with sensible defaults.
|
// DefaultConfig returns a config with sensible defaults.
|
||||||
func DefaultConfig() Config {
|
func DefaultConfig() Config {
|
||||||
return Config{
|
return Config{
|
||||||
|
|
@ -74,6 +80,29 @@ func DefaultConfig() Config {
|
||||||
"network": true,
|
"network": true,
|
||||||
"pcIdentity": true,
|
"pcIdentity": true,
|
||||||
},
|
},
|
||||||
|
Features: Features{
|
||||||
|
"software": {
|
||||||
|
"wingetInstalls": true,
|
||||||
|
"pdfDefault": true,
|
||||||
|
"ateraAgent": true,
|
||||||
|
},
|
||||||
|
"systemRegistry": {
|
||||||
|
"systemTweaks": true,
|
||||||
|
"edgePolicies": true,
|
||||||
|
"oneDriveUninstall": true,
|
||||||
|
"powercfg": true,
|
||||||
|
"proxyDisable": true,
|
||||||
|
},
|
||||||
|
"defaultProfile": {
|
||||||
|
"taskbarTweaks": true,
|
||||||
|
"startMenuTweaks": true,
|
||||||
|
"explorerTweaks": true,
|
||||||
|
},
|
||||||
|
"dellUpdate": {
|
||||||
|
"drivers": true,
|
||||||
|
"bios": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,81 @@ func AllSteps() []Step {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Feature is a single toggleable sub-item within a deployment step.
|
||||||
|
type Feature struct {
|
||||||
|
ID string
|
||||||
|
Label string
|
||||||
|
}
|
||||||
|
|
||||||
|
// StepFeatures returns per-step feature lists. Steps absent from this map
|
||||||
|
// have no sub-features and are controlled at the step level only.
|
||||||
|
func StepFeatures() map[string][]Feature {
|
||||||
|
return map[string][]Feature{
|
||||||
|
"software": {
|
||||||
|
{ID: "wingetInstalls", Label: "Instalace SW ze seznamu (winget)"},
|
||||||
|
{ID: "pdfDefault", Label: "Adobe Reader jako vychozi PDF"},
|
||||||
|
{ID: "ateraAgent", Label: "Atera RMM agent"},
|
||||||
|
},
|
||||||
|
"systemRegistry": {
|
||||||
|
{ID: "systemTweaks", Label: "Windows tweaky (Widgets, GameDVR, Recall...)"},
|
||||||
|
{ID: "edgePolicies", Label: "Edge policies (tlacitka, vyhledavac, telemetrie)"},
|
||||||
|
{ID: "oneDriveUninstall", Label: "OneDrive uninstall (consumer pre-install)"},
|
||||||
|
{ID: "powercfg", Label: "Nastaveni napajeni (timeout AC/DC)"},
|
||||||
|
{ID: "proxyDisable", Label: "Zakaz WPAD proxy auto-detect"},
|
||||||
|
},
|
||||||
|
"defaultProfile": {
|
||||||
|
{ID: "taskbarTweaks", Label: "Taskbar – zarovnani, tlacitka, layout XML"},
|
||||||
|
{ID: "startMenuTweaks", Label: "Start menu – cisteni pinu, Bing, Copilot"},
|
||||||
|
{ID: "explorerTweaks", Label: "Explorer – pripony, LaunchTo, ShowRecent"},
|
||||||
|
},
|
||||||
|
"dellUpdate": {
|
||||||
|
{ID: "drivers", Label: "Dell drivery + firmware"},
|
||||||
|
{ID: "bios", Label: "Dell BIOS update"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectableItem is a single toggleable row in the TUI checklist.
|
||||||
|
// It represents either a whole step (FeatureID == "") or a specific feature.
|
||||||
|
type SelectableItem struct {
|
||||||
|
Key string // "stepID" or "stepID.featureID"
|
||||||
|
StepID string
|
||||||
|
FeatureID string // empty for step-level items
|
||||||
|
Label string
|
||||||
|
Num string
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllSelectableItems returns the flat ordered list of all TUI toggle rows.
|
||||||
|
// Steps with features are expanded to individual feature rows.
|
||||||
|
// Steps without features appear as a single step-level row.
|
||||||
|
func AllSelectableItems() []SelectableItem {
|
||||||
|
steps := AllSteps()
|
||||||
|
features := StepFeatures()
|
||||||
|
var items []SelectableItem
|
||||||
|
for _, s := range steps {
|
||||||
|
feats, hasFeatures := features[s.ID]
|
||||||
|
if !hasFeatures {
|
||||||
|
items = append(items, SelectableItem{
|
||||||
|
Key: s.ID,
|
||||||
|
StepID: s.ID,
|
||||||
|
Label: s.Num + " – " + s.Name,
|
||||||
|
Num: s.Num,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
for _, f := range feats {
|
||||||
|
items = append(items, SelectableItem{
|
||||||
|
Key: s.ID + "." + f.ID,
|
||||||
|
StepID: s.ID,
|
||||||
|
FeatureID: f.ID,
|
||||||
|
Label: s.Num + " – " + f.Label,
|
||||||
|
Num: s.Num,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
// RunConfig holds runtime parameters passed to each script.
|
// RunConfig holds runtime parameters passed to each script.
|
||||||
type RunConfig struct {
|
type RunConfig struct {
|
||||||
ScriptsDir string
|
ScriptsDir string
|
||||||
|
|
|
||||||
|
|
@ -50,11 +50,11 @@ type Model struct {
|
||||||
cfg config.Config
|
cfg config.Config
|
||||||
|
|
||||||
// form-bound values (huh writes here via pointer)
|
// form-bound values (huh writes here via pointer)
|
||||||
pcName string
|
pcName string
|
||||||
pcDesc string
|
pcDesc string
|
||||||
productKey string
|
productKey string
|
||||||
profileType string
|
profileType string
|
||||||
selectedStepIDs []string
|
selectedItemKeys []string
|
||||||
|
|
||||||
// runner state
|
// runner state
|
||||||
r *runner.Runner
|
r *runner.Runner
|
||||||
|
|
@ -90,10 +90,10 @@ func NewModel(cfg config.Config, runCfg runner.RunConfig) Model {
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
func buildForm(m *Model) *huh.Form {
|
func buildForm(m *Model) *huh.Form {
|
||||||
allSteps := runner.AllSteps()
|
allItems := runner.AllSelectableItems()
|
||||||
opts := make([]huh.Option[string], len(allSteps))
|
opts := make([]huh.Option[string], len(allItems))
|
||||||
for i, s := range allSteps {
|
for i, item := range allItems {
|
||||||
opts[i] = huh.NewOption(s.Num+" - "+s.Name, s.ID).Selected(true)
|
opts[i] = huh.NewOption(item.Label, item.Key).Selected(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
return huh.NewForm(
|
return huh.NewForm(
|
||||||
|
|
@ -121,9 +121,9 @@ func buildForm(m *Model) *huh.Form {
|
||||||
),
|
),
|
||||||
huh.NewGroup(
|
huh.NewGroup(
|
||||||
huh.NewMultiSelect[string]().
|
huh.NewMultiSelect[string]().
|
||||||
Title("Kroky k provedeni (mezernikem odzaskrtnout)").
|
Title("Kroky a nastaveni (mezernikem odzaskrtnout)").
|
||||||
Options(opts...).
|
Options(opts...).
|
||||||
Value(&m.selectedStepIDs),
|
Value(&m.selectedItemKeys),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -217,15 +217,42 @@ func (m Model) startRun() (Model, tea.Cmd) {
|
||||||
m.cfg.Deployment.ProfileType = m.profileType
|
m.cfg.Deployment.ProfileType = m.profileType
|
||||||
m.runCfg.ProfileType = m.profileType
|
m.runCfg.ProfileType = m.profileType
|
||||||
|
|
||||||
// build step list with Enabled flag from the user's checklist
|
// Index selected keys for fast lookup
|
||||||
selected := make(map[string]bool, len(m.selectedStepIDs))
|
selectedSet := make(map[string]bool, len(m.selectedItemKeys))
|
||||||
for _, id := range m.selectedStepIDs {
|
for _, key := range m.selectedItemKeys {
|
||||||
selected[id] = true
|
selectedSet[key] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build Features map: feature enabled = its composite key was selected
|
||||||
|
features := make(config.Features)
|
||||||
|
for _, item := range runner.AllSelectableItems() {
|
||||||
|
if item.FeatureID == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if features[item.StepID] == nil {
|
||||||
|
features[item.StepID] = make(map[string]bool)
|
||||||
|
}
|
||||||
|
features[item.StepID][item.FeatureID] = selectedSet[item.Key]
|
||||||
|
}
|
||||||
|
m.cfg.Features = features
|
||||||
|
|
||||||
|
// Determine which steps are enabled:
|
||||||
|
// - step with features: enabled if at least one feature selected
|
||||||
|
// - step without features: enabled if step key selected
|
||||||
|
stepEnabled := make(map[string]bool)
|
||||||
|
for _, item := range runner.AllSelectableItems() {
|
||||||
|
if item.FeatureID == "" {
|
||||||
|
stepEnabled[item.StepID] = selectedSet[item.Key]
|
||||||
|
} else if selectedSet[item.Key] {
|
||||||
|
// any feature selected enables the step
|
||||||
|
stepEnabled[item.StepID] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
allSteps := runner.AllSteps()
|
allSteps := runner.AllSteps()
|
||||||
steps := make([]runner.Step, len(allSteps))
|
steps := make([]runner.Step, len(allSteps))
|
||||||
for i, s := range allSteps {
|
for i, s := range allSteps {
|
||||||
s.Enabled = selected[s.ID]
|
s.Enabled = stepEnabled[s.ID]
|
||||||
steps[i] = s
|
steps[i] = s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,18 @@ function Write-Log {
|
||||||
Add-Content -Path $LogFile -Value $line -Encoding UTF8
|
Add-Content -Path $LogFile -Value $line -Encoding UTF8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Get-Feature {
|
||||||
|
param([object]$Cfg, [string]$StepID, [string]$FeatureID, [bool]$Default = $true)
|
||||||
|
try {
|
||||||
|
if ($null -eq $Cfg) { return $Default }
|
||||||
|
$stepFeatures = $Cfg.features.$StepID
|
||||||
|
if ($null -eq $stepFeatures) { return $Default }
|
||||||
|
$val = $stepFeatures.$FeatureID
|
||||||
|
if ($null -eq $val) { return $Default }
|
||||||
|
return [bool]$val
|
||||||
|
} catch { return $Default }
|
||||||
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Check winget availability
|
# Check winget availability
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
@ -62,40 +74,39 @@ Write-Log "winget found: $($winget.Source -or $winget)" -Level OK
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Install packages from config
|
# Install packages from config
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
if (-not $Config -or -not $Config.software -or -not $Config.software.install) {
|
if (Get-Feature $Config "software" "wingetInstalls") {
|
||||||
Write-Log "No software list in config - skipping installs" -Level WARN
|
if (-not $Config -or -not $Config.software -or -not $Config.software.install) {
|
||||||
} else {
|
Write-Log "No software list in config - skipping installs" -Level WARN
|
||||||
foreach ($pkg in $Config.software.install) {
|
} else {
|
||||||
Write-Log "Installing $($pkg.name) ($($pkg.wingetId))" -Level INFO
|
foreach ($pkg in $Config.software.install) {
|
||||||
$result = & winget install --id $pkg.wingetId `
|
Write-Log "Installing $($pkg.name) ($($pkg.wingetId))" -Level INFO
|
||||||
--silent `
|
$result = & winget install --id $pkg.wingetId `
|
||||||
--accept-package-agreements `
|
--silent `
|
||||||
--accept-source-agreements `
|
--accept-package-agreements `
|
||||||
--disable-interactivity `
|
--accept-source-agreements `
|
||||||
2>&1
|
--disable-interactivity `
|
||||||
|
2>&1
|
||||||
|
|
||||||
$exitCode = $LASTEXITCODE
|
$exitCode = $LASTEXITCODE
|
||||||
if ($exitCode -eq 0) {
|
if ($exitCode -eq 0) {
|
||||||
Write-Log " Installed OK: $($pkg.name)" -Level OK
|
Write-Log " Installed OK: $($pkg.name)" -Level OK
|
||||||
} elseif ($exitCode -eq -1978335189) {
|
} elseif ($exitCode -eq -1978335189) {
|
||||||
# 0x8A150011 = already installed
|
# 0x8A150011 = already installed
|
||||||
Write-Log " Already installed: $($pkg.name)" -Level OK
|
Write-Log " Already installed: $($pkg.name)" -Level OK
|
||||||
} else {
|
} else {
|
||||||
Write-Log " Failed: $($pkg.name) (exit $exitCode)" -Level ERROR
|
Write-Log " Failed: $($pkg.name) (exit $exitCode)" -Level ERROR
|
||||||
Write-Log " Output: $($result -join ' ')" -Level ERROR
|
Write-Log " Output: $($result -join ' ')" -Level ERROR
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Write-Log "wingetInstalls feature disabled - skipping" -Level INFO
|
||||||
}
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Set Adobe Reader as default PDF app
|
# Set Adobe Reader as default PDF app
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
$forcePdf = $true
|
if (Get-Feature $Config "software" "pdfDefault") {
|
||||||
if ($Config -and $Config.pdfDefault) {
|
|
||||||
$forcePdf = [bool]$Config.pdfDefault.forceAdobeReader
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($forcePdf) {
|
|
||||||
Write-Log "Setting Adobe Reader as default PDF app" -Level INFO
|
Write-Log "Setting Adobe Reader as default PDF app" -Level INFO
|
||||||
|
|
||||||
# Stop UCPD driver before writing file association.
|
# Stop UCPD driver before writing file association.
|
||||||
|
|
@ -160,37 +171,43 @@ if ($forcePdf) {
|
||||||
Write-Log " Could not restart UCPD: $_" -Level WARN
|
Write-Log " Could not restart UCPD: $_" -Level WARN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Write-Log "pdfDefault feature disabled - skipping" -Level INFO
|
||||||
}
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Install Atera RMM Agent
|
# Install Atera RMM Agent
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
Write-Log "Installing Atera RMM Agent" -Level INFO
|
if (Get-Feature $Config "software" "ateraAgent") {
|
||||||
|
Write-Log "Installing Atera RMM Agent" -Level INFO
|
||||||
|
|
||||||
$ateraUrl = "https://x9.servicedesk.atera.com/api/utils/agent-install/windows/?cid=31&aeid=50b72e7113e54a63ac76b96c54c7e337"
|
$ateraUrl = "https://x9.servicedesk.atera.com/api/utils/agent-install/windows/?cid=31&aeid=50b72e7113e54a63ac76b96c54c7e337"
|
||||||
$ateraMsi = "$env:TEMP\AteraAgent.msi"
|
$ateraMsi = "$env:TEMP\AteraAgent.msi"
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Write-Log " Downloading Atera agent..." -Level INFO
|
Write-Log " Downloading Atera agent..." -Level INFO
|
||||||
Invoke-WebRequest -Uri $ateraUrl -OutFile $ateraMsi -UseBasicParsing -ErrorAction Stop
|
Invoke-WebRequest -Uri $ateraUrl -OutFile $ateraMsi -UseBasicParsing -ErrorAction Stop
|
||||||
Write-Log " Download complete" -Level OK
|
Write-Log " Download complete" -Level OK
|
||||||
|
|
||||||
$msiResult = & msiexec /i $ateraMsi /qn 2>&1
|
$msiResult = & msiexec /i $ateraMsi /qn 2>&1
|
||||||
Start-Sleep -Seconds 5
|
Start-Sleep -Seconds 5
|
||||||
|
|
||||||
$ateraExe = "$env:ProgramFiles\ATERA Networks\AteraAgent\AteraAgent.exe"
|
$ateraExe = "$env:ProgramFiles\ATERA Networks\AteraAgent\AteraAgent.exe"
|
||||||
if (Test-Path $ateraExe) {
|
if (Test-Path $ateraExe) {
|
||||||
Write-Log " Atera agent installed" -Level OK
|
Write-Log " Atera agent installed" -Level OK
|
||||||
} else {
|
} else {
|
||||||
Write-Log " Atera agent install may have failed - binary not found at expected path" -Level WARN
|
Write-Log " Atera agent install may have failed - binary not found at expected path" -Level WARN
|
||||||
Write-Log " msiexec output: $($msiResult -join ' ')" -Level WARN
|
Write-Log " msiexec output: $($msiResult -join ' ')" -Level WARN
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
catch {
|
||||||
catch {
|
Write-Log " Atera agent download/install failed: $_" -Level ERROR
|
||||||
Write-Log " Atera agent download/install failed: $_" -Level ERROR
|
}
|
||||||
}
|
finally {
|
||||||
finally {
|
Remove-Item $ateraMsi -Force -ErrorAction SilentlyContinue
|
||||||
Remove-Item $ateraMsi -Force -ErrorAction SilentlyContinue
|
}
|
||||||
|
} else {
|
||||||
|
Write-Log "ateraAgent feature disabled - skipping" -Level INFO
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Log "Step 2 complete" -Level OK
|
Write-Log "Step 2 complete" -Level OK
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,18 @@ function Write-Log {
|
||||||
Add-Content -Path $LogFile -Value $line -Encoding UTF8
|
Add-Content -Path $LogFile -Value $line -Encoding UTF8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Get-Feature {
|
||||||
|
param([object]$Cfg, [string]$StepID, [string]$FeatureID, [bool]$Default = $true)
|
||||||
|
try {
|
||||||
|
if ($null -eq $Cfg) { return $Default }
|
||||||
|
$stepFeatures = $Cfg.features.$StepID
|
||||||
|
if ($null -eq $stepFeatures) { return $Default }
|
||||||
|
$val = $stepFeatures.$FeatureID
|
||||||
|
if ($null -eq $val) { return $Default }
|
||||||
|
return [bool]$val
|
||||||
|
} catch { return $Default }
|
||||||
|
}
|
||||||
|
|
||||||
Add-Type -TypeDefinition @"
|
Add-Type -TypeDefinition @"
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
@ -206,91 +218,7 @@ function Remove-Reg {
|
||||||
Write-Log "3 - Applying HKLM system registry tweaks" -Level STEP
|
Write-Log "3 - Applying HKLM system registry tweaks" -Level STEP
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Bypass Network Requirement on OOBE (BypassNRO)
|
# Always-on: password and timezone (fundamental system settings)
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
Set-Reg -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE" `
|
|
||||||
-Name "BypassNRO" -Value 1
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Disable auto-install of Teams (Chat)
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
Set-Reg -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Communications" `
|
|
||||||
-Name "ConfigureChatAutoInstall" -Value 0
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Disable Cloud Optimized Content (ads in Start menu etc.)
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CloudContent" `
|
|
||||||
-Name "DisableCloudOptimizedContent" -Value 1
|
|
||||||
|
|
||||||
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CloudContent" `
|
|
||||||
-Name "DisableWindowsConsumerFeatures" -Value 1
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Disable Widgets (News and Interests)
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Dsh" `
|
|
||||||
-Name "AllowNewsAndInterests" -Value 0
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Microsoft Edge policies
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
$edgePath = "HKLM:\SOFTWARE\Policies\Microsoft\Edge"
|
|
||||||
|
|
||||||
# UI / first run
|
|
||||||
Set-Reg -Path $edgePath -Name "HideFirstRunExperience" -Value 1
|
|
||||||
Set-Reg -Path $edgePath -Name "DefaultBrowserSettingEnabled" -Value 0
|
|
||||||
|
|
||||||
# New tab page / recommendations
|
|
||||||
Set-Reg -Path $edgePath -Name "NewTabPageContentEnabled" -Value 0
|
|
||||||
Set-Reg -Path $edgePath -Name "ShowRecommendationsEnabled" -Value 0
|
|
||||||
Set-Reg -Path $edgePath -Name "SpotlightExperiencesAndRecommendationsEnabled" -Value 0
|
|
||||||
Set-Reg -Path $edgePath -Name "PersonalizationReportingEnabled" -Value 0
|
|
||||||
|
|
||||||
# Shopping / rewards / sidebar
|
|
||||||
Set-Reg -Path $edgePath -Name "EdgeShoppingAssistantEnabled" -Value 0
|
|
||||||
Set-Reg -Path $edgePath -Name "ShowMicrosoftRewards" -Value 0
|
|
||||||
Set-Reg -Path $edgePath -Name "HubsSidebarEnabled" -Value 0
|
|
||||||
|
|
||||||
# Search suggestions
|
|
||||||
Set-Reg -Path $edgePath -Name "SearchSuggestEnabled" -Value 0
|
|
||||||
Set-Reg -Path $edgePath -Name "ImportOnEachLaunch" -Value 0
|
|
||||||
|
|
||||||
# Telemetry / feedback
|
|
||||||
Set-Reg -Path $edgePath -Name "DiagnosticData" -Value 0
|
|
||||||
Set-Reg -Path $edgePath -Name "FeedbackSurveysEnabled" -Value 0
|
|
||||||
Set-Reg -Path $edgePath -Name "EdgeCollectionsEnabled" -Value 0
|
|
||||||
|
|
||||||
# Toolbar buttons - show
|
|
||||||
Set-Reg -Path $edgePath -Name "FavoritesBarEnabled" -Value 1 # Favorites bar always visible
|
|
||||||
Set-Reg -Path $edgePath -Name "DownloadsButtonEnabled" -Value 1
|
|
||||||
Set-Reg -Path $edgePath -Name "HistoryButtonEnabled" -Value 1
|
|
||||||
Set-Reg -Path $edgePath -Name "PerformanceButtonEnabled" -Value 1 # Sleeping Tabs / Performance
|
|
||||||
|
|
||||||
# Toolbar buttons - hide
|
|
||||||
Set-Reg -Path $edgePath -Name "HomeButtonEnabled" -Value 0
|
|
||||||
Set-Reg -Path $edgePath -Name "SplitScreenEnabled" -Value 0
|
|
||||||
Set-Reg -Path $edgePath -Name "EdgeEDropEnabled" -Value 0 # Drop
|
|
||||||
Set-Reg -Path $edgePath -Name "WebCaptureEnabled" -Value 0 # Screenshot
|
|
||||||
Set-Reg -Path $edgePath -Name "ShareAllowed" -Value 0 # Share
|
|
||||||
|
|
||||||
# Default search engine: Google
|
|
||||||
# SearchProviderEnabled must be 1, SearchProviderName + URL set the provider
|
|
||||||
Set-Reg -Path $edgePath -Name "DefaultSearchProviderEnabled" -Value 1 -Type "DWord"
|
|
||||||
Set-Reg -Path $edgePath -Name "DefaultSearchProviderName" -Value "Google" -Type "String"
|
|
||||||
Set-Reg -Path $edgePath -Name "DefaultSearchProviderSearchURL" `
|
|
||||||
-Value "https://www.google.com/search?q={searchTerms}" -Type "String"
|
|
||||||
# Remove other search engines (empty list = no other providers besides default)
|
|
||||||
Set-Reg -Path $edgePath -Name "ManagedSearchEngines" `
|
|
||||||
-Value '[{"is_default":true,"name":"Google","search_url":"https://www.google.com/search?q={searchTerms}","keyword":"google.com"}]' `
|
|
||||||
-Type "String"
|
|
||||||
|
|
||||||
# Disable desktop shortcut on install/update
|
|
||||||
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\EdgeUpdate" `
|
|
||||||
-Name "CreateDesktopShortcutDefault" -Value 0
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Password - no expiration
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
Write-Log " Setting password max age to UNLIMITED" -Level INFO
|
Write-Log " Setting password max age to UNLIMITED" -Level INFO
|
||||||
$pwResult = & net accounts /maxpwage:UNLIMITED 2>&1
|
$pwResult = & net accounts /maxpwage:UNLIMITED 2>&1
|
||||||
|
|
@ -300,9 +228,6 @@ if ($LASTEXITCODE -eq 0) {
|
||||||
Write-Log " Failed to set password max age: $pwResult" -Level ERROR
|
Write-Log " Failed to set password max age: $pwResult" -Level ERROR
|
||||||
}
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Time zone
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
$tz = "Central Europe Standard Time"
|
$tz = "Central Europe Standard Time"
|
||||||
if ($Config -and $Config.deployment -and $Config.deployment.timezone) {
|
if ($Config -and $Config.deployment -and $Config.deployment.timezone) {
|
||||||
$tz = $Config.deployment.timezone
|
$tz = $Config.deployment.timezone
|
||||||
|
|
@ -316,109 +241,198 @@ catch {
|
||||||
Write-Log " Failed to set time zone: $_" -Level ERROR
|
Write-Log " Failed to set time zone: $_" -Level ERROR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# System tweaks (Windows features, cloud noise, Xbox, Recall, Search UI)
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
if (Get-Feature $Config "systemRegistry" "systemTweaks") {
|
||||||
|
Write-Log " Applying system tweaks" -Level INFO
|
||||||
|
|
||||||
|
# Bypass Network Requirement on OOBE (BypassNRO)
|
||||||
|
Set-Reg -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE" `
|
||||||
|
-Name "BypassNRO" -Value 1
|
||||||
|
|
||||||
|
# Disable auto-install of Teams (Chat)
|
||||||
|
Set-Reg -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Communications" `
|
||||||
|
-Name "ConfigureChatAutoInstall" -Value 0
|
||||||
|
|
||||||
|
# Disable Cloud Optimized Content (ads in Start menu etc.)
|
||||||
|
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CloudContent" `
|
||||||
|
-Name "DisableCloudOptimizedContent" -Value 1
|
||||||
|
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CloudContent" `
|
||||||
|
-Name "DisableWindowsConsumerFeatures" -Value 1
|
||||||
|
|
||||||
|
# Disable Widgets (News and Interests)
|
||||||
|
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Dsh" `
|
||||||
|
-Name "AllowNewsAndInterests" -Value 0
|
||||||
|
|
||||||
|
# Disable Outlook (new) auto-install via UScheduler
|
||||||
|
Write-Log " Disabling Outlook (new) auto-install" -Level INFO
|
||||||
|
$uschedulerPaths = @(
|
||||||
|
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler_Oobe\OutlookUpdate"
|
||||||
|
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler\OutlookUpdate"
|
||||||
|
)
|
||||||
|
foreach ($uPath in $uschedulerPaths) {
|
||||||
|
if (Test-Path $uPath) {
|
||||||
|
try {
|
||||||
|
Remove-Item -Path $uPath -Recurse -Force
|
||||||
|
Write-Log " Removed UScheduler key: $uPath" -Level OK
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log " Failed to remove UScheduler key: $_" -Level WARN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Disable GameDVR
|
||||||
|
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\GameDVR" `
|
||||||
|
-Name "AllowGameDVR" -Value 0
|
||||||
|
|
||||||
|
# Disable Recall (Windows AI feature)
|
||||||
|
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsAI" `
|
||||||
|
-Name "DisableAIDataAnalysis" -Value 1
|
||||||
|
|
||||||
|
# Search on taskbar - hide via HKLM policy (Win11 22H2+ enforcement)
|
||||||
|
# User-level SearchboxTaskbarMode alone is insufficient on newer Win11 builds;
|
||||||
|
# this policy key ensures the setting survives Windows Updates.
|
||||||
|
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Windows Search" `
|
||||||
|
-Name "SearchOnTaskbarMode" -Value 0
|
||||||
|
|
||||||
|
# Start menu - hide Recommended section (Win11)
|
||||||
|
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer" `
|
||||||
|
-Name "HideRecommendedSection" -Value 1
|
||||||
|
} else {
|
||||||
|
Write-Log "systemTweaks feature disabled - skipping" -Level INFO
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Microsoft Edge policies
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
if (Get-Feature $Config "systemRegistry" "edgePolicies") {
|
||||||
|
Write-Log " Applying Edge policies" -Level INFO
|
||||||
|
$edgePath = "HKLM:\SOFTWARE\Policies\Microsoft\Edge"
|
||||||
|
|
||||||
|
# UI / first run
|
||||||
|
Set-Reg -Path $edgePath -Name "HideFirstRunExperience" -Value 1
|
||||||
|
Set-Reg -Path $edgePath -Name "DefaultBrowserSettingEnabled" -Value 0
|
||||||
|
|
||||||
|
# New tab page / recommendations
|
||||||
|
Set-Reg -Path $edgePath -Name "NewTabPageContentEnabled" -Value 0
|
||||||
|
Set-Reg -Path $edgePath -Name "ShowRecommendationsEnabled" -Value 0
|
||||||
|
Set-Reg -Path $edgePath -Name "SpotlightExperiencesAndRecommendationsEnabled" -Value 0
|
||||||
|
Set-Reg -Path $edgePath -Name "PersonalizationReportingEnabled" -Value 0
|
||||||
|
|
||||||
|
# Shopping / rewards / sidebar
|
||||||
|
Set-Reg -Path $edgePath -Name "EdgeShoppingAssistantEnabled" -Value 0
|
||||||
|
Set-Reg -Path $edgePath -Name "ShowMicrosoftRewards" -Value 0
|
||||||
|
Set-Reg -Path $edgePath -Name "HubsSidebarEnabled" -Value 0
|
||||||
|
|
||||||
|
# Search suggestions
|
||||||
|
Set-Reg -Path $edgePath -Name "SearchSuggestEnabled" -Value 0
|
||||||
|
Set-Reg -Path $edgePath -Name "ImportOnEachLaunch" -Value 0
|
||||||
|
|
||||||
|
# Telemetry / feedback
|
||||||
|
Set-Reg -Path $edgePath -Name "DiagnosticData" -Value 0
|
||||||
|
Set-Reg -Path $edgePath -Name "FeedbackSurveysEnabled" -Value 0
|
||||||
|
Set-Reg -Path $edgePath -Name "EdgeCollectionsEnabled" -Value 0
|
||||||
|
|
||||||
|
# Toolbar buttons - show
|
||||||
|
Set-Reg -Path $edgePath -Name "FavoritesBarEnabled" -Value 1 # Favorites bar always visible
|
||||||
|
Set-Reg -Path $edgePath -Name "DownloadsButtonEnabled" -Value 1
|
||||||
|
Set-Reg -Path $edgePath -Name "HistoryButtonEnabled" -Value 1
|
||||||
|
Set-Reg -Path $edgePath -Name "PerformanceButtonEnabled" -Value 1 # Sleeping Tabs / Performance
|
||||||
|
|
||||||
|
# Toolbar buttons - hide
|
||||||
|
Set-Reg -Path $edgePath -Name "HomeButtonEnabled" -Value 0
|
||||||
|
Set-Reg -Path $edgePath -Name "SplitScreenEnabled" -Value 0
|
||||||
|
Set-Reg -Path $edgePath -Name "EdgeEDropEnabled" -Value 0 # Drop
|
||||||
|
Set-Reg -Path $edgePath -Name "WebCaptureEnabled" -Value 0 # Screenshot
|
||||||
|
Set-Reg -Path $edgePath -Name "ShareAllowed" -Value 0 # Share
|
||||||
|
|
||||||
|
# Default search engine: Google
|
||||||
|
# SearchProviderEnabled must be 1, SearchProviderName + URL set the provider
|
||||||
|
Set-Reg -Path $edgePath -Name "DefaultSearchProviderEnabled" -Value 1 -Type "DWord"
|
||||||
|
Set-Reg -Path $edgePath -Name "DefaultSearchProviderName" -Value "Google" -Type "String"
|
||||||
|
Set-Reg -Path $edgePath -Name "DefaultSearchProviderSearchURL" `
|
||||||
|
-Value "https://www.google.com/search?q={searchTerms}" -Type "String"
|
||||||
|
# Remove other search engines (empty list = no other providers besides default)
|
||||||
|
Set-Reg -Path $edgePath -Name "ManagedSearchEngines" `
|
||||||
|
-Value '[{"is_default":true,"name":"Google","search_url":"https://www.google.com/search?q={searchTerms}","keyword":"google.com"}]' `
|
||||||
|
-Type "String"
|
||||||
|
|
||||||
|
# Disable desktop shortcut on install/update
|
||||||
|
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\EdgeUpdate" `
|
||||||
|
-Name "CreateDesktopShortcutDefault" -Value 0
|
||||||
|
} else {
|
||||||
|
Write-Log "edgePolicies feature disabled - skipping" -Level INFO
|
||||||
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# OneDrive - uninstall from clean Windows (no policy block)
|
# OneDrive - uninstall from clean Windows (no policy block)
|
||||||
# NOTE: No policy key is set intentionally - M365 installation can reinstall
|
# NOTE: No policy key is set intentionally - M365 installation can reinstall
|
||||||
# and run OneDrive normally. Policy DisableFileSyncNGSC would prevent that.
|
# and run OneDrive normally. Policy DisableFileSyncNGSC would prevent that.
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
Write-Log " Uninstalling OneDrive" -Level INFO
|
if (Get-Feature $Config "systemRegistry" "oneDriveUninstall") {
|
||||||
|
Write-Log " Uninstalling OneDrive" -Level INFO
|
||||||
|
|
||||||
# Remove OneDriveSetup.exe if present
|
$oneDrivePaths = @(
|
||||||
$oneDrivePaths = @(
|
"$env:SystemRoot\System32\OneDriveSetup.exe"
|
||||||
"$env:SystemRoot\System32\OneDriveSetup.exe"
|
"$env:SystemRoot\SysWOW64\OneDriveSetup.exe"
|
||||||
"$env:SystemRoot\SysWOW64\OneDriveSetup.exe"
|
)
|
||||||
)
|
foreach ($odPath in $oneDrivePaths) {
|
||||||
foreach ($odPath in $oneDrivePaths) {
|
if (Test-Path $odPath) {
|
||||||
if (Test-Path $odPath) {
|
try {
|
||||||
try {
|
& $odPath /uninstall 2>&1 | Out-Null
|
||||||
# Uninstall first
|
Write-Log " OneDrive uninstalled via $odPath" -Level OK
|
||||||
& $odPath /uninstall 2>&1 | Out-Null
|
}
|
||||||
Write-Log " OneDrive uninstalled via $odPath" -Level OK
|
catch {
|
||||||
}
|
Write-Log " OneDrive uninstall failed: $_" -Level WARN
|
||||||
catch {
|
}
|
||||||
Write-Log " OneDrive uninstall failed: $_" -Level WARN
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
# Remove OneDrive Start Menu shortcut
|
# Remove OneDrive Start Menu shortcut
|
||||||
$odLnk = "$env:ProgramData\Microsoft\Windows\Start Menu\Programs\OneDrive.lnk"
|
$odLnk = "$env:ProgramData\Microsoft\Windows\Start Menu\Programs\OneDrive.lnk"
|
||||||
if (Test-Path $odLnk) {
|
if (Test-Path $odLnk) {
|
||||||
Remove-Item $odLnk -Force -ErrorAction SilentlyContinue
|
Remove-Item $odLnk -Force -ErrorAction SilentlyContinue
|
||||||
Write-Log " Removed OneDrive Start Menu shortcut" -Level OK
|
Write-Log " Removed OneDrive Start Menu shortcut" -Level OK
|
||||||
}
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Outlook (new) - disable auto-install via UScheduler
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
Write-Log " Disabling Outlook (new) auto-install" -Level INFO
|
|
||||||
|
|
||||||
$uschedulerPaths = @(
|
|
||||||
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler_Oobe\OutlookUpdate"
|
|
||||||
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler\OutlookUpdate"
|
|
||||||
)
|
|
||||||
foreach ($uPath in $uschedulerPaths) {
|
|
||||||
if (Test-Path $uPath) {
|
|
||||||
try {
|
|
||||||
Remove-Item -Path $uPath -Recurse -Force
|
|
||||||
Write-Log " Removed UScheduler key: $uPath" -Level OK
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Write-Log " Failed to remove UScheduler key: $_" -Level WARN
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Write-Log "oneDriveUninstall feature disabled - skipping" -Level INFO
|
||||||
}
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Disable GameDVR
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\GameDVR" `
|
|
||||||
-Name "AllowGameDVR" -Value 0
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Disable Recall (Windows AI feature)
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsAI" `
|
|
||||||
-Name "DisableAIDataAnalysis" -Value 1
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Search on taskbar - hide via HKLM policy (Win11 22H2+ enforcement)
|
|
||||||
# User-level SearchboxTaskbarMode alone is insufficient on newer Win11 builds;
|
|
||||||
# this policy key ensures the setting survives Windows Updates.
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Windows Search" `
|
|
||||||
-Name "SearchOnTaskbarMode" -Value 0
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Start menu - hide Recommended section (Win11)
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer" `
|
|
||||||
-Name "HideRecommendedSection" -Value 1
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Power configuration
|
# Power configuration
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
Write-Log "Applying power configuration" -Level INFO
|
if (Get-Feature $Config "systemRegistry" "powercfg") {
|
||||||
|
Write-Log " Applying power configuration" -Level INFO
|
||||||
|
|
||||||
$powercfg = @(
|
$powercfgArgs = @(
|
||||||
@("/change", "standby-timeout-ac", "0"), # never sleep on AC
|
@("/change", "standby-timeout-ac", "0"), # never sleep on AC
|
||||||
@("/change", "monitor-timeout-ac", "60"), # screen off after 60 min on AC
|
@("/change", "monitor-timeout-ac", "60"), # screen off after 60 min on AC
|
||||||
@("/change", "standby-timeout-dc", "30"), # sleep after 30 min on battery
|
@("/change", "standby-timeout-dc", "30"), # sleep after 30 min on battery
|
||||||
@("/change", "monitor-timeout-dc", "15") # screen off after 15 min on battery
|
@("/change", "monitor-timeout-dc", "15") # screen off after 15 min on battery
|
||||||
)
|
)
|
||||||
foreach ($args in $powercfg) {
|
foreach ($a in $powercfgArgs) {
|
||||||
$result = & powercfg @args 2>&1
|
$result = & powercfg @a 2>&1
|
||||||
if ($LASTEXITCODE -eq 0) {
|
if ($LASTEXITCODE -eq 0) {
|
||||||
Write-Log " powercfg $($args -join ' ')" -Level OK
|
Write-Log " powercfg $($a -join ' ')" -Level OK
|
||||||
} else {
|
} else {
|
||||||
Write-Log " powercfg $($args -join ' ') failed: $result" -Level WARN
|
Write-Log " powercfg $($a -join ' ') failed: $result" -Level WARN
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Write-Log "powercfg feature disabled - skipping" -Level INFO
|
||||||
}
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Proxy auto-detect disable (WPAD)
|
# Proxy auto-detect disable (WPAD)
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings" `
|
if (Get-Feature $Config "systemRegistry" "proxyDisable") {
|
||||||
-Name "AutoDetect" -Value 0
|
Write-Log " Disabling WPAD proxy auto-detect" -Level INFO
|
||||||
|
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings" `
|
||||||
|
-Name "AutoDetect" -Value 0
|
||||||
|
} else {
|
||||||
|
Write-Log "proxyDisable feature disabled - skipping" -Level INFO
|
||||||
|
}
|
||||||
|
|
||||||
Write-Log "Step 3 complete" -Level OK
|
Write-Log "Step 3 complete" -Level OK
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,18 @@ function Write-Log {
|
||||||
Add-Content -Path $LogFile -Value $line -Encoding UTF8
|
Add-Content -Path $LogFile -Value $line -Encoding UTF8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Get-Feature {
|
||||||
|
param([object]$Cfg, [string]$StepID, [string]$FeatureID, [bool]$Default = $true)
|
||||||
|
try {
|
||||||
|
if ($null -eq $Cfg) { return $Default }
|
||||||
|
$stepFeatures = $Cfg.features.$StepID
|
||||||
|
if ($null -eq $stepFeatures) { return $Default }
|
||||||
|
$val = $stepFeatures.$FeatureID
|
||||||
|
if ($null -eq $val) { return $Default }
|
||||||
|
return [bool]$val
|
||||||
|
} catch { return $Default }
|
||||||
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Helper - apply a registry setting to both Default hive and current HKCU
|
# Helper - apply a registry setting to both Default hive and current HKCU
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
@ -150,157 +162,89 @@ Write-Log "Default hive loaded" -Level OK
|
||||||
|
|
||||||
try {
|
try {
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Taskbar settings (Win10 + Win11)
|
# Taskbar tweaks (alignment, buttons, tray, layout XML)
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
Write-Log "Applying taskbar settings" -Level STEP
|
if (Get-Feature $Config "defaultProfile" "taskbarTweaks") {
|
||||||
|
Write-Log "Applying taskbar tweaks" -Level STEP
|
||||||
|
|
||||||
$tbPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
|
$tbPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
|
||||||
|
|
||||||
# Win11: align taskbar to left (0 = left, 1 = center)
|
# Win11: align taskbar to left (0 = left, 1 = center)
|
||||||
Set-ProfileReg -SubKey $tbPath -Name "TaskbarAl" -Value 0
|
Set-ProfileReg -SubKey $tbPath -Name "TaskbarAl" -Value 0
|
||||||
|
|
||||||
# Hide Search box / button - Win10/11 (0 = hidden, 1 = icon, 2 = full box)
|
# Hide Search box / button - Win10/11 (0 = hidden, 1 = icon, 2 = full box)
|
||||||
# Note: Win11 uses Search subkey, Win10 uses Explorer\Advanced - set both
|
# Note: Win11 uses Search subkey, Win10 uses Explorer\Advanced - set both
|
||||||
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Search" `
|
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Search" `
|
||||||
-Name "SearchboxTaskbarMode" -Value 0
|
-Name "SearchboxTaskbarMode" -Value 0
|
||||||
Set-ProfileReg -SubKey $tbPath -Name "SearchboxTaskbarMode" -Value 0
|
Set-ProfileReg -SubKey $tbPath -Name "SearchboxTaskbarMode" -Value 0
|
||||||
|
|
||||||
# Hide Task View button
|
# Hide Task View button
|
||||||
Set-ProfileReg -SubKey $tbPath -Name "ShowTaskViewButton" -Value 0
|
Set-ProfileReg -SubKey $tbPath -Name "ShowTaskViewButton" -Value 0
|
||||||
|
|
||||||
# Hide Widgets button
|
# Hide Widgets button
|
||||||
Set-ProfileReg -SubKey $tbPath -Name "TaskbarDa" -Value 0
|
Set-ProfileReg -SubKey $tbPath -Name "TaskbarDa" -Value 0
|
||||||
|
|
||||||
# Hide Chat / Teams button
|
# Hide Chat / Teams button
|
||||||
Set-ProfileReg -SubKey $tbPath -Name "TaskbarMn" -Value 0
|
Set-ProfileReg -SubKey $tbPath -Name "TaskbarMn" -Value 0
|
||||||
|
|
||||||
# Hide Copilot button
|
# Hide Copilot button
|
||||||
Set-ProfileReg -SubKey $tbPath -Name "ShowCopilotButton" -Value 0
|
Set-ProfileReg -SubKey $tbPath -Name "ShowCopilotButton" -Value 0
|
||||||
|
|
||||||
# Show file extensions in Explorer
|
# Show all tray icons
|
||||||
Set-ProfileReg -SubKey $tbPath -Name "HideFileExt" -Value 0
|
# EnableAutoTray = 0 works on Win10; Win11 ignores it but set anyway
|
||||||
|
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
|
||||||
|
-Name "EnableAutoTray" -Value 0
|
||||||
|
|
||||||
# Open Explorer to This PC instead of Quick Access
|
# Win11 workaround: clear cached tray icon streams so all icons appear on next login
|
||||||
Set-ProfileReg -SubKey $tbPath -Name "LaunchTo" -Value 1
|
$trayNotifyKey = "HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
|
||||||
|
if (Test-Path $trayNotifyKey) {
|
||||||
|
Remove-ItemProperty -Path $trayNotifyKey -Name "IconStreams" -Force -ErrorAction SilentlyContinue
|
||||||
|
Remove-ItemProperty -Path $trayNotifyKey -Name "PastIconsStream" -Force -ErrorAction SilentlyContinue
|
||||||
|
Write-Log " Cleared TrayNotify icon streams (Win11 systray workaround)" -Level OK
|
||||||
|
}
|
||||||
|
$defTrayKey = "Registry::HKU\DefaultProfile\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
|
||||||
|
if (Test-Path $defTrayKey) {
|
||||||
|
Remove-ItemProperty -Path $defTrayKey -Name "IconStreams" -Force -ErrorAction SilentlyContinue
|
||||||
|
Remove-ItemProperty -Path $defTrayKey -Name "PastIconsStream" -Force -ErrorAction SilentlyContinue
|
||||||
|
Write-Log " Cleared TrayNotify icon streams in Default hive" -Level OK
|
||||||
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# Desktop icons - show This PC
|
||||||
# System tray - show all icons
|
# CLSID {20D04FE0-3AEA-1069-A2D8-08002B30309D} = This PC / Computer
|
||||||
# -----------------------------------------------------------------------
|
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel" `
|
||||||
# EnableAutoTray = 0 works on Win10; Win11 ignores it but set anyway
|
-Name "{20D04FE0-3AEA-1069-A2D8-08002B30309D}" -Value 0
|
||||||
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
|
|
||||||
-Name "EnableAutoTray" -Value 0
|
|
||||||
|
|
||||||
# Win11 workaround: clear cached tray icon streams so all icons appear on next login
|
# Taskbar pinned apps layout (Win10/11)
|
||||||
# Windows rebuilds the streams with all icons visible when no cache exists
|
# ProfileType: default = empty, admin = Explorer+PS+Edge, user = Explorer+Edge
|
||||||
$trayNotifyKey = "HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
|
# Note: TaskbarLayoutModification.xml locks the taskbar temporarily.
|
||||||
if (Test-Path $trayNotifyKey) {
|
# UnlockStartLayout scheduled task removes the lock 5 min after first boot
|
||||||
Remove-ItemProperty -Path $trayNotifyKey -Name "IconStreams" -Force -ErrorAction SilentlyContinue
|
# so users can then customize pins freely.
|
||||||
Remove-ItemProperty -Path $trayNotifyKey -Name "PastIconsStream" -Force -ErrorAction SilentlyContinue
|
# Win11 24H2+ may require ProvisionedLayoutModification.xml format instead.
|
||||||
Write-Log " Cleared TrayNotify icon streams (Win11 systray workaround)" -Level OK
|
Write-Log " Writing taskbar layout (ProfileType=$ProfileType)" -Level INFO
|
||||||
}
|
|
||||||
|
|
||||||
# Also clear in Default hive so new users start with clean state
|
$taskbarLayoutDir = "C:\Users\Default\AppData\Local\Microsoft\Windows\Shell"
|
||||||
$defTrayKey = "Registry::HKU\DefaultProfile\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
|
if (-not (Test-Path $taskbarLayoutDir)) {
|
||||||
if (Test-Path $defTrayKey) {
|
New-Item -ItemType Directory -Path $taskbarLayoutDir -Force | Out-Null
|
||||||
Remove-ItemProperty -Path $defTrayKey -Name "IconStreams" -Force -ErrorAction SilentlyContinue
|
}
|
||||||
Remove-ItemProperty -Path $defTrayKey -Name "PastIconsStream" -Force -ErrorAction SilentlyContinue
|
|
||||||
Write-Log " Cleared TrayNotify icon streams in Default hive" -Level OK
|
|
||||||
}
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
$pinList = switch ($ProfileType) {
|
||||||
# Desktop icons - show This PC
|
"admin" {
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# CLSID {20D04FE0-3AEA-1069-A2D8-08002B30309D} = This PC / Computer
|
|
||||||
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel" `
|
|
||||||
-Name "{20D04FE0-3AEA-1069-A2D8-08002B30309D}" -Value 0
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Start menu settings
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
Write-Log "Applying Start menu settings" -Level STEP
|
|
||||||
|
|
||||||
# Disable Bing search suggestions in Start menu
|
|
||||||
Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\Explorer" `
|
|
||||||
-Name "DisableSearchBoxSuggestions" -Value 1
|
|
||||||
|
|
||||||
# Win11: empty Start menu pins
|
|
||||||
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Start" `
|
|
||||||
-Name "ConfigureStartPins" `
|
|
||||||
-Value '{"pinnedList":[]}' `
|
|
||||||
-Type "String"
|
|
||||||
|
|
||||||
# Hide "Recently added" apps in Start menu
|
|
||||||
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
|
|
||||||
-Name "Start_TrackProgs" -Value 0
|
|
||||||
|
|
||||||
# Hide recently opened files/docs from Start menu
|
|
||||||
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
|
|
||||||
-Name "Start_TrackDocs" -Value 0
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Copilot - disable
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\WindowsCopilot" `
|
|
||||||
-Name "TurnOffWindowsCopilot" -Value 1
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# GameDVR - disable
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
Set-ProfileReg -SubKey "System\GameConfigStore" `
|
|
||||||
-Name "GameDVR_Enabled" -Value 0
|
|
||||||
|
|
||||||
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\GameDVR" `
|
|
||||||
-Name "AppCaptureEnabled" -Value 0
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Num Lock on startup
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
Set-ProfileReg -SubKey "Control Panel\Keyboard" `
|
|
||||||
-Name "InitialKeyboardIndicators" -Value 2 -Type "String"
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Accent color on title bars
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
Set-ProfileReg -SubKey "Software\Microsoft\Windows\DWM" `
|
|
||||||
-Name "ColorPrevalence" -Value 1
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Taskbar pinned apps layout (Win10/11)
|
|
||||||
# ProfileType: default = empty, admin = Explorer+PS+Edge, user = Explorer+Edge
|
|
||||||
# Note: TaskbarLayoutModification.xml locks the taskbar temporarily.
|
|
||||||
# UnlockStartLayout scheduled task removes the lock 5 min after first boot
|
|
||||||
# so users can then customize pins freely.
|
|
||||||
# Win11 24H2+ may require ProvisionedLayoutModification.xml format instead.
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
Write-Log "Writing taskbar layout (ProfileType=$ProfileType)" -Level INFO
|
|
||||||
|
|
||||||
$taskbarLayoutDir = "C:\Users\Default\AppData\Local\Microsoft\Windows\Shell"
|
|
||||||
if (-not (Test-Path $taskbarLayoutDir)) {
|
|
||||||
New-Item -ItemType Directory -Path $taskbarLayoutDir -Force | Out-Null
|
|
||||||
}
|
|
||||||
|
|
||||||
# Build pin list based on profile type.
|
|
||||||
# Paths resolve relative to the new user at first login.
|
|
||||||
# Missing shortcuts are silently skipped by Windows.
|
|
||||||
$pinList = switch ($ProfileType) {
|
|
||||||
"admin" {
|
|
||||||
@'
|
@'
|
||||||
<taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/>
|
<taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/>
|
||||||
<taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\Windows PowerShell\Windows PowerShell.lnk"/>
|
<taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\Windows PowerShell\Windows PowerShell.lnk"/>
|
||||||
<taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
|
<taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
|
||||||
'@
|
'@
|
||||||
}
|
}
|
||||||
"user" {
|
"user" {
|
||||||
@'
|
@'
|
||||||
<taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/>
|
<taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/>
|
||||||
<taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
|
<taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
|
||||||
'@
|
'@
|
||||||
|
}
|
||||||
|
default { "" } # empty = clean slate
|
||||||
}
|
}
|
||||||
default { "" } # empty = clean slate
|
|
||||||
}
|
|
||||||
|
|
||||||
$taskbarLayoutXml = @"
|
$taskbarLayoutXml = @"
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LayoutModificationTemplate
|
<LayoutModificationTemplate
|
||||||
xmlns="http://schemas.microsoft.com/Start/2014/LayoutModification"
|
xmlns="http://schemas.microsoft.com/Start/2014/LayoutModification"
|
||||||
|
|
@ -317,9 +261,85 @@ $pinList
|
||||||
</CustomTaskbarLayoutCollection>
|
</CustomTaskbarLayoutCollection>
|
||||||
</LayoutModificationTemplate>
|
</LayoutModificationTemplate>
|
||||||
"@
|
"@
|
||||||
$taskbarLayoutXml | Set-Content -Path "$taskbarLayoutDir\LayoutModification.xml" -Encoding UTF8 -Force
|
$taskbarLayoutXml | Set-Content -Path "$taskbarLayoutDir\LayoutModification.xml" -Encoding UTF8 -Force
|
||||||
Write-Log " Taskbar LayoutModification.xml written (profile: $ProfileType)" -Level OK
|
Write-Log " Taskbar LayoutModification.xml written (profile: $ProfileType)" -Level OK
|
||||||
|
|
||||||
|
# NumLock on startup
|
||||||
|
Set-ProfileReg -SubKey "Control Panel\Keyboard" `
|
||||||
|
-Name "InitialKeyboardIndicators" -Value 2 -Type "String"
|
||||||
|
|
||||||
|
# Accent color on title bars
|
||||||
|
Set-ProfileReg -SubKey "Software\Microsoft\Windows\DWM" `
|
||||||
|
-Name "ColorPrevalence" -Value 1
|
||||||
|
} else {
|
||||||
|
Write-Log "taskbarTweaks feature disabled - skipping" -Level INFO
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Start menu tweaks (pins, Bing, Copilot, GameDVR)
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
if (Get-Feature $Config "defaultProfile" "startMenuTweaks") {
|
||||||
|
Write-Log "Applying Start menu tweaks" -Level STEP
|
||||||
|
|
||||||
|
# Disable Bing search suggestions in Start menu
|
||||||
|
Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\Explorer" `
|
||||||
|
-Name "DisableSearchBoxSuggestions" -Value 1
|
||||||
|
|
||||||
|
# Win11: empty Start menu pins
|
||||||
|
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Start" `
|
||||||
|
-Name "ConfigureStartPins" `
|
||||||
|
-Value '{"pinnedList":[]}' `
|
||||||
|
-Type "String"
|
||||||
|
|
||||||
|
# Hide "Recently added" apps in Start menu
|
||||||
|
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
|
||||||
|
-Name "Start_TrackProgs" -Value 0
|
||||||
|
|
||||||
|
# Hide recently opened files/docs from Start menu
|
||||||
|
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
|
||||||
|
-Name "Start_TrackDocs" -Value 0
|
||||||
|
|
||||||
|
# Disable Copilot
|
||||||
|
Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\WindowsCopilot" `
|
||||||
|
-Name "TurnOffWindowsCopilot" -Value 1
|
||||||
|
|
||||||
|
# Disable GameDVR
|
||||||
|
Set-ProfileReg -SubKey "System\GameConfigStore" `
|
||||||
|
-Name "GameDVR_Enabled" -Value 0
|
||||||
|
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\GameDVR" `
|
||||||
|
-Name "AppCaptureEnabled" -Value 0
|
||||||
|
} else {
|
||||||
|
Write-Log "startMenuTweaks feature disabled - skipping" -Level INFO
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Explorer tweaks (file extensions, LaunchTo, ShowRecent, FullPath)
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
if (Get-Feature $Config "defaultProfile" "explorerTweaks") {
|
||||||
|
Write-Log "Applying Explorer tweaks" -Level STEP
|
||||||
|
|
||||||
|
$advPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
|
||||||
|
|
||||||
|
# Show file extensions in Explorer
|
||||||
|
Set-ProfileReg -SubKey $advPath -Name "HideFileExt" -Value 0
|
||||||
|
|
||||||
|
# Open Explorer to This PC instead of Quick Access
|
||||||
|
Set-ProfileReg -SubKey $advPath -Name "LaunchTo" -Value 1
|
||||||
|
|
||||||
|
# Hide Recent files from Quick Access
|
||||||
|
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
|
||||||
|
-Name "ShowRecent" -Value 0
|
||||||
|
|
||||||
|
# Hide Frequent folders from Quick Access
|
||||||
|
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
|
||||||
|
-Name "ShowFrequent" -Value 0
|
||||||
|
|
||||||
|
# Show full path in Explorer title bar
|
||||||
|
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState" `
|
||||||
|
-Name "FullPath" -Value 1
|
||||||
|
} else {
|
||||||
|
Write-Log "explorerTweaks feature disabled - skipping" -Level INFO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,18 @@ function Write-Log {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Get-Feature {
|
||||||
|
param([object]$Cfg, [string]$StepID, [string]$FeatureID, [bool]$Default = $true)
|
||||||
|
try {
|
||||||
|
if ($null -eq $Cfg) { return $Default }
|
||||||
|
$stepFeatures = $Cfg.features.$StepID
|
||||||
|
if ($null -eq $stepFeatures) { return $Default }
|
||||||
|
$val = $stepFeatures.$FeatureID
|
||||||
|
if ($null -eq $val) { return $Default }
|
||||||
|
return [bool]$val
|
||||||
|
} catch { return $Default }
|
||||||
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Detect Dell hardware
|
# Detect Dell hardware
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
@ -95,28 +107,46 @@ if (-not $dcuCli) {
|
||||||
Write-Log " dcu-cli.exe found: $dcuCli" -Level OK
|
Write-Log " dcu-cli.exe found: $dcuCli" -Level OK
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
# Run all available updates (drivers, firmware, BIOS)
|
# Run updates - categories controlled by feature flags
|
||||||
# -reboot=disable -> no mid-deployment reboot; BIOS/firmware staged for next restart
|
# -reboot=disable -> no mid-deployment reboot; BIOS/firmware staged for next restart
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
Write-Log "Running Dell Command | Update (all categories, no auto-reboot)..." -Level STEP
|
$runDrivers = Get-Feature $Config "dellUpdate" "drivers"
|
||||||
Write-Log " This may take several minutes depending on available updates" -Level INFO
|
$runBios = Get-Feature $Config "dellUpdate" "bios"
|
||||||
|
|
||||||
$dcuOutput = & $dcuCli /applyUpdates -silent -reboot=disable 2>&1
|
if (-not $runDrivers -and -not $runBios) {
|
||||||
$exitCode = $LASTEXITCODE
|
Write-Log "Both drivers and bios features disabled - skipping update run" -Level INFO
|
||||||
$dcuOutput | ForEach-Object { Write-Log " [DCU] $_" -Level INFO }
|
} else {
|
||||||
|
# Build update type list from enabled features
|
||||||
|
$updateTypes = @()
|
||||||
|
if ($runDrivers) {
|
||||||
|
$updateTypes += "driver"
|
||||||
|
$updateTypes += "firmware"
|
||||||
|
}
|
||||||
|
if ($runBios) {
|
||||||
|
$updateTypes += "bios"
|
||||||
|
}
|
||||||
|
$updateTypeArg = $updateTypes -join ","
|
||||||
|
|
||||||
Write-Log " DCU exit code: $exitCode" -Level INFO
|
Write-Log "Running Dell Command | Update (updateType=$updateTypeArg, no auto-reboot)..." -Level STEP
|
||||||
|
Write-Log " This may take several minutes depending on available updates" -Level INFO
|
||||||
|
|
||||||
# Dell Command | Update exit codes:
|
$dcuOutput = & $dcuCli /applyUpdates -silent -reboot=disable "-updateType=$updateTypeArg" 2>&1
|
||||||
# 0 = completed, no updates required or updates applied (no reboot needed)
|
$exitCode = $LASTEXITCODE
|
||||||
# 1 = updates applied, reboot required to finalize BIOS/firmware
|
$dcuOutput | ForEach-Object { Write-Log " [DCU] $_" -Level INFO }
|
||||||
# 5 = no applicable updates found for this system
|
|
||||||
# others = error or partial failure
|
Write-Log " DCU exit code: $exitCode" -Level INFO
|
||||||
switch ($exitCode) {
|
|
||||||
0 { Write-Log "Dell Command | Update: complete (no reboot required)" -Level OK }
|
# Dell Command | Update exit codes:
|
||||||
1 { Write-Log "Dell Command | Update: updates staged - BIOS/firmware will finalize on restart" -Level OK }
|
# 0 = completed, no updates required or updates applied (no reboot needed)
|
||||||
5 { Write-Log "Dell Command | Update: no applicable updates for this model" -Level OK }
|
# 1 = updates applied, reboot required to finalize BIOS/firmware
|
||||||
default { Write-Log "Dell Command | Update: exit code $exitCode - review DCU log in C:\ProgramData\Dell\UpdateService\Logs" -Level WARN }
|
# 5 = no applicable updates found for this system
|
||||||
|
# others = error or partial failure
|
||||||
|
switch ($exitCode) {
|
||||||
|
0 { Write-Log "Dell Command | Update: complete (no reboot required)" -Level OK }
|
||||||
|
1 { Write-Log "Dell Command | Update: updates staged - BIOS/firmware will finalize on restart" -Level OK }
|
||||||
|
5 { Write-Log "Dell Command | Update: no applicable updates for this model" -Level OK }
|
||||||
|
default { Write-Log "Dell Command | Update: exit code $exitCode - review DCU log in C:\ProgramData\Dell\UpdateService\Logs" -Level WARN }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Log "Step 11 complete" -Level OK
|
Write-Log "Step 11 complete" -Level OK
|
||||||
|
|
|
||||||
BIN
xetup.exe
Executable file
BIN
xetup.exe
Executable file
Binary file not shown.
Loading…
Reference in a new issue