diff --git a/windows/branding/lib/BrandingLayers.ps1 b/windows/branding/lib/BrandingLayers.ps1 new file mode 100644 index 0000000..d1b02fa --- /dev/null +++ b/windows/branding/lib/BrandingLayers.ps1 @@ -0,0 +1,56 @@ +Set-StrictMode -Version Latest +. "$PSScriptRoot\RegistryHelpers.ps1" + +function Set-OemInformation { + param([Parameter(Mandatory)][string]$SoftwareRoot,[Parameter(Mandatory)]$Manifest,[Parameter(Mandatory)][string]$LogoPath) + $sub = 'Microsoft\Windows\CurrentVersion\OEMInformation' + Set-SmRegValue -Root $SoftwareRoot -SubKey $sub -Name 'Manufacturer' -Type String -Value $Manifest.oem.manufacturer + Set-SmRegValue -Root $SoftwareRoot -SubKey $sub -Name 'Model' -Type String -Value $Manifest.oem.model + Set-SmRegValue -Root $SoftwareRoot -SubKey $sub -Name 'SupportURL' -Type String -Value $Manifest.oem.supportUrl + Set-SmRegValue -Root $SoftwareRoot -SubKey $sub -Name 'SupportHours' -Type String -Value $Manifest.oem.supportHours + Set-SmRegValue -Root $SoftwareRoot -SubKey $sub -Name 'Logo' -Type String -Value $LogoPath +} + +function Set-LockScreen { + param([Parameter(Mandatory)][string]$SoftwareRoot,[Parameter(Mandatory)][string]$ImagePath,[bool]$Lock=$true) + # Per-device modern lock-screen image (reliable on Enterprise/IoT). + $csp = 'Microsoft\Windows\CurrentVersion\PersonalizationCSP' + Set-SmRegValue -Root $SoftwareRoot -SubKey $csp -Name 'LockScreenImagePath' -Type String -Value $ImagePath + Set-SmRegValue -Root $SoftwareRoot -SubKey $csp -Name 'LockScreenImageUrl' -Type String -Value $ImagePath + Set-SmRegValue -Root $SoftwareRoot -SubKey $csp -Name 'LockScreenImageStatus' -Type DWord -Value 1 + if ($Lock) { + $pol = 'Policies\Microsoft\Windows\Personalization' + Set-SmRegValue -Root $SoftwareRoot -SubKey $pol -Name 'LockScreenImage' -Type String -Value $ImagePath + Set-SmRegValue -Root $SoftwareRoot -SubKey $pol -Name 'NoChangingLockScreen' -Type DWord -Value 1 + } +} + +function Set-DesktopBranding { + param([Parameter(Mandatory)][string]$DefaultUserRoot,[Parameter(Mandatory)]$Manifest,[Parameter(Mandatory)][string]$WallpaperPath) + Set-SmRegValue -Root $DefaultUserRoot -SubKey 'Control Panel\Desktop' -Name 'WallPaper' -Type String -Value $WallpaperPath + Set-SmRegValue -Root $DefaultUserRoot -SubKey 'Control Panel\Desktop' -Name 'WallpaperStyle' -Type String -Value '10' # fill + if ($Manifest.desktop.darkMode) { + $p = 'Software\Microsoft\Windows\CurrentVersion\Themes\Personalize' + Set-SmRegValue -Root $DefaultUserRoot -SubKey $p -Name 'AppsUseLightTheme' -Type DWord -Value 0 + Set-SmRegValue -Root $DefaultUserRoot -SubKey $p -Name 'SystemUsesLightTheme' -Type DWord -Value 0 + } + # Accent (cyan). BGR DWORD from manifest hex (stored little-endian as 0x00BBGGRR). + $bgr = [Convert]::ToInt32($Manifest.desktop.accentBgr,16) + Set-SmRegValue -Root $DefaultUserRoot -SubKey 'Software\Microsoft\Windows\DWM' -Name 'AccentColor' -Type DWord -Value $bgr + Set-SmRegValue -Root $DefaultUserRoot -SubKey 'Software\Microsoft\Windows\DWM' -Name 'ColorizationColor' -Type DWord -Value $bgr + if (-not $Manifest.desktop.lockWallpaper) { return } + Set-SmRegValue -Root $DefaultUserRoot -SubKey 'Software\Microsoft\Windows\CurrentVersion\Policies\ActiveDesktop' -Name 'NoChangingWallPaper' -Type DWord -Value 1 +} + +function Set-BitLockerPreboot { + param([Parameter(Mandatory)][string]$SoftwareRoot,[Parameter(Mandatory)]$Manifest) + # GPO "Configure pre-boot recovery message and URL" (ADMX VolumeEncryption). + # NOTE: only the BitLocker RECOVERY screen is customisable; the normal PIN-entry + # screen text is fixed Windows UI. Exact value names are asserted by the read-back + # test; if a name is wrong the offline-apply verify (Task A4) catches it. + $fve = 'Policies\Microsoft\FVE' + Set-SmRegValue -Root $SoftwareRoot -SubKey $fve -Name 'UseCustomRecoveryMessage' -Type DWord -Value 1 + Set-SmRegValue -Root $SoftwareRoot -SubKey $fve -Name 'RecoveryMessage' -Type String -Value $Manifest.bitlocker.recoveryMessage + Set-SmRegValue -Root $SoftwareRoot -SubKey $fve -Name 'UseCustomRecoveryUrl' -Type DWord -Value 1 + Set-SmRegValue -Root $SoftwareRoot -SubKey $fve -Name 'RecoveryUrl' -Type String -Value $Manifest.bitlocker.recoveryUrl +} diff --git a/windows/tests/Branding.Tests.ps1 b/windows/tests/Branding.Tests.ps1 index f7cb680..db019b6 100644 --- a/windows/tests/Branding.Tests.ps1 +++ b/windows/tests/Branding.Tests.ps1 @@ -20,3 +20,43 @@ Describe 'Set-SmRegValue' { (Get-ItemProperty "$script:root\A").Flag | Should -Be 1 } } + +Describe 'Branding layer writers' { + BeforeAll { + . "$PSScriptRoot\..\branding\lib\BrandingLayers.ps1" + $script:sw = 'HKCU:\Software\SilverMetalTest\SW' + $script:du = 'HKCU:\Software\SilverMetalTest\DU' + $script:m = Get-Content "$PSScriptRoot\..\branding\branding.manifest.json" -Raw | ConvertFrom-Json + } + AfterAll { + Remove-Item 'HKCU:\Software\SilverMetalTest' -Recurse -Force -ErrorAction SilentlyContinue + } + + It 'writes OEM About info' { + Set-OemInformation -SoftwareRoot $script:sw -Manifest $script:m -LogoPath 'C:\Windows\System32\oemlogo.bmp' + $k = Get-ItemProperty "$script:sw\Microsoft\Windows\CurrentVersion\OEMInformation" + $k.Manufacturer | Should -Be 'SilverLABS' + $k.Model | Should -Be 'SilverMetal Windows' + $k.SupportURL | Should -Be 'https://silverlabs.uk' + $k.Logo | Should -Be 'C:\Windows\System32\oemlogo.bmp' + } + + It 'writes a locked lock-screen image' { + Set-LockScreen -SoftwareRoot $script:sw -ImagePath 'C:\Windows\Web\Screen\SilverMetal\lockscreen.jpg' -Lock $true + (Get-ItemProperty "$script:sw\Microsoft\Windows\CurrentVersion\PersonalizationCSP").LockScreenImageStatus | Should -Be 1 + (Get-ItemProperty "$script:sw\Policies\Microsoft\Windows\Personalization").NoChangingLockScreen | Should -Be 1 + } + + It 'writes desktop wallpaper + dark mode into the default-user root' { + Set-DesktopBranding -DefaultUserRoot $script:du -Manifest $script:m -WallpaperPath 'C:\Windows\Web\Wallpaper\SilverMetal\wallpaper.jpg' + (Get-ItemProperty "$script:du\Control Panel\Desktop").WallPaper | Should -Be 'C:\Windows\Web\Wallpaper\SilverMetal\wallpaper.jpg' + (Get-ItemProperty "$script:du\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize").AppsUseLightTheme | Should -Be 0 + } + + It 'writes the BitLocker pre-boot recovery message policy' { + Set-BitLockerPreboot -SoftwareRoot $script:sw -Manifest $script:m + $k = Get-ItemProperty "$script:sw\Policies\Microsoft\FVE" + $k.UseCustomRecoveryMessage | Should -Be 1 + $k.RecoveryMessage | Should -Be 'SilverMetal Windows. Locked out? silverlabs.uk' + } +}