You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell模块(psm1)中锁屏图片修改脚本失效求助

问题

我有一段修改Windows 11锁屏图片的PowerShell脚本,直接执行时能正常修改锁屏,但封装成psm1模块里的SetLockScreen函数后,执行时能输出提示且无报错,却无法修改锁屏图片,全程都是管理员模式运行。

脚本与调用流程

  1. 直接执行的有效脚本:
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
}
  1. 模块调用流程:
    • 执行命令:
      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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 01:57:03