Control Your ScreenSaver With Powershell

I was playing around with some system changes and thought it would be cool to be able to set the screen saver timeout on my machine.  Now, I know you can use the registry provider in Powershell to set the timeout in the registry, but you have to log off and log on or restart your machine to get that to work.  What I am talking about is real-time updates to the screen saver timeout setting right from the Powershell console!

I had seen a couple of programs that took advantage of the technology I am going to discuss, but until just recently, I have not been able to figure out exactly how it was being done.  This frustrated me.  So every so often, I have picked up this idea and worked at it until I finally have an answer.

In C#, you have the ability to “import” dll files to use the functions inside.  Luckily, Microsoft has provided a pretty comprehensive list of all the things you can control as well as the values of the items you might want to view or change.  This particular function, SystemParametersInfo, is called from the “user32.dll” library.

To begin, you will need to set up the signature information for how Powershell can call into this library.

$signature=@"[DllImport("user32.dll")]
public static extern bool SystemParametersInfo(int uAction, int uParam, ref int lpvParam, int flags );
"@

This is pretty straightforward.  We are using the same type of code we would use in C# to create an alias call into the user32.dll file. 

Next thing to do is to create a Powershell assembly and assign it to a variable.

$systemParamInfo = Add-Type -memberDefinition  $signature -Name ScreenSaver -passThru

I used information from the MDSN site to help figure out how to set this up.  Now all we have to do is create our Powershell functions to make use of this new in-memory assembly that has been created.

Function Get-ScreenSaverTimeout
{
  [Int32]$value = 0
  $systemParamInfo::SystemParametersInfo(14, 0, [REF]$value, 0)
  $($value/60)
}

In this function, we are creating an Int32 variable to hold the value that comes back from the procedure call.  Next we use the $systemParamInfo object and call the Static method SystemParametersInfo().  There are four parameters that are passed in to get our answer. 

uiAction Code for what we are trying to query or set.
uiParam Item specific parameter, usually “0” (zero).
pvParam Normally NULL, but in this case, will receive the return value
fWinini Specifies whether to update the user profile.

Finally, we take the returned value and divide by 60 to return the number of minutes to the console.  The next thing to do is to set up our function to set the timeout value.

Function Set-ScreenSaverTimeout
{
  Param ([Int32]$value)
  $seconds = $value * 60
  [Int32]$nullVar = 0
  $systemParamInfo::SystemParametersInfo(15, $seconds, [REF]$nullVar, 2)
}

The difference in this function is that now we are accepting an integer value to use for the timeout.  To make it easier, I am asking for the minutes instead of seconds since it is easily converted to seconds by multiplying by 60.  The function call is nearly identical to the first one.  We are using the same basic parameters with the exception of the pvParam.  This time we are passing in a garbage variable.  The only thing this procedure call will return is TRUE or FALSE based on if the update was successful.  This call is also updating the user profile, so the last parameter is “2” to force the update.

Here is the complete code.  Play around with it.  The link above that points to MSDN shows all the different settings that you can work with.  I have placed this in my Powershell Profile script so that I have these functions available when I start a session.


$signature = @"
[DllImport("user32.dll")]
public static extern bool SystemParametersInfo(int uAction, int uParam, ref int lpvParam, int flags );
"@

$systemParamInfo = Add-Type -memberDefinition  $signature -Name ScreenSaver -passThru

Function Get-ScreenSaverTimeout
{
  [Int32]$value = 0
  $systemParamInfo::SystemParametersInfo(14, 0, [REF]$value, 0)
  $($value/60)
}

Function Set-ScreenSaverTimeout
{
  Param ([Int32]$value)
  $seconds = $value * 60
  [Int32]$nullVar = 0
  $systemParamInfo::SystemParametersInfo(15, $seconds, [REF]$nullVar, 2)
}

About these ads
This entry was posted in Scripting and tagged , , , , . Bookmark the permalink.