views:

661

answers:

2

Is there a way to find out when the system was last shutdown?

I know there's a way to find out last boot up time using the LastBootUpTime property in Win32_OperatingSystem namespace using WMI.

Is there anything similar to find out last shutdown time?

Thanks.

+3  A: 

Assuming Windows is shutdown smoothly. It stores it in the registry:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows\ShutdownTime

It is stored as an array of bytes but is a FILETIME.

While there may be a better way, I have used this before and think it works:

    public static DateTime GetLastSystemShutdown()
    {
        string sKey = @"System\CurrentControlSet\Control\Windows";
        Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(sKey);

        string sValueName = "ShutdownTime";
        object val = key.GetValue(sValueName);

        DateTime output = DateTime.MinValue;
        if (val is byte[] && ((byte[])val).Length == 8)
        {
            byte[] bytes = (byte[])val;

            System.Runtime.InteropServices.ComTypes.FILETIME ft = new System.Runtime.InteropServices.ComTypes.FILETIME();
            int valLow = bytes[0] + 256 * (bytes[1] + 256 * (bytes[2] + 256 * bytes[3]));
            int valTwo = bytes[4] + 256 * (bytes[5] + 256 * (bytes[6] + 256 * bytes[7]));
            ft.dwLowDateTime = valLow;
            ft.dwHighDateTime = valTwo;

            DateTime UTC = DateTime.FromFileTimeUtc((((long) ft.dwHighDateTime) << 32) + ft.dwLowDateTime);
            TimeZoneInfo lcl = TimeZoneInfo.Local;
            TimeZoneInfo utc = TimeZoneInfo.Utc;
            output = TimeZoneInfo.ConvertTime(UTC, utc, lcl);
        }
        return output;
    }
JDunkerley
+1 fine approach, I deleted my post, as this is far more accurate it seems
Abel
sorry, I couldn't resist, there seems to be slightly easier way to convert a byte array to a `DateTime`, hope you don't mind, but I couldn't have done it without your answer :)
Abel
+1  A: 

(everything here is 100% courtesy of JDunkerley's earlier answer)

The solution is above, but the approach of going from a byte array to DateTime can be achieved with fewer statements using the BitConverter.The following six lines of code do the same and give the correct DateTime from the registry:

public static DateTime GetLastSystemShutdown()
{
    string sKey = @"System\CurrentControlSet\Control\Windows";
    Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(sKey);

    string sValueName = "ShutdownTime";
    byte[] val = (byte[]) key.GetValue(sValueName);
    long valueAsLong = BitConverter.ToInt64(val, 0);
    return DateTime.FromFileTime(valueAsLong);
}
Abel
Hmm, thanks for accepting, but the solution provided here is totally based on JDunkerley's answer, he should receive all credit, basically ;-)
Abel