我想要一个可以更改 Windows 7 当前主题的脚本。我找到了存储该脚本的注册表项,但我显然需要采取进一步的措施才能让 Windows 加载该主题。我该怎么办?
这是我正在尝试使用的脚本,但它不起作用(注册表已更新,但主题未更改):
######################################
# Change theme by updating registry. #
######################################
# Define argument which defines which theme to apply.
param ( [string] $theme = $(Read-Host -prompt "Theme") )
# Define the themes we know about.
$knownThemes = @{ "myTheme" = "mytheme.theme"; "alien" = "oem.theme" }
# Identify paths to user themes.
$userThemes = " C:\Users\yoda\AppData\Local\Microsoft\Windows\"
# Get name of theme file, based on theme provided
$themeFile = $knownThemes["$theme"]
# Build path to theme and set registry.
$newThemePath = "$userThemes$themeFile"
$regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\"
Set-ItemProperty -path $regPath -name CurrentTheme -value $newThemePath
# Update system with this info...this isn't working!
rundll32.exe user32.dll, UpdatePerUserSystemParameters
答案1
看看 Stack Overflow 上的问题如何以编程方式更改当前 Windows 主题?处理同样的问题。似乎大多数评论者都认为你根本不应该这样做(你可以选择忽略他们)。其他建议可以轻松转换为 PowerShell 脚本 - 只需调用适当的 API 函数即可。
答案2
我已经用此代码解决了该问题(在 Windows 7 64 位中测试)
# definition de la fonction native Windows permettant le test d'activation d'Aero
$def = @"
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern bool DwmIsCompositionEnabled();
"@
# chargement de la fonction native dans un namespace personnel
Add-Type -Namespace MaifCode -Name Aero -MemberDefinition $def
# fonction qui check si Aero est desactive ou non
function Check-Is-Aero{
[CmdletBinding()]
param()
Write-Verbose "[$([DateTime]::Now)] ==> Test de la presence du mode Aero pour la session utilisateur $env:USERNAME"
if([MaifCode.Aero]::DwmIsCompositionEnabled()){
Write-Verbose "[$([DateTime]::Now)] ==> Aero actif pour la session utilisateur $env:USERNAME"
return $true
}else{
Write-Verbose "[$([DateTime]::Now)] ==> Aero inactif pour la session utilisateur $env:USERNAME"
return $false
}
}
# fonction qui test si Aero est actif et le desactive dans ce cas
function Disable-Aero{
[CmdletBinding()]
param()
# test si aero actif
If(Check-Is-Aero) {
Write-Verbose "[$([DateTime]::Now)] ==> Tentative de desactivation du mode Aero pour la session utilisateur $env:USERNAME"
# desactivation du mode aero en passant sur le them par defaut
try{
Start-Process -Wait -FilePath "rundll32.exe" -ArgumentList "$env:SystemRoot\system32\shell32.dll,Control_RunDLL $env:SystemRoot\system32\desk.cpl desk,@Themes /Action:OpenTheme /file:""C:\Windows\Resources\Ease of Access Themes\basic.theme"""
}
catch [exception]
{
# si erreur alors on sort et on affiche le message d'erreur
Write-Error "Erreur dans l'execution de la desactivation du mode Aero : $error"
exit -1
}
Write-Verbose "[$([DateTime]::Now)] ==> Desactivation du mode Aero pour la session utilisateur $env:USERNAME terminee"
}else{
Write-Verbose "[$([DateTime]::Now)] ==> sortie du script sans action"
}
}
# execution du code de desactivation
Disable-Aero -Verbose
# on sort
exit 0
答案3
要直接回答 OP 的问题,您可以使用以下内容。我在结尾处添加了一些关于关闭机制的评论,如果您搜索此问题,您会发现它们的行为并不像脚本新手所认为的那样。
我还稍微改进了最先进的技术,因为解决方案是纯 powershell(尽管调用了 com 对象),并且关闭窗口之前的延迟会根据桌面的状态自行配置。
#the path to the theme we want to apply
$ThemePath = "C:\Windows\Resources\Ease of Access Themes\classic.theme"
#the name of the desktop customization window (Written for windows 7, change for your flavor)
$CustomizationWindowName = "Personalization"
$myWScriptShell = New-Object -ComObject Wscript.Shell #wscriptshell com object to interact with the system
$myShellApplication = New-Object -ComObject Shell.Application #shellapplication com object to access window names
#execute the theme change
$myWScriptShell.Run("rundll32.exe %SystemRoot%\system32\shell32.dll,Control_RunDLL %SystemRoot%\system32\desk.cpl desk,@Themes /Action:OpenTheme /file:""$ThemePath""")
#this while block continuously searches for the
#customization window which will be left behind based on it's name
:search while($true)
{
#enumerate the open windows
foreach($window in $myShellApplication.Windows())
{
#check each window to see if it's the one of interest
#when we find the window, break from the outer
#"search" loop to execute the remainder of the script
if($window.LocationName -eq $CustomizationWindowName){break search}
}
}
#activate the customization window (in case it's in the background,
#and to be sure we send the keys to the right window)
$myWScriptShell.AppActivate($CustomizationWindowName)
#This is alt+F+C, intended for file->Close.
#Presumably pulled from another (perhaps office?) script
#In the common literature, this line actually did the close, #the last line was essentially doing nothing
#$myWScriptShell.SendKeys("%FC") #commented as extraneous
#In the common literature, this was just {F4}, which doesn't work without the % for "alt".
#The prior line actually did the work.
$myWScriptShell.SendKeys("%{F4}")