Monday, January 14, 2013

Automating Screenshots with PowerShell

Penetration tests can become very hectic at a moment's notice. One second you are casually reviewing HTML source for a target website and the next dropping a webshell and hooking browsers before staying up all night trying to gain persistent domain-admin access to the enterprise. Keeping notes during hectic times can be difficult, tedious and potentially distracting. Sometimes, it pays to have something taking notes for you. I like to utilize both a key-logger that does time stamping and take frequent screenshots.

There are applications that can take screenshots for you at regular intervals and in the past I used an AutoIt macro to printscreen and save. That works well when I am on my own machine, but what if I was at a kiosk or doing an insider assessment from one of their workstations? I needed a PowerShell script that could take a screenshot at regular intervals, time stamp it, save it to a file and not tamper with the contents of the clipboard.

While looking for a good script to start from, I found this one that uses inline C# which seemed a little over-the-top. Another one seemed simple and straight-forward so I started working with it. After getting the function built, I was quickly annoyed with data from the clipboard disappearing. I knew I had to find another way. After digging through MSDN for an hour, I found the Bitmap Class and the System Info Class.

After loading the System.Windows.Forms assembly, I created a function that will be called to take the screenshot and save it to the disk:

Next we need a way to distinguish each file and a way to stamp them with the time it was taken:

Now we just need to settle on parameters, add this to a do-while loop and wrap the whole thing in a try-catch block. The result is Get-TimedScreenshot:


Instead of downloading or installing additional software, we now have a script that will take periodic screenshots.  The images can be large so I wouldn't recommend leaving it running overnight, but its great to help you fill in gaps in note-taking at the end of a long hacking session.

***Updated 8/6/2013: The maintained version of this script can by found within the PowerSploit framework here.

There is also a clear post-exploitation use for the function. You can schedule it to run and maybe add a check to see if the screensaver is running to make sure you aren't wasting space. I think the function is pretty flexible and with event triggering and an email function could potentially be used as a simple parental alert system. As is, it works for my purposes which is to remind me what I did today. I hope you find it useful and thanks for reading. In case you were wondering, it works well with multiple monitor setups:

Please let me know if you have any issues, bugs or questions. Hopefully, I will see you at Shmoocon and Firetalks. Also, if you are in town, check out Shmoocon Epilogue.  The other talks look really good, but I get the chance to present "No Tools? No Problem! Building a PowerShell Bot." It will cover chaining simple tasks like this one into a nefarious PowerShell script.



  1. Issue running this with provided example. . .\script -Path C:\temp -Interval 30 -EndTime 10:54

    1. There are two things you should probably check. The first is that you have a "C:\temp" directory since that is not a default directory and that you have the ability to write to it under the context that PowerShell is currently running. You should be provided a warning if either of those conditions exist.

      The next and more likely thing to check is the time. The time is in 24-hour time so if 10:54 AM has passed for the day, it will only run once and then quit. Try 22:54 if you would like it to be PM. Feel free to edit the time to allow for multi-day runs, but I prefer it to not be able to fill my hd by continuing to save screenshot images.

      Thanks for you commend and let me know if that fixes your issue.

    2. Script crash then capture UAC message

  2. Paste the content of the entire file in PS. Hit rreturn twice to return to prompt. Run command again:
    Get-TimedScreenshot -Path C:\temp -Interval 30 -EndTime 10:54
    If command executes (which it should) you have a permission issue. Check permissions and execution policy.

    1. It certainly could be a permissions issue on c:\temp, but I don't think the ExecutionPolicy comes into play since the file is just a function and call to that function. The ExecutioPolicy restrictions are only enforced on scripts.

  3. Thanks Chris for the great post.
    Here is an alternative for the filename.
    $FileName = [DateTime]::Now.ToString("MM-dd-yy-hh-mm-ss")
    MM=Month and mm=minutes


  4. Github link is not working.