Hey Scripting Guy! I have been trying to set the screen saver time out value on my workstations by using WMI. It is not working. Can you help me get WMI working?
— HR
Hello HR,
Microsoft Scripting Guy Ed Wilson here. My teapot is empty. I was getting ready to head downstairs to fix me a nice pot of Constant Comment tea, but Outlook dinged at me signaling that your e-mail had arrived in the scripter@microsoft.com alias. I love it when an e-mail is short, sweet, and to the point. Because I get several hundred e-mail messages a week. Long, convoluted messages tend to get shuffled to the bottom of the pile. Eventually, they get answered, but short ones are easier to deal with. The short answer is that WMI is probably already working just fine. The problem is that it does not allow you to modify the screen saver timeout value.
Note: Portions of today’s Hey, Scripting Guy! post are excerpted from the Microsoft Press book, Windows PowerShell 2.0 Best Practices by Ed Wilson, which is now available for pre-order.
For all the good things to be had with WMI, there are still a number of very frustrating limitations. For example, WMI is good at retrieving information, but it is not always very good at changing that information. Here is an example that illustrates the point. The Win32_Desktop WMI class provides information about desktop settings as seen here.
PS C:> Get-WmiObject Win32_Desktop
__GENUS : 2
__CLASS : Win32_Desktop
__SUPERCLASS : CIM_Setting
__DYNASTY : CIM_Setting
__RELPATH : Win32_Desktop.Name=”NT AUTHORITY\SYSTEM”
__PROPERTY_COUNT : 21
__DERIVATION : {CIM_Setting}
__SERVER : MRED1
__NAMESPACE : rootcimv2
__PATH : \MRED1rootcimv2:Win32_Desktop.Name=”NT AUTHORITY\SY
STEM”
BorderWidth : 1
Caption :
CoolSwitch :
CursorBlinkRate : 500
Description :
DragFullWindows : True
GridGranularity :
IconSpacing :
IconTitleFaceName : Segoe UI
IconTitleSize : 9
IconTitleWrap : True
Name : NT AUTHORITYSYSTEM
Pattern : (None)
ScreenSaverActive : True
ScreenSaverExecutable : C:Windowssystem32logon.scr
ScreenSaverSecure : True
ScreenSaverTimeout : 600
SettingID :
Wallpaper :
WallpaperStretched : False
WallpaperTiled :
As you can see from the properties and values that are returned from the Get-WmiObject cmdlet, much of the information is valuable. Items such as screen saver timeout values and secure screen saver are of routine concern to many network administrators. While it is true these values can, and in most cases should, be set via Group Policy, there are times when network administrators want the ability to change these values via script. If you use the Get-Member cmdlet to examine the properties of the Win32_Desktop WMI class, you will be greeted with the following information.
PS C:> Get-WmiObject Win32_Desktop | Get-Member
TypeName: System.Management.ManagementObject#rootcimv2Win32_Desktop
Name MemberType Definition
—- ———- ———-
BorderWidth Property System.UInt32 BorderWidth {get;set;}
Caption Property System.String Caption {get;set;}
CoolSwitch Property System.Boolean CoolSwitch {get;set;}
CursorBlinkRate Property System.UInt32 CursorBlinkRate {get;set;}
Description Property System.String Description {get;set;}
DragFullWindows Property System.Boolean DragFullWindows {get;set;}
GridGranularity Property System.UInt32 GridGranularity {get;set;}
IconSpacing Property System.UInt32 IconSpacing {get;set;}
IconTitleFaceName Property System.String IconTitleFaceName {get;set;}
IconTitleSize Property System.UInt32 IconTitleSize {get;set;}
IconTitleWrap Property System.Boolean IconTitleWrap {get;set;}
Name Property System.String Name {get;set;}
Pattern Property System.String Pattern {get;set;}
ScreenSaverActive Property System.Boolean ScreenSaverActive {get;set;}
ScreenSaverExecutable Property System.String ScreenSaverExecutable {get;…
ScreenSaverSecure Property System.Boolean ScreenSaverSecure {get;set;}
ScreenSaverTimeout Property System.UInt32 ScreenSaverTimeout {get;set;}
SettingID Property System.String SettingID {get;set;}
Wallpaper Property System.String Wallpaper {get;set;}
WallpaperStretched Property System.Boolean WallpaperStretched {get;set;}
WallpaperTiled Property System.Boolean WallpaperTiled {get;set;}
__CLASS Property System.String __CLASS {get;set;}
__DERIVATION Property System.String[] __DERIVATION {get;set;}
__DYNASTY Property System.String __DYNASTY {get;set;}
__GENUS Property System.Int32 __GENUS {get;set;}
__NAMESPACE Property System.String __NAMESPACE {get;set;}
__PATH Property System.String __PATH {get;set;}
__PROPERTY_COUNT Property System.Int32 __PROPERTY_COUNT {get;set;}
__RELPATH Property System.String __RELPATH {get;set;}
__SERVER Property System.String __SERVER {get;set;}
__SUPERCLASS Property System.String __SUPERCLASS {get;set;}
ConvertFromDateTime ScriptMethod System.Object ConvertFromDateTime();
ConvertToDateTime ScriptMethod System.Object ConvertToDateTime();
When you use the filter parameter to get a specific instance of the Win32_Desktop WMI class and store it in a variable, you can directly access the properties of the class. In this example we need to escape the backward slash that is used as a separator between NT Authority and System. This is shown here.
PS C:> $desktop = Get-WmiObject Win32_Desktop -Filter `
>> “name = ‘NT AUTHORITY\SYSTEM'”
After you have access to a specific instance of the WMI class, you can assign a new value for the ScreenSaverTimeout parameter. As shown here, the value is updated immediately:
PS C:> $Desktop.ScreenSaverTimeout = 300
PS C:> $Desktop.ScreenSaverTimeout
300
However, if you resubmit the WMI query, you will see that the ScreenSaverTimeout property was not updated. The get:set that is reported by the Get-Member cmdlet is related to the copy of the object that is returned by the WMI query, and not to the actual instance of the object represented by the WMI class. This is seen here:
PS C:> $desktop = Get-WmiObject Win32_Desktop -Filter `
>> “name = ‘NT AUTHORITY\SYSTEM'”
>>
PS C:> $Desktop.ScreenSaverTimeout
600
To set the screen saver timeout value, you will need to edit the registry. The GetSetScreenSaverTimeOut.ps1 script uses the Set-ItemProperty cmdlet to assign a new value to the ScreenSaverTimeout registry key. The GetSetScreenSaverTimeOut.ps1 script accepts two command-line parameters. The first parameter is a debug switch, and the second is the new screen saver timeout value you wish to set.
The Get-ItemProperty cmdlet is used to read the current value of the screen saver timeout value from the registry. It accepts the path to the registry key and the name of the registry property. The Get-RegistryValue function calls the Get-ItemProperty cmdlet and stores the returned value in the $in reference variable. The Get-RegistryValue function is seen here:
Function Get-RegistryValue([ref]$in)
{
Write-Debug $MyInvocation.MyCommand.name
$in.value = (Get-ItemProperty -path $path -name $name).$name
} #end Get-RegistryValue
The Set-ItemProperty cmdlet accepts the path to the registry key, the name of the registry property to modify, and the new value to assign to the registry key. This is seen in the Set-RegistryValue function:
Function Set-RegistryValue($value)
{
Write-Debug $MyInvocation.MyCommand.name
Set-ItemProperty -Path $path -name $name -value $value
} #end Get-RegistryValue
The Write-Feedback function is used to display the value stored in the screen saver timeout registry key. This function is seen here:
Function Write-Feedback($in)
{
Write-Debug $MyInvocation.MyCommand.name
“The $name is set to $($in)”
} #end Write-Feedback
If the script is run with the –debug switch, the Write-Debug cmdlet will display additional information on the screen. This is seen here:
The complete GetSetScreenSaverTimeOut.ps1 script is seen here.
GetSetScreenSaverTimeOut.ps1
Param([switch]$debug, $value = 120)
Function Get-RegistryValue([ref]$in)
{
Write-Debug $MyInvocation.MyCommand.name
$in.value = (Get-ItemProperty -path $path -name $name).$name
} #end Get-RegistryValue
Function Set-RegistryValue($value)
{
Write-Debug $MyInvocation.MyCommand.name
Set-ItemProperty -Path $path -name $name -value $value
} #end Get-RegistryValue
Function Write-Feedback($in)
{
Write-Debug $MyInvocation.MyCommand.name
“The $name is set to $($in)”
} #end Write-Feedback
# *** Entry Point ***
if($debug) { $DebugPreference = “continue” }
$path = ‘HKCU:Control PanelDesktop’
$name = ‘ScreenSaveTimeOut’
$in = $null
Get-RegistryValue([ref]$in)
Write-Feedback($in)
Set-RegistryValue($value)
Get-RegistryValue([ref]$in)
Write-Feedback($in)
HR, that is all there is to setting the screen saver timeout value. WMI Week will continue tomorrow.
If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson and Craig Liebendorfer, Scripting Guys
0 comments