diff --git a/src/samy.functions.ps1 b/src/samy.functions.ps1 index 58042bf..a0dd5d2 100644 --- a/src/samy.functions.ps1 +++ b/src/samy.functions.ps1 @@ -85,102 +85,130 @@ function Initialize-NuGetProvider { } } -#region re-usable unction - function Set-RegistryValueForCurrentAndAllUsers { - [CmdletBinding()] - param( - [Parameter(Mandatory)] [string] $RelativeKeyPath, # e.g. "Software\...\Explorer\Advanced" - [Parameter(Mandatory)] [string] $Name, - [Parameter(Mandatory)] [ValidateSet('String','ExpandString','DWord','QWord','Binary','MultiString')] [string] $Type, - [Parameter(Mandatory)] $Value - ) +#region Re-usable functions - # Helper: write to a specific HKU root (SID or temp mount) - function _SetValueInHkuRoot { - param([Parameter(Mandatory)] [string] $HkuRoot) # e.g. "Registry::HKEY_USERS\S-1-5-21-..." - $k = Join-Path $HkuRoot $RelativeKeyPath +function Set-RegistryValueInHkuRoot { + [CmdletBinding()] + param( + [Parameter(Mandatory)] [string] $HkuRoot, # e.g. "Registry::HKEY_USERS\S-1-5-21-..." + [Parameter(Mandatory)] [string] $RelativeKeyPath, # e.g. "Software\...\Explorer\Advanced" + [Parameter(Mandatory)] [string] $Name, + [Parameter(Mandatory)] [ValidateSet('String','ExpandString','DWord','QWord','Binary','MultiString')] [string] $Type, + [Parameter(Mandatory)] $Value + ) - if (-not (Test-Path $k)) { New-Item -Path $k -Force | Out-Null } + $k = Join-Path $HkuRoot $RelativeKeyPath + if (-not (Test-Path $k)) { New-Item -Path $k -Force | Out-Null } - if ($Type -in @('String','ExpandString','MultiString','Binary')) { - New-ItemProperty -Path $k -Name $Name -PropertyType $Type -Value $Value -Force | Out-Null - } elseif ($Type -in @('DWord','QWord')) { - New-ItemProperty -Path $k -Name $Name -PropertyType $Type -Value ([int64]$Value) -Force | Out-Null + New-ItemProperty -Path $k -Name $Name -PropertyType $Type -Value $Value -Force -err + Stop | Out-Null +} + +function Set-RegistryValueForCurrentAndAllUsers { + [CmdletBinding()] + param( + [Parameter(Mandatory)] [string] $RelativeKeyPath, + [Parameter(Mandatory)] [string] $Name, + [Parameter(Mandatory)] [ValidateSet('String','ExpandString','DWord','QWord','Binary','MultiString')] [string] $Type, + [Parameter(Mandatory)] $Value + ) + + # 1) Current user (HKCU) when meaningful + try { + $hkcuKey = "HKCU:\$RelativeKeyPath" + if (-not (Test-Path $hkcuKey)) { New-Item -Path $hkcuKey -Force | Out-Null } + New-ItemProperty -Path $hkcuKey -Name $Name -PropertyType $Type -Value $Value -Force | Out-Null + } catch { + # Common during SYSTEM runs; ignore + } + + # 2) Default User (future users) + $defaultDat = "C:\Users\Default\NTUSER.DAT" + $mountName = "SVS_DefaultUser" + $mount = "HKU\$mountName" + $didLoad = $false + + if (Test-Path $defaultDat) { + + if (-not (Test-Path "Registry::HKEY_USERS\$mountName")) { + $loadOut = & reg.exe load $mount $defaultDat 2>&1 + if ($LASTEXITCODE -eq 0) { + $didLoad = $true + Write-LogHybrid "Loaded Default User hive ($defaultDat) to HKEY_USERS\$mountName" Info Tweaks -LogToEvent } else { - # Fallback - New-ItemProperty -Path $k -Name $Name -PropertyType $Type -Value $Value -Force | Out-Null + Write-LogHybrid "Failed to load Default User hive ($defaultDat) to HKEY_USERS\$mountName. reg.exe said: $loadOut" Warning Tweaks -LogToEvent } + } else { + Write-LogHybrid "Default User hive already loaded at HKEY_USERS\$mountName (skipping reg load)" Info Tweaks -LogToEvent } - # 1) Current user (HKCU) - if meaningful in this context try { - $hkcuKey = "HKCU:\$RelativeKeyPath" - if (-not (Test-Path $hkcuKey)) { New-Item -Path $hkcuKey -Force | Out-Null } + if (Test-Path "Registry::HKEY_USERS\$mountName") { + Set-RegistryValueInHkuRoot -HkuRoot "Registry::HKEY_USERS\$mountName" ` + -RelativeKeyPath $RelativeKeyPath -Name $Name -Type $Type -Value $Value - New-ItemProperty -Path $hkcuKey -Name $Name -PropertyType $Type -Value $Value -Force | Out-Null - } catch { - # Common during SYSTEM runs; ignore - } - - # 2) Default User (future users) - $defaultDat = "C:\Users\Default\NTUSER.DAT" - if (Test-Path $defaultDat) { - $mount = "HKU\SVS_DefaultUser" - & reg.exe load $mount $defaultDat 2>$null | Out-Null - - try { - _SetValueInHkuRoot -HkuRoot "Registry::HKEY_USERS\SVS_DefaultUser" - } finally { - & reg.exe unload $mount 2>$null | Out-Null + Write-LogHybrid "Default User updated: [$RelativeKeyPath] $Name = $Value ($Type)" Success Tweaks -LogToEvent } } - - # 3) All existing user profiles - $profileList = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" - Get-ChildItem $profileList -ErrorAction SilentlyContinue | ForEach-Object { - $sid = $_.PSChildName - if ($sid -notmatch '^S-1-5-21-\d+-\d+-\d+-\d+$') { return } - - # If hive is already loaded (user logged in), write directly to HKU:\SID - $loaded = Test-Path "Registry::HKEY_USERS\$sid" - - if ($loaded) { - try { _SetValueInHkuRoot -HkuRoot "Registry::HKEY_USERS\$sid" } catch {} - return + finally { + if ($didLoad) { + $unloadOut = & reg.exe unload $mount 2>&1 + if ($LASTEXITCODE -eq 0) { + Write-LogHybrid "Unloaded Default User hive from HKEY_USERS\$mountName" Info Tweaks -LogToEvent + } else { + Write-LogHybrid "Failed to unload Default User hive from HKEY_USERS\$mountName. reg.exe said: $unloadOut" Warning Tweaks -LogToEvent + } } + } + } else { + Write-LogHybrid "Default User hive not found at $defaultDat (skipping future-user tweak)" Warning Tweaks -LogToEvent + } - # Otherwise load NTUSER.DAT from profile path - $profilePath = (Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue).ProfileImagePath - if (-not $profilePath) { return } - $ntuser = Join-Path $profilePath "NTUSER.DAT" - if (-not (Test-Path $ntuser)) { return } - - $tempMount = "HKU\SVS_$sid" - & reg.exe load $tempMount $ntuser 2>$null | Out-Null + # 3) Existing profiles + $profileList = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" + Get-ChildItem $profileList -ErrorAction SilentlyContinue | ForEach-Object { + $sid = $_.PSChildName + if ($sid -notmatch '^S-1-5-21-\d+-\d+-\d+-\d+$') { return } + # If already loaded, write directly + if (Test-Path "Registry::HKEY_USERS\$sid") { try { - _SetValueInHkuRoot -HkuRoot "Registry::HKEY_USERS\SVS_$sid" - } finally { - & reg.exe unload $tempMount 2>$null | Out-Null - } + Set-RegistryValueInHkuRoot -HkuRoot "Registry::HKEY_USERS\$sid" ` + -RelativeKeyPath $RelativeKeyPath -Name $Name -Type $Type -Value $Value + } catch {} + return + } + + $profilePath = (Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue).ProfileImagePath + if (-not $profilePath) { return } + + $ntuser = Join-Path $profilePath "NTUSER.DAT" + if (-not (Test-Path $ntuser)) { return } + + $tempMount = "HKU\SVS_$sid" + & reg.exe load $tempMount $ntuser 2>$null | Out-Null + try { + Set-RegistryValueInHkuRoot -HkuRoot "Registry::HKEY_USERS\SVS_$sid" ` + -RelativeKeyPath $RelativeKeyPath -Name $Name -Type $Type -Value $Value + } finally { + & reg.exe unload $tempMount 2>$null | Out-Null } } +} function Restart-ExplorerIfInteractive { [CmdletBinding()] param() - # Don't kill Explorer during SYSTEM/unboxing contexts where it may not exist or may be harmful - $isSystem = ($env:USERNAME -eq 'SYSTEM') - - if (-not $isSystem) { + # Avoid during SYSTEM/unboxing contexts + if ($env:USERNAME -ne 'SYSTEM') { Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue Start-Process explorer.exe } } -#rendegion re-usable function +#endregion Re-usable functions #region App handlers