Skip to content
Snippets Groups Projects
SystemChecks.cs 8.95 KiB
Newer Older
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management;
using NLog;

{
    public static class SystemChecks
    {
        private static readonly Logger Log = LogManager.GetCurrentClassLogger();

        /// <summary>
        /// Get the available physical memory in MB.
        /// </summary>
        /// <returns>Available physical memory in MB or -1 in case of an error.</returns>
        public static long GetFreeMemory() {
            try {
                var searcher =
                    new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem");
                foreach (var mo in searcher.Get()) {
                    var queryObj = (ManagementObject)mo;
                    return Convert.ToInt64(queryObj["FreePhysicalMemory"]) / 1024;
                }
            }
            catch (Exception ex) {
                Log.Trace("Error in GetFreeMemory: {0}", ex.Message);
            return -1;
        }

        /// <summary>
        /// Get the CPU usage in percent over all cores.
        /// </summary>
        /// <returns>CPU usage in percent or -1 if an error occured.</returns>
        public static int GetCpuUsage() {
Niko Ehrenfeuchter's avatar
Niko Ehrenfeuchter committed
            // TODO: fix bug #36
            return 0;
                Log.Trace("Querying WMI for CPU load...");
                var watch = Stopwatch.StartNew();
                var queryString = "SELECT Name, PercentProcessorTime " +
                            "FROM Win32_PerfFormattedData_PerfOS_Processor";
                var opts = new EnumerationOptions {
                    Timeout = new TimeSpan(0, 0, 10),
                    ReturnImmediately = false,
                var searcher = new ManagementObjectSearcher("", queryString, opts);
                Int32 usageInt32 = -1;

                var managementObjects = searcher.Get();
                if (managementObjects.Count == 0) {
                    Log.Error("No objects returned from WMI!");
                    watch.Stop();
                    Log.Debug("WMI query took {0} ms.", watch.ElapsedMilliseconds);
                    return -1;
                }
                Log.Debug("WMI query returned {0} objects.", managementObjects.Count);
                foreach (var mo in managementObjects) {
                    var obj = (ManagementObject)mo;
                    var usage = obj["PercentProcessorTime"];
                    var name = obj["Name"];
                    
                    usageInt32 = Convert.ToInt32(usage);
                    Log.Debug("CPU usage {1}: {0}", usageInt32, name);
                watch.Stop();
                Log.Debug("WMI query took {0} ms.", watch.ElapsedMilliseconds);
                return usageInt32;
                var cpuTimes = searcher.Get()
                    .Cast<ManagementObject>()
                    .Select(mo => new {
                            Name = mo["Name"],
                            Usage = mo["PercentProcessorTime"]
                        }
                    )
                    .ToList();
                if (cpuTimes.Count == 0)
                    return -1;

                Log.Trace("WMI query returned {0} objects.", cpuTimes.Count);
                // The '_Total' value represents the average usage across all cores,
                // and is the best representation of overall CPU usage
                var query = cpuTimes.Where(x => x.Name.ToString() == "_Total").Select(x => x.Usage);
                var cpuUsage = query.SingleOrDefault();
                usageInt32 = Convert.ToInt32(cpuUsage);
                Log.Trace("CPU usage: {0}", usageInt32);
                return usageInt32;
                Log.Trace("Error in GetCpuUsage: {0}", ex.Message);
            Log.Trace("Failed querying CPU usage!");
        /// <summary>
        /// Validate the WMI query methods work correctly and create a summary or warning message.
        /// </summary>
        /// <returns>A summary with current readings from WMI or a warning message.</returns>
        public static string WmiSummary() {
            var failed = new List<string>();
            var load = GetCpuUsage();
            var free = GetFreeMemory();
            var summary = $"CPU load: {load}\n" +
                          $"Free system memory: {Conv.MegabytesToString(free)}\n";
            Log.Warn(summary);
            if (load == -1) {
                failed.Add("CPU load");
            }
            if (free == -1) {
                failed.Add("free RAM");
            }

            if (failed.Count > 0) {
                summary = "*******************************************************\n" +
                          "WARNING: Checking system parameters via WMI failed for:\n";
                foreach (var property in failed) {
                    summary += $" - {property}\n";
                }

                summary += "\n" +
                           "-------------------------------------------------------\n" +
                           "Limits configured for these properties will be IGNORED!\n" +
                           "-------------------------------------------------------\n\n";
                Log.Error(summary);
            }

            return summary;
        }

        /// Get the free space of a drive in bytes.
        /// </summary>
        /// /// <param name="drive">The drive name, e.g. "c:".</param>
        /// <returns>Free space of a drive in bytes, zero if an error occured.</returns>
        public static long GetFreeDriveSpace(string drive) {
            try {
                var dInfo = new DriveInfo(drive);
                // log this as an error which then also gets sent via email (if configured) and
                // let the rate-limiter take care of not flooding the admin with mails:
                Log.Error("Error in GetFreeDriveSpace({0}): {1}", drive, ex.Message);
        /// <summary>
        /// Check all configured disks for their free space and send a notification
        /// if necessary (depending on the configured delta time).
        /// </summary>
        public static string CheckFreeDiskSpace(List<Serializables.DriveToCheck> drives) {
            var msg = "";
            foreach (var driveToCheck in drives) {
                var freeSpace = GetFreeDriveSpace(driveToCheck.DriveName);
                if (freeSpace >= driveToCheck.SpaceThreshold * Conv.GigaBytes) {
                    Log.Trace("Drive [{0}] free space: {1}, above threshold ({2})",
                        driveToCheck.DriveName, Conv.BytesToString(freeSpace),
                        Conv.GigabytesToString(driveToCheck.SpaceThreshold));
                msg += $"Drive [{driveToCheck.DriveName}] " +
                       $"free space: {Conv.BytesToString(freeSpace)} " +
                       $"(threshold: {Conv.GigabytesToString(driveToCheck.SpaceThreshold)})\n";
        /// <summary>
        /// Compares all processes against the ProcessNames in the BlacklistedProcesses list.
        /// </summary>
        /// <returns>Returns the name of the first matching process, an empty string otherwise.</returns>
        public static string CheckForBlacklistedProcesses(List<string> processNames) {
            foreach (var running in Process.GetProcesses()) {
                try {
                    foreach (var blacklisted in processNames) {
                        if (running.ProcessName.ToLower().Equals(blacklisted)) {
                            return blacklisted;
                        }
                    }
                }
                catch (Exception ex) {
                    Log.Error("Error in checkProcesses(): {0}", ex.Message);
        /// <summary>
        /// Check if a user is currently logged into Windows.
        /// 
        /// WARNING: this DOES NOT ACCOUNT for users logged in via RDP!!
        /// </summary>
        /// See https://stackoverflow.com/questions/5218778/ for the RDP problem.
        public static bool NoUserIsLoggedOn() {
            var username = "";
            try {
                var searcher = new ManagementObjectSearcher("SELECT UserName " +
                                                            "FROM Win32_ComputerSystem");
                var collection = searcher.Get();
                username = (string)collection.Cast<ManagementBaseObject>().First()["UserName"];
            }
            catch (Exception ex) {
                Log.Error("Error in getCurrentUsername(): {0}", ex.Message);