325 lines
14 KiB
PowerShell
325 lines
14 KiB
PowerShell
|
|
param(
|
||
|
|
[object]$Config,
|
||
|
|
[string]$LogFile
|
||
|
|
)
|
||
|
|
|
||
|
|
$ErrorActionPreference = "Continue"
|
||
|
|
|
||
|
|
function Write-Log {
|
||
|
|
param([string]$Message, [string]$Level = "INFO")
|
||
|
|
$line = "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message"
|
||
|
|
Add-Content -Path $LogFile -Value $line -Encoding UTF8
|
||
|
|
}
|
||
|
|
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
# Helper - apply a registry setting to both Default hive and current HKCU
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
function Grant-HiveWriteAccess {
|
||
|
|
param([string]$HivePath) # full path e.g. "Registry::HKU\DefaultProfile\Software\..."
|
||
|
|
# Grants Administrators FullControl on a loaded hive key with restricted ACL.
|
||
|
|
try {
|
||
|
|
$acl = Get-Acl -Path $HivePath -ErrorAction Stop
|
||
|
|
$rule = New-Object System.Security.AccessControl.RegistryAccessRule(
|
||
|
|
"BUILTIN\Administrators",
|
||
|
|
[System.Security.AccessControl.RegistryRights]::FullControl,
|
||
|
|
[System.Security.AccessControl.InheritanceFlags]"ContainerInherit,ObjectInherit",
|
||
|
|
[System.Security.AccessControl.PropagationFlags]::None,
|
||
|
|
[System.Security.AccessControl.AccessControlType]::Allow
|
||
|
|
)
|
||
|
|
$acl.SetAccessRule($rule)
|
||
|
|
Set-Acl -Path $HivePath -AclObject $acl -ErrorAction Stop
|
||
|
|
}
|
||
|
|
catch {
|
||
|
|
Write-Log " Grant-HiveWriteAccess failed for $HivePath - $_" -Level WARN
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function Set-ProfileReg {
|
||
|
|
param(
|
||
|
|
[string]$SubKey, # relative to HKCU (e.g. "Software\Microsoft\...")
|
||
|
|
[string]$Name,
|
||
|
|
$Value,
|
||
|
|
[string]$Type = "DWord"
|
||
|
|
)
|
||
|
|
|
||
|
|
# Apply to loaded Default hive
|
||
|
|
$defPath = "Registry::HKU\DefaultProfile\$SubKey"
|
||
|
|
try {
|
||
|
|
if (-not (Test-Path $defPath)) {
|
||
|
|
New-Item -Path $defPath -Force -ErrorAction Stop | Out-Null
|
||
|
|
}
|
||
|
|
Set-ItemProperty -Path $defPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
|
||
|
|
}
|
||
|
|
catch {
|
||
|
|
# Retry after granting write access to parent key
|
||
|
|
try {
|
||
|
|
$parentPath = $defPath -replace '\\[^\\]+$', ''
|
||
|
|
if (Test-Path $parentPath) { Grant-HiveWriteAccess -HivePath $parentPath }
|
||
|
|
if (-not (Test-Path $defPath)) {
|
||
|
|
New-Item -Path $defPath -Force -ErrorAction Stop | Out-Null
|
||
|
|
}
|
||
|
|
Set-ItemProperty -Path $defPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
|
||
|
|
}
|
||
|
|
catch {
|
||
|
|
Write-Log " DEFAULT HIVE failed $SubKey\$Name - $_" -Level ERROR
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Apply to current user as well
|
||
|
|
$hkcuPath = "HKCU:\$SubKey"
|
||
|
|
try {
|
||
|
|
if (-not (Test-Path $hkcuPath)) {
|
||
|
|
New-Item -Path $hkcuPath -Force -ErrorAction Stop | Out-Null
|
||
|
|
}
|
||
|
|
Set-ItemProperty -Path $hkcuPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
|
||
|
|
Write-Log " SET $SubKey\$Name = $Value" -Level OK
|
||
|
|
}
|
||
|
|
catch {
|
||
|
|
Write-Log " HKCU failed $SubKey\$Name - $_" -Level ERROR
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function Remove-ProfileReg {
|
||
|
|
param([string]$SubKey, [string]$Name)
|
||
|
|
|
||
|
|
$defPath = "Registry::HKU\DefaultProfile\$SubKey"
|
||
|
|
try {
|
||
|
|
if (Test-Path $defPath) {
|
||
|
|
Remove-ItemProperty -Path $defPath -Name $Name -Force -ErrorAction SilentlyContinue
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch { }
|
||
|
|
|
||
|
|
$hkcuPath = "HKCU:\$SubKey"
|
||
|
|
try {
|
||
|
|
if (Test-Path $hkcuPath) {
|
||
|
|
Remove-ItemProperty -Path $hkcuPath -Name $Name -Force -ErrorAction SilentlyContinue
|
||
|
|
Write-Log " REMOVED $SubKey\$Name" -Level OK
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch {
|
||
|
|
Write-Log " FAILED removing $SubKey\$Name - $_" -Level ERROR
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
# Load Default profile hive
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
$hivePath = "C:\Users\Default\NTUSER.DAT"
|
||
|
|
$hiveKey = "DefaultProfile"
|
||
|
|
|
||
|
|
Write-Log "Loading Default hive: $hivePath" -Level INFO
|
||
|
|
|
||
|
|
# Unload first in case previous run left it mounted
|
||
|
|
& reg unload "HKU\$hiveKey" 2>&1 | Out-Null
|
||
|
|
|
||
|
|
$loadResult = & reg load "HKU\$hiveKey" $hivePath 2>&1
|
||
|
|
if ($LASTEXITCODE -ne 0) {
|
||
|
|
Write-Log "Failed to load Default hive: $loadResult" -Level ERROR
|
||
|
|
exit 1
|
||
|
|
}
|
||
|
|
Write-Log "Default hive loaded" -Level OK
|
||
|
|
|
||
|
|
try {
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
# Taskbar settings (Win10 + Win11)
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
Write-Log "Applying taskbar settings" -Level STEP
|
||
|
|
|
||
|
|
$tbPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
|
||
|
|
|
||
|
|
# Win11: align taskbar to left (0 = left, 1 = center)
|
||
|
|
Set-ProfileReg -SubKey $tbPath -Name "TaskbarAl" -Value 0
|
||
|
|
|
||
|
|
# Hide Search box / button - Win10/11 (0 = hidden, 1 = icon, 2 = full box)
|
||
|
|
# Note: Win11 uses Search subkey, Win10 uses Explorer\Advanced - set both
|
||
|
|
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Search" `
|
||
|
|
-Name "SearchboxTaskbarMode" -Value 0
|
||
|
|
Set-ProfileReg -SubKey $tbPath -Name "SearchboxTaskbarMode" -Value 0
|
||
|
|
|
||
|
|
# Hide Task View button
|
||
|
|
Set-ProfileReg -SubKey $tbPath -Name "ShowTaskViewButton" -Value 0
|
||
|
|
|
||
|
|
# Hide Widgets button
|
||
|
|
Set-ProfileReg -SubKey $tbPath -Name "TaskbarDa" -Value 0
|
||
|
|
|
||
|
|
# Hide Chat / Teams button
|
||
|
|
Set-ProfileReg -SubKey $tbPath -Name "TaskbarMn" -Value 0
|
||
|
|
|
||
|
|
# Hide Copilot button
|
||
|
|
Set-ProfileReg -SubKey $tbPath -Name "ShowCopilotButton" -Value 0
|
||
|
|
|
||
|
|
# Show file extensions in Explorer
|
||
|
|
Set-ProfileReg -SubKey $tbPath -Name "HideFileExt" -Value 0
|
||
|
|
|
||
|
|
# Open Explorer to This PC instead of Quick Access
|
||
|
|
Set-ProfileReg -SubKey $tbPath -Name "LaunchTo" -Value 1
|
||
|
|
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
# System tray - show all icons
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
# EnableAutoTray = 0 works on Win10; Win11 ignores it but set anyway
|
||
|
|
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
|
||
|
|
# Windows rebuilds the streams with all icons visible when no cache exists
|
||
|
|
$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
|
||
|
|
}
|
||
|
|
|
||
|
|
# Also clear in Default hive so new users start with clean state
|
||
|
|
$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
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
# 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
|
||
|
|
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
# OneDrive - remove RunOnce key from Default profile
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
Write-Log "Removing OneDrive from Default profile RunOnce" -Level INFO
|
||
|
|
Remove-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Run" `
|
||
|
|
-Name "OneDriveSetup"
|
||
|
|
|
||
|
|
Remove-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\RunOnce" `
|
||
|
|
-Name "Delete Cached Standalone Update Binary"
|
||
|
|
|
||
|
|
# Remove OneDrive from Explorer namespace (left panel)
|
||
|
|
$oneDriveClsid = "{018D5C66-4533-4307-9B53-224DE2ED1FE6}"
|
||
|
|
$nsPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Desktop\NameSpace\$oneDriveClsid"
|
||
|
|
$defNsPath = "Registry::HKU\DefaultProfile\$nsPath"
|
||
|
|
if (Test-Path $defNsPath) {
|
||
|
|
Remove-Item -Path $defNsPath -Recurse -Force -ErrorAction SilentlyContinue
|
||
|
|
Write-Log " Removed OneDrive from Explorer namespace (Default)" -Level OK
|
||
|
|
}
|
||
|
|
$hkcuNsPath = "HKCU:\$nsPath"
|
||
|
|
if (Test-Path $hkcuNsPath) {
|
||
|
|
Remove-Item -Path $hkcuNsPath -Recurse -Force -ErrorAction SilentlyContinue
|
||
|
|
Write-Log " Removed OneDrive from Explorer namespace (HKCU)" -Level OK
|
||
|
|
}
|
||
|
|
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
# Empty taskbar pinned apps (Win10/11)
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
Write-Log "Clearing taskbar pinned apps layout" -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
|
||
|
|
}
|
||
|
|
|
||
|
|
$taskbarLayoutXml = @"
|
||
|
|
<?xml version="1.0" encoding="utf-8"?>
|
||
|
|
<LayoutModificationTemplate
|
||
|
|
xmlns="http://schemas.microsoft.com/Start/2014/LayoutModification"
|
||
|
|
xmlns:defaultlayout="http://schemas.microsoft.com/Start/2014/FullDefaultLayout"
|
||
|
|
xmlns:start="http://schemas.microsoft.com/Start/2014/StartLayout"
|
||
|
|
xmlns:taskbar="http://schemas.microsoft.com/Start/2014/TaskbarLayout"
|
||
|
|
Version="1">
|
||
|
|
<CustomTaskbarLayoutCollection PinListPlacement="Replace">
|
||
|
|
<defaultlayout:TaskbarLayout>
|
||
|
|
<taskbar:TaskbarPinList>
|
||
|
|
</taskbar:TaskbarPinList>
|
||
|
|
</defaultlayout:TaskbarLayout>
|
||
|
|
</CustomTaskbarLayoutCollection>
|
||
|
|
</LayoutModificationTemplate>
|
||
|
|
"@
|
||
|
|
$taskbarLayoutXml | Set-Content -Path "$taskbarLayoutDir\LayoutModification.xml" -Encoding UTF8 -Force
|
||
|
|
Write-Log " Taskbar LayoutModification.xml written" -Level OK
|
||
|
|
|
||
|
|
}
|
||
|
|
finally {
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
# Unload Default hive - always, even on error
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
Write-Log "Unloading Default hive" -Level INFO
|
||
|
|
[GC]::Collect()
|
||
|
|
[GC]::WaitForPendingFinalizers()
|
||
|
|
Start-Sleep -Milliseconds 500
|
||
|
|
|
||
|
|
$unloadResult = & reg unload "HKU\$hiveKey" 2>&1
|
||
|
|
if ($LASTEXITCODE -eq 0) {
|
||
|
|
Write-Log "Default hive unloaded" -Level OK
|
||
|
|
} else {
|
||
|
|
Write-Log "Failed to unload Default hive: $unloadResult" -Level ERROR
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
# Restart Explorer to apply taskbar/tray changes to current session
|
||
|
|
# -----------------------------------------------------------------------
|
||
|
|
Write-Log "Restarting Explorer to apply taskbar changes" -Level INFO
|
||
|
|
try {
|
||
|
|
Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue
|
||
|
|
Start-Sleep -Seconds 2
|
||
|
|
Start-Process explorer
|
||
|
|
Write-Log "Explorer restarted" -Level OK
|
||
|
|
}
|
||
|
|
catch {
|
||
|
|
Write-Log "Explorer restart failed (non-fatal): $_" -Level WARN
|
||
|
|
}
|
||
|
|
|
||
|
|
Write-Log "Step 4 complete" -Level OK
|