Newer
Older
using System;
using System.Collections.Generic;
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() {
Log.Trace("Querying WMI for CPU load...");
var watch = Stopwatch.StartNew();
var queryString = "SELECT Name, PercentProcessorTime " +
"FROM Win32_PerfFormattedData_PerfOS_Processor";
Timeout = new TimeSpan(0, 0, 10),
ReturnImmediately = false,
var searcher = new ManagementObjectSearcher("", queryString, opts);
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);
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;
}
catch (Exception ex) {
Log.Trace("Error in GetCpuUsage: {0}", ex.Message);
Log.Trace("Failed querying CPU usage!");
return -1;
}
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/// <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;
}
/// <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);
return dInfo.TotalFreeSpace;
}
catch (Exception ex) {
// 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);
return 0;
}
/// <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));
continue;
msg += $"Drive [{driveToCheck.DriveName}] " +
$"free space: {Conv.BytesToString(freeSpace)} " +
$"(threshold: {Conv.GigabytesToString(driveToCheck.SpaceThreshold)})\n";
}
return msg;
}
/// <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);
return "";
}
/// <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);
return username == "";
}
}
}