Prevent desktop lock or screensaver with PowerShell

Imagine that there’s a webcast that you absolutely need to record and your girlfriend calls because she had a bad dream and you need to go to give her consolation, or it’s your daughter’s birthday, or simply 11 pm because the Earth is huge and the timezones suck. Your first reaction is to simply try to record the webcast but this is a corporate PC and group policy is configured to lock the desktop after x minutes of inactivity. What do you do?

I found myself in this situation a few days ago, and did not want to search the internet and download a random executable simulating user activity and doing who knows what else on my computer.

Instead I wrote this simple PowerShell script:

param($minutes = 60)

$myshell = New-Object -com "Wscript.Shell"

for ($i = 0; $i -lt $minutes; $i++) {
  Start-Sleep -Seconds 60
  $myshell.sendkeys(".")
}

All the script does is creates a Windows scripting shell com object, and then for the specified number of minutes (which is a script parameter) every minute presses the “.” key.

Then I saved the script as Prevent-Screensaver.ps1 file (“prevent” is not a proper PowerShell verb, but disable- or stop- do not seem quite right…) and started it from PowerShell command-line: & c:\Prevent-Screensaver.ps1 120

One other thing which I also did was starting a notepad and clicking into it. This made the script output the dots into the application rather than overload Windows input buffer (which would have caused the OS to start beeping.)

Oh, and before anyone adds comments on how I have just ruined desktop security in the enterprise… By using this you might be circumventing security measures which your company might have for a reason. Check with your HR/IT/legal department/manager when in doubt. 😉

[UPDATE] Check out what Claus posted in his comments here – an even better way of preventing the screensaver by moving the mouse cursor a bit.

Tags: ,

