Windows屏幕亮度调整脚本无效:注册表已改但亮度未变求助
问题描述
环境:Windows 10 21H2 19044.1949、PowerShell 7.2.6
我编写了一个调整Windows屏幕亮度的脚本,修改注册表后值已按预期设置,但屏幕亮度并未实际改变。打开Windows设置->系统->屏幕,亮度值仍未变化;但手动修改该设置时,注册表值会相应更新。请问遗漏了什么?
脚本代码如下:
# 显示/设置亮度 param ( [parameter(Mandatory=$false)] [Int32] [ValidateRange(0,100)] $number = -1 ); function Take-Permissions { # 来源:stackoverflow相关实现 # 适用于PowerShell v4.0,需要管理员权限 param($rootKey, $key, [System.Security.Principal.SecurityIdentifier]$sid = 'S-1-5-32-545', $recurse = $true) switch -regex ($rootKey) { 'HKCU|HKEY_CURRENT_USER' { $rootKey = 'CurrentUser' } 'HKLM|HKEY_LOCAL_MACHINE' { $rootKey = 'LocalMachine' } 'HKCR|HKEY_CLASSES_ROOT' { $rootKey = 'ClassesRoot' } 'HKCC|HKEY_CURRENT_CONFIG' { $rootKey = 'CurrentConfig' } 'HKU|HKEY_USERS' { $rootKey = 'Users' } } ### 步骤1 - 提升当前进程权限 # 获取SeTakeOwnership、SeBackup和SeRestore权限,脚本需要管理员权限 $import = '[DllImport("ntdll.dll")] public static extern int RtlAdjustPrivilege(ulong a, bool b, bool c, ref bool d);' $ntdll = Add-Type -Member $import -Name NtDll -PassThru $privileges = @{ SeTakeOwnership = 9; SeBackup = 17; SeRestore = 18 } foreach ($i in $privileges.Values) { $null = $ntdll::RtlAdjustPrivilege($i, 1, 0, [ref]0) } function Take-KeyPermissions { param($rootKey, $key, $sid, $recurse, $recurseLevel = 0) ### 步骤2 - 获取键的所有权 - 仅对当前键生效 $regKey = [Microsoft.Win32.Registry]::$rootKey.OpenSubKey($key, 'ReadWriteSubTree', 'TakeOwnership') $acl = New-Object System.Security.AccessControl.RegistrySecurity $acl.SetOwner($sid) $regKey.SetAccessControl($acl) ### 步骤3 - 启用当前键从父键继承权限(不包括所有权) $acl.SetAccessRuleProtection($false, $false) $regKey.SetAccessControl($acl) ### 步骤4 - 仅对顶级键,修改当前键权限并传播到子键 # 要让子键也应用权限,需要为每个子键重复步骤2-3(步骤5) if ($recurseLevel -eq 0) { $regKey = $regKey.OpenSubKey('', 'ReadWriteSubTree', 'ChangePermissions') $rule = New-Object System.Security.AccessControl.RegistryAccessRule($sid, 'FullControl', 'ContainerInherit', 'None', 'Allow') $acl.ResetAccessRule($rule) $regKey.SetAccessControl($acl) } ### 步骤5 - 递归对子键重复步骤2-5 if ($recurse) { foreach($subKey in $regKey.OpenSubKey('').GetSubKeyNames()) { Take-KeyPermissions $rootKey ($key+'\'+$subKey) $sid $recurse ($recurseLevel+1) } } } Take-KeyPermissions $rootKey $key $sid $recurse } ### 主逻辑 ### # 获取当前活动电源计划的GUID: $guid = (Get-CimInstance -classname Win32_PowerPlan -Namespace "root\cimv2\power" -Filter "IsActive='True'").InstanceID.tostring() $regex = [regex]"{(.*?)}" $planGuid = $regex.Match($guid).groups[1].value # 设置注册表路径值: $regPath0="HKLM" $regPath1=$regPath0+":" $regPath2= "SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes\"+$planGuid+"\7516b95f-f776-4464-8c53-06167f40cc99\aded5e82-b909-4619-9949-f5d71dac0bcb" $regPath=$regPath1+$regPath2 $regProp1="ACSettingIndex"; $regProp2="DCSettingIndex"; if ($number -eq -1) { Write-Host "当前亮度:" (Get-ItemProperty $regPath $regProp2).$regProp2 } else { # 初始状态下管理员没有修改该键的权限: $AdminGroupSid="S-1-5-32-544" Take-Permissions $regPath0 $regPath2 $AdminGroupSid $false Set-ItemProperty $regPath $regProp1 $number Set-ItemProperty $regPath $regProp2 $number # 验证新设置: Write-Host "亮度已设置为:" (Get-ItemProperty $regPath $regProp2).$regProp2 }
解决方法
你修改的注册表项是电源计划的持久化亮度设置,但Windows不会自动刷新这些设置到当前运行的系统中。要让亮度立即生效,需要通知系统电源设置已更改,或者直接调用系统API来调整实时亮度。
原因分析
- 手动修改设置时,Windows设置应用会同时更新注册表、调用系统底层接口改变屏幕亮度,还会通知电源服务刷新配置。
- 仅修改注册表只会改变电源计划的保存配置,不会触发系统实时调整,也不会同步设置界面的显示值。
修复方案
在脚本修改注册表后,添加以下操作之一:
方案1:通知电源服务刷新设置
添加以下代码到Set-ItemProperty之后:
# 重新激活当前电源计划,强制加载新配置 powercfg -setactive $planGuid
方案2:直接调用API修改实时亮度(推荐)
使用Windows的WMI接口直接调整屏幕亮度,这种方式无需修改注册表,设置后立即生效且同步设置界面。添加以下函数到脚本中,并在设置数值时调用:
function Set-ScreenBrightness { param([int]$Brightness) # 确保亮度值在0-100范围内 $Brightness = [Math]::Clamp($Brightness, 0, 100) # 获取显示器亮度控制实例 $monitorMethods = Get-CimInstance -Namespace root/wmi -ClassName WmiMonitorBrightnessMethods if ($monitorMethods) { # 1表示立即应用亮度设置 $monitorMethods.WmiSetBrightness(1, $Brightness) } }
然后在修改注册表后调用该函数:
Set-ScreenBrightness -Brightness $number
完整逻辑说明
- 保留你原有的注册表修改代码,确保电源计划的持久化配置更新
- 调用上述任一方案触发实时亮度调整
- 验证设置是否生效
这样修改后,屏幕亮度会立即变化,设置界面的数值也会同步更新。
内容的提问来源于stack exchange,提问作者jamacoe
相关产品推荐
相关产品推荐

