PowerShell模块(psm1)中锁屏图片修改脚本失效求助
问题
我有一段修改Windows 11锁屏图片的PowerShell脚本,直接执行时能正常修改锁屏,但封装成psm1模块里的SetLockScreen函数后,执行时能输出提示且无报错,却无法修改锁屏图片,全程都是管理员模式运行。
脚本与调用流程
- 直接执行的有效脚本:
Write-Output "Lock Screen Changing..." try { $RegKeyPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\PersonalizationCSP" $LockScreenPath = "LockScreenImagePath" $LockScreenStatus = "LockScreenImageStatus" $LockScreenUrl = "LockScreenImageUrl" $StatusValue = "1" $LockScreenImageValue = "C:\temp\abc.png" if (!(Test-Path $RegKeyPath)) { Write-Host "Creating registry path $($RegKeyPath)." New-Item -Path $RegKeyPath -Force | Out-Null } Write-Output $RegKeyPath Write-Output $LockScreenImageValue New-ItemProperty -Path $RegKeyPath -Name $LockScreenStatus -Value $StatusValue -PropertyType DWORD -Force | Out-Null New-ItemProperty -Path $RegKeyPath -Name $LockScreenPath -Value $LockScreenImageValue -PropertyType STRING -Force | Out-Null New-ItemProperty -Path $RegKeyPath -Name $LockScreenUrl -Value $LockScreenImageValue -PropertyType STRING -Force | Out-Null Write-Output "Lock Changes done...." } catch { Write-Host "An error occurred:" Write-Host $_.ScriptStackTrace }
- 模块调用流程:
- 执行命令:
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0Win11.ps1" -include "%~dp0Win11.psm1" -preset "master-preset.txt" -log "NSX-Install.log" - Win11.ps1代码:
$PSCommandArgs = @() Function AddOrRemoveTweak($tweak) { If ($tweak[0] -eq "!") { # If the name starts with exclamation mark (!), exclude the tweak from selection $script:tweaks = $script:tweaks | Where-Object { $_ -ne $tweak.Substring(1) } } ElseIf ($tweak -ne "") { # Otherwise add the tweak $script:tweaks += $tweak } } # Parse and resolve paths in passed arguments $i = 0 While ($i -lt $args.Length) { If ($args[$i].ToLower() -eq "-include") { # Resolve full path to the included file $include = Resolve-Path $args[++$i] -ErrorAction Stop $PSCommandArgs += "-include `"$include`"" # Import the included file as a module Import-Module -Name $include -ErrorAction Stop } ElseIf ($args[$i].ToLower() -eq "-preset") { # Resolve full path to the preset file $preset = Resolve-Path $args[++$i] -ErrorAction Stop $PSCommandArgs += "-preset `"$preset`"" # Load tweak names from the preset file Get-Content $preset -ErrorAction Stop | ForEach-Object { AddOrRemoveTweak($_.Split("#")[0].Trim()) } } ElseIf ($args[$i].ToLower() -eq "-log") { # Resolve full path to the output file $log = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($args[++$i]) $PSCommandArgs += "-log `"$log`"" # Record session to the output file Start-Transcript $log } Else { $PSCommandArgs += $args[$i] # Load tweak names from command line AddOrRemoveTweak($args[$i]) } $i++ } # Call the desired tweak functions $tweaks | ForEach-Object { Invoke-Expression $_ } - master-preset.txt内容:
SetLockScreen - Win11.psm1中的SetLockScreen函数:
Function SetLockScreen { Write-Output "Lock Screen Changing..." Get-ExecutionPolicy try { $RegKeyPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\PersonalizationCSP" $LockScreenPath = "LockScreenImagePath" $LockScreenStatus = "LockScreenImageStatus" $LockScreenUrl = "LockScreenImageUrl" $StatusValue = "1" $LockScreenImageValue = "C:\temp\abc.png" if (!(Test-Path $RegKeyPath)) { Write-Host "Creating registry path $($RegKeyPath)." New-Item -Path $RegKeyPath -Force | Out-Null } Write-Output $RegKeyPath Write-Output $LockScreenImageValue New-ItemProperty -Path $RegKeyPath -Name $LockScreenStatus -Value $StatusValue -PropertyType DWORD -Force | Out-Null New-ItemProperty -Path $RegKeyPath -Name $LockScreenPath -Value $LockScreenImageValue -PropertyType STRING -Force | Out-Null New-ItemProperty -Path $RegKeyPath -Name $LockScreenUrl -Value $LockScreenImageValue -PropertyType STRING -Force | Out-Null Write-Output "Lock Changes done...." } catch { Write-Host "An error occurred:" Write-Host $_.ScriptStackTrace } }
- 执行命令:
排查分析与解决方案
1. 注册表重定向问题(64位系统)
64位Windows中,32位PowerShell会自动将HKLM:\SOFTWARE路径重定向到HKLM:\SOFTWARE\WOW6432Node,而Windows锁屏读取的是64位注册表路径,导致写入的值无法被系统识别。
解决办法:
- 强制使用64位PowerShell执行脚本,修改启动命令为:
%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0Win11.ps1" -include "%~dp0Win11.psm1" -preset "master-preset.txt" -log "NSX-Install.log" - 或者在函数中显式指定64位注册表视图:
$RegKeyPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\PersonalizationCSP" # 打开64位注册表根键 $regBase = [Microsoft.Win32.RegistryKey]::OpenBaseKey('LocalMachine', 'Registry64') $regKey = $regBase.OpenSubKey($RegKeyPath, $true) # 写入值 $regKey.SetValue("LockScreenImageStatus", 1, [Microsoft.Win32.RegistryValueKind]::DWord) $regKey.SetValue("LockScreenImagePath", "C:\temp\abc.png", [Microsoft.Win32.RegistryValueKind]::String) $regKey.SetValue("LockScreenImageUrl", "C:\temp\abc.png", [Microsoft.Win32.RegistryValueKind]::String) $regKey.Close() $regBase.Close()
2. Invoke-Expression的执行上下文问题
使用Invoke-Expression $_调用函数时,可能存在隐性的作用域或权限解析问题,改用直接调用更可靠。
解决办法:
将Win11.ps1中调用函数的代码替换为:
# Call the desired tweak functions $tweaks | ForEach-Object { if (Get-Command $_ -ErrorAction SilentlyContinue) { & $_ } else { Write-Warning "Tweak function $_ not found" } }
3. 系统未刷新设置
修改PersonalizationCSP注册表后,需要主动通知系统刷新设置,否则锁屏不会立即读取新值。
解决办法:
在SetLockScreen函数末尾添加以下代码,触发系统设置刷新:
# 发送系统设置变更通知 $signature = @" [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam, uint fuFlags, uint uTimeout, out UIntPtr lpdwResult); "@ $sendMessage = Add-Type -MemberDefinition $signature -Name "Win32SendMessage" -Namespace Win32Functions -PassThru $HWND_BROADCAST = [IntPtr]0xffff $WM_SETTINGCHANGE = 0x001A $null = $sendMessage::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE, [UIntPtr]::Zero, "Environment", 2, 5000, [ref][UIntPtr]::Zero)
4. 验证注册表写入结果
在函数中添加验证步骤,确认值是否正确写入目标路径:
# 写入后验证注册表值 Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\PersonalizationCSP" -Name LockScreenStatus, LockScreenImagePath, LockScreenImageUrl | Format-List
将结果输出到日志,检查路径和值是否符合预期。
内容的提问来源于stack exchange,提问作者Sayed Ahmad
相关产品推荐
相关产品推荐