51 Responses to “Prevent desktop lock or screensaver with PowerShell”


  1. 1 stangm June 29, 2009 at 1:21 pm

    Using Jaykul’s WASP to send mouse clicks would help with the input buffer problem, and remove the need for launching notepad to accept the keys.

    Actually I did this a while back with a simple autoit script that I compiled as an .exe. So when I need this functionality I just run that program, and kill it when I’m done.

  2. 4 Dmitry Sotnikov June 29, 2009 at 1:36 pm

    Yep, good comments. I love Jaykul’s stuff but wanted something simple and self-contained so I ended up with the keys approach.

  3. 5 asf June 29, 2009 at 10:09 pm

    talk about using the wrong tool for the job, why is powershell even involved, just some excuse not to use a WSH script (I know its tagged a hack and you are a powershell guy, but still) The proper way to do this would be to use the windows api (You can call the native api with autoit, so using a key pressing hack there is even worse)

    And a “.”? why not toggle the start menu with ctrl+esc or something (print screen maybe if the scripting supports an escape code for that)?

  4. 6 Claus Thude Nielsen July 27, 2009 at 10:15 am

    I did something similar in AutoIt as well, just moving the mouse one “pixel”.

    So I thought I would try the same in PowerShell, here is what I ended up with, it will move the mouse one “Pixel” to the right, which is hardly noticeable.

    $Pos = [System.Windows.Forms.Cursor]::Position
    [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point((($Pos.X) + 1) , $Pos.Y)

    • 7 Vics September 8, 2009 at 6:46 pm

      What happen when your program move the mouse enough times that the screen end, do yo get bips or what ?

    • 8 garegin August 11, 2016 at 8:26 am

      So, how do you make the script stop. Would a restart do the job? I don’t want the sleep suppression to be permanent.

    • 10 Anonymous April 6, 2020 at 10:55 am

      Just to make easier for others. Following script will move move left 11 pixel then right 1 pixel. For 600 minutes (10 hours), after every 300 seconds.

      Add-Type -AssemblyName System.Windows.Forms
      for ($i = 0; $i -lt 600; $i++) {
      $Pos = [System.Windows.Forms.Cursor]::Position
      if (($i % 2) -eq 0) {
      [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point((($Pos.X) + 1) , $Pos.Y)
      }
      else {
      [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point((($Pos.X) – 1) , $Pos.Y)
      }
      Start-Sleep -Seconds 300

      }

      #This is how to execute it — powershell -ExecutionPolicy ByPass -File path_to_script\name_of_file.ps1

    • 12 Anonymous October 27, 2023 at 2:19 am

      You might add these lines to load the assemblies.. It will prevent errors missing them at run time.
      [void] [System.Reflection.Assembly]::LoadWithPartialName(“System.Drawing”)
      [void] [System.Reflection.Assembly]::LoadWithPartialName(“System.Windows.Forms”)

  5. 13 Dmitry Sotnikov July 28, 2009 at 3:16 pm

    Claus,

    This is way-way better than what I originally used!

    Learning something new every day. Thanks a lot for the tip!

    Dmitry

  6. 14 Dmitry Sotnikov September 8, 2009 at 7:38 pm

    My guess is that it will just stop at the border.

    However, you can just make it move to the side and back by doing something like:

    [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point((($Pos.X) + 1) , $Pos.Y)
    [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point($Pos.X , $Pos.Y)

    • 15 dj DeeJay October 23, 2015 at 1:37 am

      i tried the same but this is not preventing the screesaver from starting, so i landed on this page, but a keypress is also not good because it writes where the Focus is. Next I tried to consume the pressed key immedialtly but no chance 😦

  7. 16 Henrik June 10, 2010 at 10:03 am

    My problem is that my screen saver starts even though Powershell is moving the mouse pointer around.

  8. 17 Mike November 18, 2010 at 3:37 pm

    “this is a corporate PC and group policy is configured to lock the desktop after x minutes of inactivity.”

    So how do you install PowerShell?

    • 18 Dmitry Sotnikov November 18, 2010 at 3:52 pm

      Comes standard on Win 7. But yes, I hear you: in some environments it might be not present and policies might prevent installation… Luckily in my situation this was not the case.

  9. 19 Delon Newman December 15, 2010 at 12:56 am

    Here’s something similar I’ve used in VBScript

    Dim WSHShell

    Set WSHShell = CreateObject(“WScript.Shell”)

    ‘ Press key every 1.5 minutes

    Do While True
    WSHShell.SendKeys “.”
    WScript.Sleep 90000
    Loop

  10. 20 Mike February 7, 2011 at 2:46 pm

    I know you are looking to avoid 3rd party tools, but this app has saved my life a thousand times, and would be perfect for what you’re doing It’s SO EASY!!

    http://www.autohotkey.com/docs/Tutorial.htm

  11. 21 müzso October 3, 2011 at 7:25 pm

    Combining Delon’s approach with the F15 keypress from Caffeine, I came up with this:

    Dim WshShell
    Set WshShell = WScript.CreateObject(“WScript.Shell”)
    Do While True
    WshShell.SendKeys(“{F15}”)
    WScript.Sleep(55000)
    Loop

    It works on Windows XP SP3 and Windows 2008 R2, so I assume it works on everything else in between (2003, 2008, Vista, 7). And the F15 keypress does not seem to have any side effects. Pasting the above script in a *.vbs file and putting it in my user’s Startup folder works for me like a charm.
    (Note: if you use this hack in a Terminal Service session and minimize the Terminal Service client’s window, the screen will get locked locked just as usual. I guess you cannot send keys in the session via SendKeys() if it’s minimized.)

    • 22 alien June 7, 2012 at 4:14 am

      Hey the scripts does work like a charm.Thank you!
      – just wondering which process to kill in task manager, in case I want to stop the script from working.

      • 23 Keith Trangmar December 7, 2012 at 10:12 am

        If you kill WSCRIPT.EXE that’s the Windows Scripting Host, which the process that’s running the script. If the script is running in a console window, the process might be called CSCRIPT.EXE instead.

    • 24 bjosephs February 18, 2015 at 8:43 am

      Sendkeys F15 on my system makes my num-lock toggle on and off.
      Win 8.1 pro x64
      Logitech K350 keyboard.

  12. 26 Vinay Jagadeesh Naikar June 12, 2013 at 5:07 am

    Hi. .. I have a script In which i run a ‘.exe’. This .exe waits for an input from user to log some events in a file. I want to develop an automated script that runs the .exe and also simulates the key press that will be an input to the .exe for it to continue. Can anybody help me. Thanks in advance.

  13. 27 sam September 23, 2013 at 3:15 pm

    Hi Dmitry,I used the code of claus for moving the mouse pointer.
    The following is the error am getting in my cmd prompt.Thanks in advance.

    Unable to find type [System.Windows.Forms.Cursor]: make sure that the assembly
    containing this type is loaded.
    At D:\myscript.ps1:1 char:37
    + $Pos = [System.Windows.Forms.Cursor] <<<< ::Position
    + CategoryInfo : InvalidOperation: (System.Windows.Forms.Cursor:S
    tring) [], RuntimeException
    + FullyQualifiedErrorId : TypeNotFound

    New-Object : Cannot find type [System.Drawing.Point]: make sure the assembly co
    ntaining this type is loaded.
    At D:\myscript.ps1:2 char:53
    + [System.Windows.Forms.Cursor]::Position = New-Object <<<< System.Drawing.Poi
    nt((($Pos.X) + 1) , $Pos.Y)
    + CategoryInfo : InvalidType: (:) [New-Object], PSArgumentExcepti
    on
    + FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewOb
    jectCommand.

    Please advise on how to load the assemblies.

    • 28 Dmitry Sotnikov September 24, 2013 at 6:37 am

      Which version of PowerShell are you using? 3.0, right? If so, see which architecture that is. Chances are that you are on x64 Windows and the assembly only exists for the architecture different from the one that you are using. Try the same code in regular PowerShell and PowerShell x86 and see whether one of these works.

      • 29 garegin August 11, 2016 at 8:22 am

        its not a x86 or 64 issue. you need to run this command

        [System.Reflection.Assembly]::LoadWithPartialName(“System.Windows.Forms”)

  14. 30 Anonymous October 12, 2013 at 8:15 pm

    param($minutes = 60)

    $myshell = New-Object -com “Wscript.Shell”

    for ($i = 0; $i -lt $minutes; $i++) {
    Start-Sleep -Seconds 50
    $myshell.sendkeys(“{F15}”)
    }

    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! above in C:\lock.ps1

    powershell.exe -windowstyle hidden -file C:\lock.ps1

    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! above in .bat extension

    This works good for me in win 7 64bit thanks #Dmitry

  15. 31 nostrumuva June 6, 2014 at 2:44 pm

    There’s an android app called “Timeout Blocker” that vibrates at intervals you set and you can put your mouse on it. Says not to use it at work though 🙂 https://play.google.com/store/apps/details?id=com.isomerprogramming.application.timeoutblocker&hl=en

  16. 32 cgsilver August 8, 2014 at 1:06 am

    old topic but thought to share experience in case some1 comes here:
    I confirm mouse position does not prevent screensaver or sleep (probably because mouse is actually not moved, just redrawn).
    However sendkey does prevent!
    I did not experience with f15 – I needed to see the script is/was working 🙂 just start the script with notepad.exe, and you don’t have to open manually.
    also for the loop, why not timeless? my code:

    notepad.exe
    $myshell = New-Object -com “Wscript.Shell”
    $i=1
    while ($I -eq 1) {
    $myshell.sendkeys(“.”)
    start-sleep -Seconds 30
    }

    thanks for all
    cheers
    K

    • 33 Kirk October 3, 2014 at 11:05 am

      @cgsilver….sorry for the noob/basic question….I’m trying to use this script you posted but don’t exactly undertsand what to script it in, how to save it, and how to run it?

      I literally copied the scipt, pasted it into notepad, saved as “MouseMove.ps1” and that doesn’t seem to work!

      Can you give me a basic step 1-10 on how to copy, paste, save, and then run at start-up or Task Schedule.

      I have the same issue some of you all do. We have a PC at our Hospital that needs to never go to sleep, lock-screen, screensave, etc. and our Group Policy keeps reverting back to our standard 20min lock-screen setting (we can’t figure out why the setting won’t hold, it works for a day or so then breaks again). So, if this could keep the PC “awake/active” that would allow the PC to always be on until it reboots every 7am to refresh the Citrix session.

      Makes sense!?! Please help!!!!

  17. 34 Dara January 21, 2015 at 2:59 pm

    Great thread, Kirk, I don’t know if you got a resolution but copying and pasting the code, for me from IE9, gave me the wrong quotation marks; ” “.
    i had to change them manually in notepad after pasting. HTH

  18. 36 Anon February 6, 2015 at 2:48 am

    This was useful too….

    I harvested the ideas above and wrapped it into a re-usable function

    Function Pause-ScreenSaver
    {
    Param(
    [Bool]$Continue = $True, #If This Is True, The Function Will Run Forever
    [Int]$DefaultSleepTime = 60 #Time To Wait Before Re-Looping
    )

    #Create A New Shell Com Object
    $Shell = New-Object -COM “WScript.Shell”

    #While $Continue Is Tue, Loop
    While ($Continue -EQ $True)
    {
    $Shell.SendKeys(“F15”)
    Start-Sleep $DefaultSleepTime
    }
    }

  19. 37 -t. October 11, 2016 at 9:45 am

    #########################################################
    # Prevent-Screensaver
    #########################################################
    # This script moves the mouse cursor
    # (or “presses” a keyboard key) every minute
    # for specified number of minutes which makes
    # Windows “think” you are at your desktop
    # so the screensaver does not start and the desktop
    # does not get locked.
    #########################################################
    # Usage:
    # & c:\filepath\Prevent-Screensaver.ps1 -Minutes 120
    # Makes the script move the mouse (press “.”) for 120 minutes.
    # Start notepad or another app and put focus there
    # to see the dots appear and prevent beeping
    ########################################################
    # (c) Dmitry Sotnikov + T.H. Schmidt
    # https://dmitrysotnikov.wordpress.com
    ########################################################
    param($minutes = 60)

    [void] [System.Reflection.Assembly]::LoadWithPartialName(“System.Windows.Forms”)

    $myshell = New-Object -com “Wscript.Shell”

    for ($i = 0; $i -lt $minutes; $i++) {
    Start-Sleep -Seconds 60
    # $myshell.sendkeys(“.”)
    $Pos = [System.Windows.Forms.Cursor]::Position
    [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point((($Pos.X) + 1) , $Pos.Y)
    }

    • 38 Gotom November 2, 2016 at 2:55 am

      Hi,

      When I run this code I keep on getting the num lock toggled on and off. I see at least two posts where people have experienced this. Has anyone found an explanation or resolution for this issue?

      I run it on Windows 7, 64 bit.

      Thanks

  20. 39 lwsrbrts November 25, 2016 at 7:30 am

    $Shell = New-Object -ComObject Wscript.Shell
    $Shell.SendKeys(‘{PRTSC}’)

    Sends a Print Screen to the computer resulting in absolutely nothing happening. It just overwrites the clipboard with the screen’s contents. I’ve used this since the beginning of time to prevent my screen from locking – or IM services showing that I’m “away” for managers that insist on using IM status as an indicator of whether or not you’re working.

    I use a script (called Keep-Alive.ps1):

    param(
    [parameter(Mandatory=$true)][string] $Until,
    [parameter(Mandatory=$false)][switch] $Logoff = $false
    )
    $Shell = New-Object -ComObject Wscript.Shell
    Start-Sleep -Seconds 1

    Do {
    $Shell.SendKeys(‘{PRTSC}’)

    If ((Get-Date) -gt (Get-Date $Until)) {
    If ($Logoff -eq $true) {
    logoff.exe
    }
    Else {
    Break
    }
    }
    Else { Start-Sleep -Seconds 60 }
    }
    While ($true)

    I start this from a batch file with a command like one of the following:
    powershell.exe -WindowStyle Hidden -File .\Keep-Alive.ps1 -Until 17:30
    or
    powershell.exe -WindowStyle Hidden -File .\Keep-Alive.ps1 -Until 17:30 -Logoff

    As soon as the provided time (-Until) is exceeded, the script loop stops and the computer will lock itself dependent on the policy affecting the screen lock/screensaver. If you provide the -Logoff switch (As per second command), the computer will log off for you.

  21. 40 Ray July 4, 2017 at 8:15 am

    We have a similar script for preventing the idle time with keystrokes too. if the host system is a windows OS and then starting the published desktop with the script it works flawlessly, but if the host system is a linux it doesn’t work, anybody knows why?

  22. 41 Brecht Gijbels February 5, 2018 at 12:20 am

    Improved the script with PowerShell code only and cleaned up a bit of the timer loop for readability:

    Param (
    [Parameter(Mandatory)]
    [String]$Until,
    [Switch]$Logoff
    )

    Do {
    [void][System.Reflection.Assembly]::LoadWithPartialName(‘System.Windows.Forms’)
    [System.Windows.Forms.SendKeys]::SendWait(“{PRTSC}”)

    Start-Sleep -Seconds 60

    If ((Get-Date) -gt (Get-Date $Until)) {
    If ($Logoff) {
    logoff.exe
    }
    Else {
    Break
    }
    }
    } While ($true)

    • 42 Tim December 8, 2019 at 12:49 pm

      Hi, I am getting an error with the [String] $Until,
      When I run through Powershell ISE.

      I have the bat file setup with Until info in it.
      powershell.exe -WindowStyle Hidden -File C:\Users\xxx\Documents\MyScripts_Local\Keep-Alive.ps1 -Until 19:59 -Logoff

      But the script itself is expecting a value for “Until,”

      ******************************************
      Param (
      [Parameter(Mandatory)]
      [String]$Until,
      [Switch]$Logoff
      )

      Do {
      [void][System.Reflection.Assembly]::LoadWithPartialName(‘System.Windows.Forms’)
      [System.Windows.Forms.SendKeys]::SendWait(“{PRTSC}”)

      Start-Sleep -Seconds 60

      If ((Get-Date) -gt (Get-Date $Until)) {
      If ($Logoff) {
      logoff.exe
      }
      Else {
      Break
      }
      }
      } While ($true)

      **************************
      Output in PS ISE

      PS C:\Windows\system32>

      C:\Users\xxx\Documents\MyScripts_Local\KeppAliveTK.ps1
      cmdlet KeppAliveTK.ps1 at command pipeline position 1
      Supply values for the following parameters:
      Until:
      PS C:\Windows\system32>

      Thanks in advance for any suggestions.
      Tim

  23. 43 Anonymous August 15, 2018 at 6:59 am

    I found the dot being randomly placed in the active window annoying, however a simple change to

    $myshell.sendkeys(“{NUMLOCK}{NUMLOCK}”)

    does the trick since it toggles it on and off so quickly that the keyboard doesn’t even have time to change so you can happily type away without being interrupted

  24. 44 Anonymous February 7, 2019 at 2:22 pm

    Just going to leave this here. https://xkcd.com/196/

  25. 45 Viki March 13, 2019 at 4:14 am

    Thank you very much
    This script helped solve my task :)))

  26. 46 Steve July 13, 2019 at 5:16 am

    Awesome… simply awesome.

  27. 47 sriram January 1, 2021 at 4:20 am

    c:\Prevent-Screensaver.ps1 120 means it willl press . for 2 hours right.

    Thanks

  28. 48 Anonymous April 5, 2021 at 5:47 am

    So it seems like an easy solution to the buffer issue is to have the code simulate the press of the shift key every 60 seconds for a set amount of minutes such as “Anonymous” suggested. How would the code change to emulate a shift key press?

  29. 50 Arun May 30, 2021 at 6:33 am

    This is really helpful, Thank you Dmitry!


  1. 1 When Five Lines Of Powershell Isn’t Enough | C O L I N . V A N N I E K E R K . M E Trackback on May 21, 2014 at 7:54 am

Leave a comment




Legal

The posts on this blog are provided “as is” with no warranties and confer no rights. The opinions expressed on this site are mine and mine alone, and do not necessarily represent those of my employer - WSO2 or anyone else for that matter. All trademarks acknowledged.

© 2007-2014 Dmitry Sotnikov

June 2009
M T W T F S S
1234567
891011121314
15161718192021
22232425262728
2930