I have a WMI Query, using ManagementObjectSearcher.
Usually, this works fine, but on some machines, it is hanging / never returning. I've tried setting a timeout on the query, but it appears to make no difference.
This is my code:
using (var query = new ManagementObjectSearcher("SELECT IDProcess, PercentProcessorTime, WorkingSet FROM Win32_PerfFormattedData_PerfProc_Process"))
{
try
{
query.Options.Timeout = new TimeSpan(0, 0, 10);
query.Options.ReturnImmediately = false;
Log.Info("Query built");
foreach (ManagementObject obj in query.Get())
{
using (obj)
{
var key = (uint)obj.GetPropertyValue("IDProcess");
Log.Info(key);
processStats[key] = new ulong[] { (ulong)obj.GetPropertyValue("PercentProcessorTime"), (ulong)obj.GetPropertyValue("WorkingSet") };
}
}
}
}
In my log, I see "Query built", and then nothing and the program becomes unresponsive.
I've tried with and without the manual timeout setting.
Recently we've tested WMI queries at "C# command line" and WMI worked as expected, but after rewriting in WPF we faced the same problem as you. After some research i've found that WMI hanging if you operating in STA(Single Threading Apartment mode ) but WPF operating in STA mode, so to perform the task we're using ThreadPool(rewriting to your case):
ThreadPool.QueueUserWorkItem((_) =>
{
using (var query = new ManagementObjectSearcher("SELECT IDProcess, PercentProcessorTime, WorkingSet FROM Win32_PerfFormattedData_PerfProc_Process"))
{
try
{
query.Options.Timeout = new TimeSpan(0, 0, 10);
query.Options.ReturnImmediately = false;
Log.Info("Query built");
foreach (ManagementObject obj in query.Get())
{
using (obj)
{
var key = (uint)obj.GetPropertyValue("IDProcess");
Log.Info(key);
processStats[key] = new ulong[] { (ulong)obj.GetPropertyValue("PercentProcessorTime"), (ulong)obj.GetPropertyValue("WorkingSet") };
}
}
}
catch (SystemException)
{
}
}
});
it should work without the 'using'
var query = new ManagementObjectSearcher("SELECT IDProcess, PercentProcessorTime, WorkingSet FROM Win32_PerfFormattedData_PerfProc_Process");
try
{
query.Options.Timeout = new TimeSpan(0, 0, 10);
query.Options.ReturnImmediately = false;
log.Info("Query built");
foreach (ManagementObject obj in query.Get())
{
using (obj)
{
var key = (uint)obj.GetPropertyValue("IDProcess");
Log.Info(key);
processStats[key] = new ulong[] { (ulong)obj.GetPropertyValue("PercentProcessorTime"), (ulong)obj.GetPropertyValue("WorkingSet") };
}
}
}
Related
Found an issue with Splunk SDK for C# v2.2.3.
When I submit a search that doesn't return any result, execution of my code hangs on enumerating results from SearchResultStream:
using (SearchResultStream stream = await _service.SearchOneShotAsync(searchCommand, 0, new JobArgs { EarliestTime = earliestTime, LatestTime = latestTime }))
{
foreach (var searchresult in stream)
{
result.add(searchresult);
}
}
Also tried to use enumerator directly, but it doesn't help, program hangs on enumerator.MoveNext():
using (SearchResultStream stream = await _service.SearchOneShotAsync(searchCommand, 0, new JobArgs { EarliestTime = earliestTime, LatestTime = latestTime }))
{
var enumerator = stream.GetEnumerator();
while (enumerator.MoveNext())
{
result.Add(enumerator.Current);
}
}
Has anybody faced with the same problem? Are there any workaround?
We use Splunk Enterprise version 6.3.3.
I need to check whether the OS needs activation,
my following code displays a multitude of "channels".
static void Main(string[] args)
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher
(
"root\\CIMV2",
"SELECT
Description,
LicenseIsAddon,
LicenseStatus
FROM SoftwareLicensingProduct
WHERE LicenseIsAddon = False"
);
foreach (ManagementObject queryObj in searcher.Get())
{
if (queryObj["Description"].ToString().ToLower().Contains("operating"))
{
foreach (var item in queryObj.Properties)
{
Console.WriteLine(item.Value);
}
}
}
Console.Write("***done***");
Console.ReadLine();
}
How do i know which one to check in order to determine if i need to activate the OS?
Or is my only way to see, if i have any LicenseStatus = 1 in there? Which of course can be wrong if there is one activated and one not activated OS installed.
Thanks
For the time being i filtered the channels a bit more and concluded, that this is good enough:
private void getOSActivation()
{
try
{
ManagementObjectSearcher LicenseSearcher =
new ManagementObjectSearcher("root\\CIMV2",
"SELECT LicenseStatus,Description FROM SoftwareLicensingProduct");
foreach (ManagementObject LSObj in LicenseSearcher.Get())
{
OStestString = LSObj["Description"].ToString().ToLower();
if (
OStestString.Contains("operating")
&&
// next line is new
(OStestString.Contains("slp") || OStestString.Contains("dm"))
)
{
foreach (var item in LSObj.Properties)
{
OSresults.Add(LSObj["LicenseStatus"].ToString());
}
}
}
}
catch (Exception LSOexception)
{
Console.WriteLine(LSOexception.Message);
}
}
I have a C#.net Windows form Application with SQL Server. My application use in Multiple user by local Network. Now I need to find Hard disk Serial Number which hard disk installed sql server (Note: By Using C#.net Application Data source ).
How can i find Hard disk Serial number throw by application data source?
This might be useful
using System;
using System.Management;
using System.Collections;
namespace WmiControl
{
public class WMI
{
public bool GetDiskSerial(string Computername)
{
try
{
ManagementScope scope = new ManagementScope(#"\\" + Computername + #"\root\cimv2");
scope.Connect();
ArrayList hdCollection;
ManagementObjectSearcher searcher;
if (GetDiskDrive(scope, out hdCollection, out searcher) || GetDiskSerial(scope, hdCollection, ref searcher))
return true;
else
return false;
}
catch (ManagementException)
{
return false;
}
}
private bool GetDiskSerial(ManagementScope scope, ArrayList hdCollection, ref ManagementObjectSearcher searcher)
{
try
{
ObjectQuery query1 = new ObjectQuery("SELECT * FROM Win32_PhysicalMedia");
searcher = new ManagementObjectSearcher(scope, query1);
int i = 0;
string sDiskSerial = "";
foreach (ManagementObject wmi_HD in searcher.Get())
{
// get the hard drive from collection
// using index
if (i < hdCollection.Count)
{
HardDrive hd = (HardDrive)hdCollection[i];
if (wmi_HD["SerialNumber"] == null)
hd.SerialNo = "";
else
hd.SerialNo = wmi_HD["SerialNumber"].ToString();
}
++i;
}
foreach (HardDrive hd in hdCollection)
{
if (!String.IsNullOrEmpty(hd.SerialNo))
{
sDiskSerial = hd.SerialNo;
break;
}
}
return true;
}
catch (Exception)
{
return false;
}
}
private bool GetDiskDrive(ManagementScope scope, out ArrayList hdCollection, out ManagementObjectSearcher searcher)
{
try
{
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_DiskDrive");
hdCollection = new ArrayList();
searcher = new ManagementObjectSearcher(scope, query);
foreach (ManagementObject wmi_HD in searcher.Get())
{
HardDrive hd = new HardDrive();
hd.Model = wmi_HD["Model"].ToString();
hd.Type = wmi_HD["InterfaceType"].ToString();
hdCollection.Add(hd);
return true;
}
return true;
}
catch (Exception)
{
hdCollection = null;
searcher = null;
return false;
}
}
}
class HardDrive
{
private string model = null;
private string type = null;
private string serialNo = null;
public string Model
{
get { return model; }
set { model = value; }
}
public string Type
{
get { return type; }
set { type = value; }
}
public string SerialNo
{
get { return serialNo; }
set { serialNo = value; }
}
}
}
See here for more info
You might want also to study CLR
You'll need to resort to WMI. With the proper privileges on the SQL Server machine, you can get the serial number of the hard-drives on it. See here for an example on retrieving the hard-disk's serial number using WMI.
You'll need to figure out which disk holds SQL Server and how to access the SQL Server machine on your own.
You have to do it in 3 stages:
The connection string of the data source gives you the name of the machine on which SQL Server is installed
You must then query the machine to find out the drive which drive SQL Server is installed on
You can then use the code supplied by others here to get the serial number
I've tracked down a leak to my group enumeration code. I've written a test routine and I'm trying to dispose of everything but still it leaks.
Does anyone see what I'm doing wrong? In my test, I call it 100 times in a row and on my small domain, the memory footprint goes from 32MB to over 150MB.
private void EnumGroups()
{
try
{
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, "domainname.com"))
{
using (PrincipalSearcher srch = new PrincipalSearcher())
{
srch.QueryFilter = new UserPrincipal(context);
// do the search
using (PrincipalSearchResult<Principal> results = srch.FindAll())
{
// enumerate over results
foreach (UserPrincipal up in results)
{
using (PrincipalSearchResult<Principal> groups = up.GetGroups())
{
foreach (GroupPrincipal gp in groups)
gp.Dispose();
}
up.Dispose();
}
}
}
}
}
catch (Exception exc)
{
Trace.WriteLine(exc);
}
}
Execute GetMembers from another temp domain:
dTaskTemporaryDomain = AppDomain.CreateDomain("BUHLO_POBEDIT_ZLO");
var currentAssembly = Assembly.GetExecutingAssembly();
AdsApiHelper = (AdsApiHelper)_adTaskTemporaryDomain.CreateInstanceAndUnwrap(currentAssembly.GetName().FullName, typeof(AdsApiHelper).ToString());
var members = AdsApiHelper.GetMembers(GroupName);
AppDomain.Unload(_adTaskTemporaryDomain)
...
[serializeble]
class AdsApiHelper {
GetMembers(String GroupName){
.....
return groupPrincipal.GetMembers().Select(m=>m.SamAccountName);
}
This is my function for enumerating processes on windows box and calculating percentage of CPU usage for each process but results are not correct.
CPU usage does't add up to 100% but more like to 120% or 130% and I don't know what I'm doing wrong.
It seems like it calculats right CPU usage for varoius apps like firefox, VS2010, office,.. but has problems with System Idle Process.
public List<ProcInfo> GetRunningProcesses()
{
List<ProcInfo> allProcesses = new List<ProcInfo>();
UInt64 currentProcessCpuTime = 0;
UInt64 allProcessCpuTime = 0;
SelectQuery wmiQuery = new SelectQuery("SELECT Name, Description, ProcessId, KernelModeTime, UserModeTime FROM Win32_Process");
ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(connectionScope, wmiQuery);
ManagementObjectCollection moc = oSearcher.Get();
foreach (ManagementObject mo in moc)
{
allProcessCpuTime += (UInt64)mo["KernelModeTime"] + (UInt64)mo["UserModeTime"];
}
foreach (ManagementObject mo in moc)
{
currentProcessCpuTime = (UInt64)mo["KernelModeTime"] + (UInt64)mo["UserModeTime"];
allProcesses.Add(new ProcInfo((string)mo["Name"], (string)mo["Description"], (UInt32)mo["ProcessId"], (currentProcessCpuTime / (double)allProcessCpuTime * 100));
}
return allProcesses;
}
EDIT:
I found that my function is all wrong.
I'm starting a bounty for the best working solution. Solution needs to work for local and remote system and should be fast.
Here is a C# code with performance counters:
public static void DumpProcessesCpu(string machineName)
{
List<PerformanceCounter> counters = new List<PerformanceCounter>();
foreach (Process process in Process.GetProcesses(machineName))
{
PerformanceCounter processorTimeCounter = new PerformanceCounter(
"Process",
"% Processor Time",
process.ProcessName,
machineName);
processorTimeCounter.NextValue();
counters.Add(processorTimeCounter);
}
Thread.Sleep(1000); // 1 second wait, needed to get a sample
foreach (PerformanceCounter processorTimeCounter in counters)
{
Console.WriteLine("Process:{0} CPU% {1}",
processorTimeCounter.InstanceName,
processorTimeCounter.NextValue());
}
}
It's inspired from here: https://learn.microsoft.com/en-us/archive/blogs/bclteam/how-to-read-performance-counters-ryan-byington
You can't really be faster than this, the reason why is explained in the article. Basically, you'll have to read the value twice to get it right, so you need to wait between samples.
However, depending on what you want to do, for example, suppose you want to write a "remote task manager", you can code all this in a background task (thread) and regularly update the values so the end-user will not really see the delay between samples.
var mos = new ManagementObjectSearcher("SELECT * FROM Win32_PerfRawData_PerfProc_Process");
var run1 = mos.Get().Cast<ManagementObject>().ToDictionary(mo => mo.Properties["Name"].Value, mo => (ulong)mo.Properties["PercentProcessorTime"].Value);
Thread.Sleep(570); // can be an arbitrary number
var run2 = mos.Get().Cast<ManagementObject>().ToDictionary(mo => mo.Properties["Name"].Value, mo => (ulong)mo.Properties["PercentProcessorTime"].Value);
var total = run2["_Total"] - run1["_Total"];
foreach (var kvp in run1)
{
var proc = kvp.Key;
var p1 = kvp.Value;
if (run2.ContainsKey(proc))
{
var p2 = run2[proc];
Console.WriteLine("{0}: {1:P}", proc, (double)(p2 - p1) / total);
}
}
Here is a C# block of code tested and validated and thanks to fejesjoco, I used his code and made the test to get it to work.
public class CPUUtilizationTests
{
[Test]
public void TestPercentProcessorTime()
{
Assert.That(PercentProcessorTime("Idle"), Is.Not.GreaterThan(100.0));
}
public float PercentProcessorTime(string processName)
{
var mos = new ManagementObjectSearcher("SELECT * FROM Win32_PerfRawData_PerfProc_Process");
var run1 = mos.Get().Cast<ManagementObject>().ToDictionary(mo => mo.Properties["Name"].Value, mo => mo);
System.Threading.Thread.Sleep(1000); // can be an arbitrary number
var run2 = mos.Get().Cast<ManagementObject>().ToDictionary(mo => mo.Properties["Name"].Value, mo => mo);
if (!run2.ContainsKey(processName)) throw new Exception(string.Format("Process not found: {0}", processName));
string percentageProcessorTime = "PercentProcessorTime";
string total = "_Total";
ulong percentageDiff = (ulong)run2[processName][percentageProcessorTime] - (ulong)run1[processName][percentageProcessorTime];
ulong totalDiff = (ulong)run2[total][percentageProcessorTime] - (ulong)run1[total][percentageProcessorTime];
return ((float)percentageDiff / (float)totalDiff)*100.0f;
}
}