156

What's the best way to shut down the computer from a C# program?

I've found a few methods that work - I'll post them below - but none of them are very elegant. I'm looking for something that's simpler and natively .net.

John Auld
  • 476
  • 2
  • 12
roomaroo
  • 5,831
  • 4
  • 31
  • 31

17 Answers17

188

Works starting with windows XP, not available in win 2000 or lower:

This is the quickest way to do it:

Process.Start("shutdown","/s /t 0");

Otherwise use P/Invoke or WMI like others have said.

Edit: how to avoid creating a window

var psi = new ProcessStartInfo("shutdown","/s /t 0");
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
Process.Start(psi);
Pop Catalin
  • 61,751
  • 23
  • 87
  • 115
  • 2
    This appears to work from services too (at least in the scenarios I'm concerned with). I was never able to get the WMI or ExitWindowsEx methods to work from a service. – James Jul 28 '11 at 17:34
  • 1
    @James It's because a service usually doesnt have the permissions for it. – AK_ Apr 11 '13 at 21:20
  • 1
    The power consumption state of the machine is different after using this, than after using the traditional shutdown dialog window. Pushing the power button to boot back up draws about 80-85 milliamps, rather than the standard 300+ish. Will post back here if I find out why. This should not affect most users. – samuelesque Feb 27 '14 at 21:29
  • This works great, except the fact that if you are in WPF, this will spawn a console window for a split second, not exactly professional looking. – Dustin Jensen Feb 23 '15 at 07:23
  • For me it just shows a window saying 'waiting for following apps to close' and they never close, so it doesnt really work. Any way to kill all running apps so system actually shuts down? When I shut it down manually, it kills all opened apps, while this method doesnt, it just waiting forever – csharp newbie May 09 '23 at 10:28
86

Taken from: a Geekpedia post

This method uses WMI to shutdown windows.

You'll need to add a reference to System.Management to your project to use this.

using System.Management;

void Shutdown()
{
    ManagementBaseObject mboShutdown = null;
    ManagementClass mcWin32 = new ManagementClass("Win32_OperatingSystem");
    mcWin32.Get();

    // You can't shutdown without security privileges
    mcWin32.Scope.Options.EnablePrivileges = true;
    ManagementBaseObject mboShutdownParams =
             mcWin32.GetMethodParameters("Win32Shutdown");

     // Flag 1 means we want to shut down the system. Use "2" to reboot.
    mboShutdownParams["Flags"] = "1";
    mboShutdownParams["Reserved"] = "0";
    foreach (ManagementObject manObj in mcWin32.GetInstances())
    {
        mboShutdown = manObj.InvokeMethod("Win32Shutdown", 
                                       mboShutdownParams, null);
    }
}
Ian R. O'Brien
  • 6,682
  • 9
  • 45
  • 73
roomaroo
  • 5,831
  • 4
  • 31
  • 31
  • 3
    Using WMI makes it easier to track errors. What happens if the shutdown command doesn't work for some reason? – Rob Walker Sep 19 '08 at 15:06
  • 2
    I'm using this method to shut down windows, and two out of three times it'll tell me I lack permissions, but the third time, it sot of "gives up" and restarts the computer anyway. What's up with that? – DTI-Matt Jun 26 '12 at 20:16
  • 2
    This solution does not work for me. I get "Privilege not held" exception even if I run program under administrator user. – Fanda Sep 03 '13 at 12:41
  • @roomaroo This method doesn't work. It throws an exception: Management exception, privilege not held. – somethingSomething Nov 07 '13 at 13:40
  • 1
    If you want to shutdown forcedly you should use mboShutdownParams["Flags"] = "5"; Value 5 means forced shutdown. – EngineerSpock Aug 07 '14 at 05:08
  • This code is boring – Zeko Aug 31 '23 at 17:44
  • Why not just throw an exception and tell me whats wrong why memorise all this why not ‘System.Shutdown()’ – Zeko Aug 31 '23 at 17:47
34

This thread provides the code necessary: http://bytes.com/forum/thread251367.html

but here's the relevant code:

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack=1)]
internal struct TokPriv1Luid
{
    public int Count;
    public long Luid;
    public int Attr;
}

[DllImport("kernel32.dll", ExactSpelling=true) ]
internal static extern IntPtr GetCurrentProcess();

