Restarting PCs with Python

Have you ever wanted to restart your Windows PC with out pressing Start, Shutdown or CTRL+ALT+DEL? What about restarting your annoying co-worker’s PC…the one who just doesn’t know when to shut up? Well, Python has the answer and this blog will tell you how to do it! Note: I don’t actually recommend rebooting your neighbor’s PC at random…

Rebooting with PyWin32

Anyway, back when I was first learning about Python, I stumbled upon an ActiveState recipe on how to do this. Of course, now I can’t seem to find that recipe, but I found a similar one here: http://code.activestate.com/recipes/360649/. Thus, we’ll start with this method first and then look at a slightly different approach. If you’d like to follow along, then you’ll need to make sure you have the PyWin32 package.

Here’s my version of the recipe from my foggy past:

# rebootServer.py

import win32security
import win32api
import sys
import time
from ntsecuritycon import *

def AdjustPrivilege(priv, enable=1):
    # Get the process token
    flags = TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
    htoken = win32security.OpenProcessToken(win32api.GetCurrentProcess(), flags)
    # Get the ID for the system shutdown privilege.
    idd = win32security.LookupPrivilegeValue(None, priv)
    # Now obtain the privilege for this process.
    # Create a list of the privileges to be added.
    if enable:
        newPrivileges = [(idd, SE_PRIVILEGE_ENABLED)]
    else:
        newPrivileges = [(idd, 0)]
    # and make the adjustment
    win32security.AdjustTokenPrivileges(htoken, 0, newPrivileges)

def RebootServer(message='Rebooting', timeout=30, bForce=0, bReboot=1):
    AdjustPrivilege(SE_SHUTDOWN_NAME)
    try:
        win32api.InitiateSystemShutdown(None, message, timeout, bForce, bReboot)
    finally:
        # Now we remove the privilege we just added.
        AdjustPrivilege(SE_SHUTDOWN_NAME, 0)

def AbortReboot():
    AdjustPrivilege(SE_SHUTDOWN_NAME)
    try:
        win32api.AbortSystemShotdown(None)
    finally:
        AdjustPrivilege(SE_SHUTDOWN_NAME, 0)

if __name__ == '__main__':
    RebootServer()
    time.sleep(10)
    print 'Aborting shutdown'
    AbortReboot()

I actually took out the ability to reboot remote machines in this snippet just because I didn’t want to be tempted to do so. If you want to reboot a machine on your network, change the following line:

win32api.InitiateSystemShutdown(None, message, timeout, bForce, bReboot)

to

win32api.InitiateSystemShutdown("someMachineName", message, timeout, bForce, bReboot)

or just add a host parameter to the RebootServer function and modify the InitiateSystemShutdown as necessary. If you just pass None in, then you’ll just reboot your own machine. The AdjustPrivilege method is used to change the privilege of the process so that it can actually shut the PC down. I think that only applies if you run the script as a user with limited privileges, but I almost never run that way so I can’t be sure. I do remember the recipe stating that you needed to remove the privileges that you added, which is what the finally statement is for. However, I would assume that once the reboot is complete, those privileges would have been revoked anyway.

Rebooting with just Plain Ol’ Python

The other way to initiate a shutdown is to learn the magic of your Windows command line. There is a shutdown command that you can put into your Run dialog (go to Start –> Run) that will reboot your PC too. Here’s the one I’m talking about: shutdown -r -t 1 Note that this will only restart the local machine!

Now we just need to figure out how to make Python call that for us. Probably the simplest way to do so is to import the os module and call its system method. Let’s take a look:

import os
os.system("shutdown -r -t 1")

This is much shorter than the PyWin32 method, but I don’t know that it’s as robust. I used this method in a quick and dirty wxPython application I created for our Sun Ray virtual machines at work. One of the biggest problems with the Sun Ray system is that the user is connected to their virtual machine using Remote Desktop. A part of Remote Desktop is to hide the Shutdown button, so there is no simple way for the user to restart their PC unless they’re installed some kind of hotfix that does it for them. There are times when rebooting a machine is a good thing, so I took the script above and put it into the following application:

import os
import wx
from wx.lib.buttons import GenBitmapButton

########################################################################
class RestarterPanel(wx.Panel):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent=parent)
        
        img = wx.Bitmap("cute-logoff.png")
        logoutBtn = GenBitmapButton(self, wx.ID_ANY, img, style=wx.BORDER_NONE)
        logoutBtn.Bind(wx.EVT_BUTTON, self.onLogout)

        img = wx.Bitmap("quick_restart.png")
        restartBtn = GenBitmapButton(self, wx.ID_ANY, img, style=wx.BORDER_NONE)
        restartBtn.Bind(wx.EVT_BUTTON, self.onRestart)
        
        cancelBtn = wx.Button(self, label="Cancel")
        cancelBtn.Bind(wx.EVT_BUTTON, self.onCancel)
        
        vSizer = wx.BoxSizer(wx.VERTICAL)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(self.buttonBuilder("Logout", logoutBtn), 0, wx.CENTER)
        sizer.Add(self.buttonBuilder("Restart", restartBtn), 0, wx.CENTER)
        vSizer.Add(sizer, 0, wx.CENTER)
        vSizer.Add(cancelBtn, 0, wx.ALIGN_RIGHT|wx.ALL, 5)
        self.SetSizer(vSizer)
        
    #----------------------------------------------------------------------
    def buttonBuilder(self, label, button):
        """
        Creates a button with a label underneath it and puts them into
        a vertical BoxSizer, which is then returned
        """
        font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(button, 0, wx.ALL, 3)
        
        lbl = wx.StaticText(self, label=label)
        lbl.SetFont(font)
        sizer.Add(lbl, 0, wx.CENTER|wx.BOTTOM, 4)
        
        return sizer
    
    #----------------------------------------------------------------------
    def onCancel(self, event):
        """
        Close the dialog
        """
        self.GetParent().Close()
    
    #----------------------------------------------------------------------
    def onLogout(self, event):
        """
        Logs the current user out
        """
        os.system("shutdown -t 0 -l")
        
    #----------------------------------------------------------------------
    def onRestart(self, event):
        """
        Restarts the PC
        """
        os.system("shutdown -r -t 1")
        
########################################################################
class RestarterFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, size=(273, 169))
        panel = RestarterPanel(self)
        self.Center()
     
########################################################################
class Main(wx.App):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, redirect=False, filename=None):
        """Constructor"""
        wx.App.__init__(self, redirect, filename)
        dlg = RestarterFrame()
        dlg.Show()
        
#----------------------------------------------------------------------
if __name__ == "__main__":
    app = Main()
    app.MainLoop()

I looked at a lot of icons for this project and I think I ended up just doing searches for shutdown and logout icons and downloaded the ones I liked the best. Both of these free or had Creative Commons licenses.

Now you know the tricks to restart local and remote machines. Use this knowledge wisely!

4 thoughts on “Restarting PCs with Python”

  1. Hi Tim,

    I use Wingware’s Python IDE which has templates for that sort of thing. I like the way it separates things too.

    – Mike

Comments are closed.