12

I need to develop a program in C# find out when was Windows started or shutdown.

Is there a log file that I can read to know Windows start and shutdown times? Or do you have any ideas how to do so?

EDIT :

With the help of Mr. Reed Copsey, the best answer is found under this question.

Community
  • 1
  • 1
YAM
  • 1,362
  • 2
  • 16
  • 30
  • In Windows >= 8 with Fast Boot / Startup enabled all the solutions provided here so far are "wrong", because shutdown = "close all programs, log out the user and hibernate". Environment.TickCount might work, but sometimes it yields negative numbers. – Niklas Peter Oct 06 '16 at 07:17
  • https://msdn.microsoft.com/en-us/library/windows/hardware/jj835779(v=vs.85).aspx – Niklas Peter Oct 06 '16 at 07:48

9 Answers9

15

According to this article you can use WMI to get the last boot date/time.

// define a select query
SelectQuery query =
    new SelectQuery(@"SELECT LastBootUpTime FROM Win32_OperatingSystem
       WHERE Primary='true'");

// create a new management object searcher and pass it
// the select query
ManagementObjectSearcher searcher =
    new ManagementObjectSearcher(query);

// get the datetime value and set the local boot
// time variable to contain that value
foreach(ManagementObject mo in searcher.Get())
{
    dtBootTime =
        ManagementDateTimeConverter.ToDateTime(
            mo.Properties["LastBootUpTime"].Value.ToString());

    // display the start time and date
    txtDate.Text = dtBootTime.ToLongDateString();
    txtTime.Text = dtBootTime.ToLongTimeString();
}
michaelx386
  • 765
  • 8
  • 8
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
6

System.Environment.TickCount has a 24.8 days limitation.
This is because TickCount is a millisecond value contained in a signed 32 bits value.

Windows API exposes these two functions:
GetTickCount - returns a 32 bits value - available from Windows 2000
GetTickCount64 - returns a 64 bits value - available from Vista/Windows Server 2008

You can use GetTickCount64 this way:

using System.Runtime.InteropServices;  

[DllImport("Kernel32.dll")]  
static extern long GetTickCount64();  

DateTime osStartTime = DateTime.Now - new TimeSpan(10000 * GetTickCount64());
Kiquenet
  • 14,494
  • 35
  • 148
  • 243
figolu
  • 1,388
  • 13
  • 6
5

As Reed pointed out you could access the Event Logs and see when they were created. AFAIK there are no specific event entries for system startup/shutdown, but you could look for services that are usually started/stopped with Windows. Though using this approach means it won't be 100% accurate, say if it crashes or it's manually started/stopped/restarted. One event I consider is the most accurate is EventLog service start/stop event.

if (EventLog.Exists("System"))
{
    var log = new EventLog("System", Environment.MachineName, "EventLog");

    var entries = new EventLogEntry[log.Entries.Count];
    log.Entries.CopyTo(entries, 0);

    var startupTimes = entries.Where(x => x.InstanceId == 2147489653).Select(x => x.TimeGenerated);
    var shutdownTimes = entries.Where(x => x.InstanceId == 2147489654).Select(x => x.TimeGenerated);
}

Edit

Turns out there was a shutdown event. You can replace the Linq to get it:

var shutdownEvents = entries.Where(x => x.InstanceId == 2147484722);
Matt
  • 91
  • 4
4

You can use the classes in System.Diagnostics.Eventing.Reader to access the system Event Logs.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • 2
    Would you please give me more details of how to read desired data then? Thanks – YAM Sep 13 '11 at 19:37
  • @Yas_EG: It's a bit too long for a simple query here - but there are good samples on MSDN showing how to read and query data using these classes. See: http://msdn.microsoft.com/en-us/library/bb671200(v=VS.90).aspx and http://msdn.microsoft.com/en-us/library/bb671197(v=VS.90).aspx – Reed Copsey Sep 13 '11 at 19:46
  • 1
    I'm curious why the downvotes - This is the only working solution that lets you get historical startup/shutdown times that's been listed thus far.... – Reed Copsey Sep 13 '11 at 19:47
  • @Yas_EG: Here's a simpler example:http://stackoverflow.com/questions/6185608/getting-server-restart-count-in-a-day-using-c It shows a console app that will read shutdown events... – Reed Copsey Sep 13 '11 at 19:57
  • That's exactly what I wanted. In the link you sent, 'USER32' is used to read system shutdown and restart events. I'd be grateful if you help me know the system event source that records system start up. – YAM Sep 13 '11 at 20:41
  • 1
    @Yag_EG: If you look for Event ID 6005, you'll see when the Event Logging Service starts. This happens immediately on boot... – Reed Copsey Sep 13 '11 at 20:49
4

You could use the "System Up Time" performance counter to get the start time of the system:

 PerformanceCounter systemUpTime = new PerformanceCounter("System", "System Up Time");

 systemUpTime.NextValue();
 TimeSpan upTimeSpan = TimeSpan.FromSeconds(systemUpTime.NextValue());
 Console.Out.WriteLine(DateTime.Now.Subtract(upTimeSpan).ToShortTimeString());

Hope, this helps.

Hans
  • 12,902
  • 2
  • 57
  • 60
  • 2
    This one takes current datetime and substracts the period of time windows has been runing. If you are "hibernateing" your machine, result won't be valid. – adrian.krzysztofek Sep 26 '13 at 09:28
3

Last Restart time can be found using this piece of code

static void Main(string[] args)
    {          
        TimeSpan t = TimeSpan.FromMilliseconds(System.Environment.TickCount);
        Console.WriteLine( DateTime.Now.Subtract(t));          
    }
Sravan
  • 596
  • 1
  • 9
  • 19
1

Here is a collected code that can be executed, including the code above.

This was written in .NET 4.6.1, which is usually executed.

You can choose any method :

using System;
using System.Linq;
using System.Diagnostics;
using System.Management;

namespace ConsoleEventLogSample1
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args is null) throw new ArgumentNullException(nameof(args));


            // EventLog
            Console.WriteLine($"EventLog = Last shutdown time : " +
                $"{GetSystemLastTimeByEventLog(false):yyyy-MM-dd HH:MM:ss}, " +
                $"Last startup time : {GetSystemLastTimeByEventLog(true):yyyy-MM-dd HH:MM:ss}"); // ms(fff) is not displayed

            // Registry
            Console.WriteLine($"Registry = Last shutdown time : " +
                $"{GetSystemLastShutdownTimeByRegistry():yyyy-MM-dd HH:MM:ss.fff}");

            // WMI
            Console.WriteLine($"WMI = Last startup time : " +
                $"{GetSystemLastStartupTimeByWMI():yyyy-MM-dd HH:MM:ss.fff}");

            Console.ReadLine();
        }

        static DateTime GetSystemLastTimeByEventLog(bool direction)
        {
            // Do not check for presence or not : Items that must exist
            var log = new EventLog("System", Environment.MachineName, "EventLog");

            var entries = new EventLogEntry[log.Entries.Count];
            log.Entries.CopyTo(entries, 0);

            if (direction)
            {
                return entries.Where(x => x.InstanceId == 2147489653).Select(x => x.TimeGenerated).Last();
            }
            else
            {
                return entries.Where(x => x.InstanceId == 2147489654 || x.InstanceId == 2147489656).Select(x => x.TimeGenerated).Last();
            }
        }

        static DateTime GetSystemLastShutdownTimeByRegistry()
        {
            // Do not check for presence or not : Items that must exist
            string sKey = @"System\CurrentControlSet\Control\Windows";
            using (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);
            }
        }

        static DateTime GetSystemLastStartupTimeByWMI()
        {
            // Do not check for presence or not : Items that must exist
            SelectQuery query = new SelectQuery(@"select LastBootUpTime from Win32_OperatingSystem where Primary='true'");

            ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
            DateTime lastdt = new DateTime();

            foreach (ManagementObject mo in searcher.Get())
            {
                lastdt = ManagementDateTimeConverter.ToDateTime(mo.Properties["LastBootUpTime"].Value.ToString());
                break;
            }

            return lastdt;
        }

    }
}
Tapegawui
  • 11
  • 4
1

Some more options:

Community
  • 1
  • 1
Yahia
  • 69,653
  • 9
  • 115
  • 144
0

In .NET 5 and .NET Core 3, you can use the Environment.TickCount64 property.

var t = TimeSpan.FromMilliseconds(Environment.TickCount64);
var lastBootTime = DateTime.UtcNow.Subtract(t);
Console.WriteLine(lastBootTime);
l33t
  • 18,692
  • 16
  • 103
  • 180