[DllImport("advapi32.dll", ExactSpelling=true, SetLastError=true) ]
internal static extern bool OpenProcessToken( IntPtr h, int acc, ref IntPtr
phtok );

[DllImport("advapi32.dll", SetLastError=true) ]
internal static extern bool LookupPrivilegeValue( string host, string name,
ref long pluid );

[DllImport("advapi32.dll", ExactSpelling=true, SetLastError=true) ]
internal static extern bool AdjustTokenPrivileges( IntPtr htok, bool disall,
ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen );

[DllImport("user32.dll", ExactSpelling=true, SetLastError=true) ]
internal static extern bool ExitWindowsEx( int flg, int rea );

internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
internal const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
internal const int EWX_LOGOFF = 0x00000000;
internal const int EWX_SHUTDOWN = 0x00000001;
internal const int EWX_REBOOT = 0x00000002;
internal const int EWX_FORCE = 0x00000004;
internal const int EWX_POWEROFF = 0x00000008;
internal const int EWX_FORCEIFHUNG = 0x00000010;

private void DoExitWin( int flg )
{
    bool ok;
    TokPriv1Luid tp;
    IntPtr hproc = GetCurrentProcess();
    IntPtr htok = IntPtr.Zero;
    ok = OpenProcessToken( hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok );
    tp.Count = 1;
    tp.Luid = 0;
    tp.Attr = SE_PRIVILEGE_ENABLED;
    ok = LookupPrivilegeValue( null, SE_SHUTDOWN_NAME, ref tp.Luid );
    ok = AdjustTokenPrivileges( htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero );
    ok = ExitWindowsEx( flg, 0 );
    }

Usage:

DoExitWin( EWX_SHUTDOWN );

or

DoExitWin( EWX_REBOOT );
abatishchev
  • 98,240
  • 88
  • 296
  • 433
Stephen Wrighton
  • 36,783
  • 6
  • 67
  • 86
  • You can read about what the other EWX_ contstants do here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa376868%28v=vs.85%29.aspx – TripleAntigen Apr 10 '14 at 01:59
  • 1
    When porting numeric constants to C#, best practice is to use an enum. That's what an enum is designed to do. It gives strong typing around numeric constants, optionally supports flags / bitmasks, and easily casts back and forth to the underlying numeric type. – Andrew Rondeau Aug 24 '17 at 17:14
27

Different methods:

A. System.Diagnostics.Process.Start("Shutdown", "-s -t 10");

B. Windows Management Instrumentation (WMI)

C. System.Runtime.InteropServices Pinvoke

D. System Management

After I submit, I have seen so many others also have posted...

Ian R. O'Brien
  • 6,682
  • 9
  • 45
  • 73
lakshmanaraj
  • 4,145
  • 23
  • 12
15

Short and sweet. Call an external program:

    using System.Diagnostics;

    void Shutdown()
    {
        Process.Start("shutdown.exe", "-s -t 00");
    }

Note: This calls Windows' Shutdown.exe program, so it'll only work if that program is available. You might have problems on Windows 2000 (where shutdown.exe is only available in the resource kit) or XP Embedded.

roomaroo
  • 5,831
  • 4
  • 31
  • 31
14

The old-school ugly method. Use the ExitWindowsEx function from the Win32 API.

using System.Runtime.InteropServices;

void Shutdown2()
{
    const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
    const short SE_PRIVILEGE_ENABLED = 2;
    const uint EWX_SHUTDOWN = 1;
    const short TOKEN_ADJUST_PRIVILEGES = 32;
    const short TOKEN_QUERY = 8;
    IntPtr hToken;
    TOKEN_PRIVILEGES tkp;

    // Get shutdown privileges...
    OpenProcessToken(Process.GetCurrentProcess().Handle, 
          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out hToken);
    tkp.PrivilegeCount = 1;
    tkp.Privileges.Attributes = SE_PRIVILEGE_ENABLED;
    LookupPrivilegeValue("", SE_SHUTDOWN_NAME, out tkp.Privileges.pLuid);
    AdjustTokenPrivileges(hToken, false, ref tkp, 0U, IntPtr.Zero, 
          IntPtr.Zero);

    // Now we have the privileges, shutdown Windows
    ExitWindowsEx(EWX_SHUTDOWN, 0);
}

// Structures needed for the API calls
private struct LUID
{
    public int LowPart;
    public int HighPart;
}
private struct LUID_AND_ATTRIBUTES
{
    public LUID pLuid;
    public int Attributes;
}
private struct TOKEN_PRIVILEGES
{
    public int PrivilegeCount;
    public LUID_AND_ATTRIBUTES Privileges;
}

[DllImport("advapi32.dll")]
static extern int OpenProcessToken(IntPtr ProcessHandle, 
                     int DesiredAccess, out IntPtr TokenHandle);

[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AdjustTokenPrivileges(IntPtr TokenHandle,
    [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges,
    ref TOKEN_PRIVILEGES NewState,
    UInt32 BufferLength,
    IntPtr PreviousState,
    IntPtr ReturnLength);

[DllImport("advapi32.dll")]
static extern int LookupPrivilegeValue(string lpSystemName, 
                       string lpName, out LUID lpLuid);

[DllImport("user32.dll", SetLastError = true)]
static extern int ExitWindowsEx(uint uFlags, uint dwReason);

In production code you should be checking the return values of the API calls, but I left that out to make the example clearer.

Ian R. O'Brien
  • 6,682
  • 9
  • 45
  • 73
roomaroo
  • 5,831
  • 4
  • 31
  • 31
10

Just to add to Pop Catalin's answer, here's a one liner which shuts down the computer without displaying any windows:

Process.Start(new ProcessStartInfo("shutdown", "/s /t 0") {
  CreateNoWindow = true, UseShellExecute = false
});
Anand G
  • 3,130
  • 1
  • 22
  • 28
man
  • 423
  • 1
  • 6
  • 11
9
System.Diagnostics.Process.Start("shutdown", "/s /t 0")

Should work.

For restart, it's /r

This will restart the PC box directly and cleanly, with NO dialogs.

Fattie
  • 27,874
  • 70
  • 431
  • 719
Micah Vertal
  • 564
  • 1
  • 7
  • 16
  • This is the perfect answer on modern (2015+) systems. – Fattie Apr 11 '15 at 03:29
  • thanks, could you explain what the /s and the /t 0 do? – Mister Verleg Feb 11 '16 at 16:21
  • 1
    @Peterverleg Sure. The "/s" argument tells the computer to shutdown and the "/t" tells the computer to wait for x seconds before shutting down. I know from personal experience that the "/t" argument does not do anything in Windows 8.1, but it does work in 7 for sure. You can use these functions also: `shutdown /s /t 0 //For shutdown` `shutdown /r /t 0 //For restart` `shutdown /h /t 0 //For hibernate` Also, try typing them into CMD for the same result. – Micah Vertal Feb 13 '16 at 00:13
8

Note that shutdown.exe is just a wrapper around InitiateSystemShutdownEx, which provides some niceties missing in ExitWindowsEx

Liam
  • 27,717
  • 28
  • 128
  • 190
unbob
  • 331
  • 3
  • 7
5

You can launch the shutdown process:

  • shutdown -s -t 0 - Shutdown
  • shutdown -r -t 0 - Restart
Jason Plank
  • 2,336
  • 5
  • 31
  • 40
RichS
  • 3,097
  • 30
  • 26
5

I had trouble trying to use the WMI method accepted above because i always got privilige not held exceptions despite running the program as an administrator.

The solution was for the process to request the privilege for itself. I found the answer at http://www.dotnet247.com/247reference/msgs/58/292150.aspx written by a guy called Richard Hill.

I've pasted my basic use of his solution below in case that link gets old.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
using System.Runtime.InteropServices;
using System.Security;
using System.Diagnostics;

namespace PowerControl
{
    public class PowerControl_Main
    {


        public void Shutdown()
        {
            ManagementBaseObject mboShutdown = null;
            ManagementClass mcWin32 = new ManagementClass("Win32_OperatingSystem");
            mcWin32.Get();

            if (!TokenAdjuster.EnablePrivilege("SeShutdownPrivilege", true))
            {
                Console.WriteLine("Could not enable SeShutdownPrivilege");
            }
            else
            {
                Console.WriteLine("Enabled SeShutdownPrivilege");
            }

            // You can't shutdown without security privileges
            mcWin32.Scope.Options.EnablePrivileges = true;
            ManagementBaseObject mboShutdownParams = mcWin32.GetMethodParameters("Win32Shutdown");

            // Flag 1 means we want to shut down the system
            mboShutdownParams["Flags"] = "1";
            mboShutdownParams["Reserved"] = "0";

            foreach (ManagementObject manObj in mcWin32.GetInstances())
            {
                try
                {
                    mboShutdown = manObj.InvokeMethod("Win32Shutdown",
                                                   mboShutdownParams, null);
                }
                catch (ManagementException mex)
                {
                    Console.WriteLine(mex.ToString());
                    Console.ReadKey();
                }
            }
        }


    }


    public sealed class TokenAdjuster
    {
        // PInvoke stuff required to set/enable security privileges
        [DllImport("advapi32", SetLastError = true),
        SuppressUnmanagedCodeSecurityAttribute]
        static extern int OpenProcessToken(
        System.IntPtr ProcessHandle, // handle to process
        int DesiredAccess, // desired access to process
        ref IntPtr TokenHandle // handle to open access token
        );

        [DllImport("kernel32", SetLastError = true),
        SuppressUnmanagedCodeSecurityAttribute]
        static extern bool CloseHandle(IntPtr handle);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern int AdjustTokenPrivileges(
        IntPtr TokenHandle,
        int DisableAllPrivileges,
        IntPtr NewState,
        int BufferLength,
        IntPtr PreviousState,
        ref int ReturnLength);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern bool LookupPrivilegeValue(
        string lpSystemName,
        string lpName,
        ref LUID lpLuid);

        [StructLayout(LayoutKind.Sequential)]
        internal struct LUID
        {
            internal int LowPart;
            internal int HighPart;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct LUID_AND_ATTRIBUTES
        {
            LUID Luid;
            int Attributes;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct _PRIVILEGE_SET
        {
            int PrivilegeCount;
            int Control;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] // ANYSIZE_ARRAY = 1
            LUID_AND_ATTRIBUTES[] Privileges;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct TOKEN_PRIVILEGES
        {
            internal int PrivilegeCount;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
            internal int[] Privileges;
        }
        const int SE_PRIVILEGE_ENABLED = 0x00000002;
        const int TOKEN_ADJUST_PRIVILEGES = 0X00000020;
        const int TOKEN_QUERY = 0X00000008;
        const int TOKEN_ALL_ACCESS = 0X001f01ff;
        const int PROCESS_QUERY_INFORMATION = 0X00000400;

        public static bool EnablePrivilege(string lpszPrivilege, bool
        bEnablePrivilege)
        {
            bool retval = false;
            int ltkpOld = 0;
            IntPtr hToken = IntPtr.Zero;
            TOKEN_PRIVILEGES tkp = new TOKEN_PRIVILEGES();
            tkp.Privileges = new int[3];
            TOKEN_PRIVILEGES tkpOld = new TOKEN_PRIVILEGES();
            tkpOld.Privileges = new int[3];
            LUID tLUID = new LUID();
            tkp.PrivilegeCount = 1;
            if (bEnablePrivilege)
                tkp.Privileges[2] = SE_PRIVILEGE_ENABLED;
            else
                tkp.Privileges[2] = 0;
            if (LookupPrivilegeValue(null, lpszPrivilege, ref tLUID))
            {
                Process proc = Process.GetCurrentProcess();
                if (proc.Handle != IntPtr.Zero)
                {
                    if (OpenProcessToken(proc.Handle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
                    ref hToken) != 0)
                    {
                        tkp.PrivilegeCount = 1;
                        tkp.Privileges[2] = SE_PRIVILEGE_ENABLED;
                        tkp.Privileges[1] = tLUID.HighPart;
                        tkp.Privileges[0] = tLUID.LowPart;
                        const int bufLength = 256;
                        IntPtr tu = Marshal.AllocHGlobal(bufLength);
                        Marshal.StructureToPtr(tkp, tu, true);
                        if (AdjustTokenPrivileges(hToken, 0, tu, bufLength, IntPtr.Zero, ref ltkpOld) != 0)
                        {
                            // successful AdjustTokenPrivileges doesn't mean privilege could be changed
                            if (Marshal.GetLastWin32Error() == 0)
                            {
                                retval = true; // Token changed
                            }
                        }
                        TOKEN_PRIVILEGES tokp = (TOKEN_PRIVILEGES)Marshal.PtrToStructure(tu,
                        typeof(TOKEN_PRIVILEGES));
                        Marshal.FreeHGlobal(tu);
                    }
                }
            }
            if (hToken != IntPtr.Zero)
            {
                CloseHandle(hToken);
            }
            return retval;
        }

    }
}
m3z
  • 980
  • 16
  • 32
  • 2
    This worked, although I dislike not knowing why. I honestly wonder if I should have just gone with the "shutdown" command... – Dan Bailiff Jul 26 '12 at 21:12
2

I tried roomaroo's WMI method to shutdown Windows 2003 Server, but it would not work until I added `[STAThread]' (i.e. "Single Threaded Apartment" threading model) to the Main() declaration:

[STAThread]
public static void Main(string[] args) {
    Shutdown();
}

I then tried to shutdown from a thread, and to get that to work I had to set the "Apartment State" of the thread to STA as well:

using System.Management;
using System.Threading;

public static class Program {

    [STAThread]
    public static void Main(string[] args) {
        Thread t = new Thread(new ThreadStart(Program.Shutdown));
        t.SetApartmentState(ApartmentState.STA);
        t.Start();
        ...
    }

    public static void Shutdown() {
        // roomaroo's code
    }
}

I'm a C# noob, so I'm not entirely sure of the significance of STA threads in terms of shutting down the system (even after reading the link I posted above). Perhaps someone else can elaborate...?

Community
  • 1
  • 1
MisterEd
  • 1,725
  • 1
  • 14
  • 15
  • Actually, only the thread that calls WMI needs to be STA thread. If that's not the main thread, `Main()` does not need `[STAThread]`. – SLaks Aug 09 '12 at 23:14
2

**Elaborated Answer...

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
// Remember to add a reference to the System.Management assembly
using System.Management;
using System.Diagnostics;

namespace ShutDown
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnShutDown_Click(object sender, EventArgs e)
        {
            ManagementBaseObject mboShutdown = null;
            ManagementClass mcWin32 = new ManagementClass("Win32_OperatingSystem");
            mcWin32.Get();

            // You can't shutdown without security privileges
            mcWin32.Scope.Options.EnablePrivileges = true;
            ManagementBaseObject mboShutdownParams = mcWin32.GetMethodParameters("Win32Shutdown");

            // Flag 1 means we want to shut down the system
            mboShutdownParams["Flags"] = "1";
            mboShutdownParams["Reserved"] = "0";

            foreach (ManagementObject manObj in mcWin32.GetInstances())
            {
                mboShutdown = manObj.InvokeMethod("Win32Shutdown", mboShutdownParams, null);
            }
        }
    }
}
adrianbanks
  • 81,306
  • 22
  • 176
  • 206
Fazil Mir
  • 21
  • 1
1

Use shutdown.exe. To avoid problem with passing args, complex execution, execution from WindowForms use PowerShell execute script:

using System.Management.Automation;
...
using (PowerShell PowerShellInstance = PowerShell.Create())
{
    PowerShellInstance.AddScript("shutdown -a; shutdown -r -t 100;");
    // invoke execution on the pipeline (collecting output)
    Collection<PSObject> PSOutput = PowerShellInstance.Invoke();
} 

System.Management.Automation.dll should be installed on OS and available in GAC.

Sorry for My english.

user1785960
  • 565
  • 5
  • 17
1

For Windows 10, I needed to add /f option in order to shutdown the pc without any question and wait time.

//This did not work for me
Process.Start("shutdown", "/s /t 0");

//But this worked
Process.Start("shutdown", "/s /f /t 0");
NthDeveloper
  • 969
  • 8
  • 16
0

There is no .net native method for shutting off the computer. You need to P/Invoke the ExitWindows or ExitWindowsEx API call.

Yes - that Jake.
  • 16,725
  • 14
  • 70
  • 96
0

If you want to shut down computer remotely then you can use

Using System.Diagnostics;

on any button click

{
    Process.Start("Shutdown","-i");
}
Jason Plank
  • 2,336
  • 5
  • 31
  • 40