Getting culture (locale) independent WMI property - c#

I need to get the power settings for a machine using WMI. I am using the MSDN Link to get the required values. I need specific values from the list returned. The following C# code does this:
string NamespacePath = #"root\cimv2\power";
string powerPlanClass = "Win32_powerplan";
string powerSettingClass = "Win32_PowerSettingDataIndex";
ManagementClass powerPlanManagementClass = new ManagementClass(NamespacePath + ":" + powerPlanClass);
ManagementObject powerPlanManagementObject = null;
foreach (ManagementObject managementObject in powerPlanManagementClass.GetInstances())
{
if (managementObject["IsActive"] != null && Boolean.Parse(managementObject["IsActive"].ToString()))
{
powerPlanManagementObject = managementObject;
}
}
Dictionary<string, PowerSetting> powerItems = new Dictionary<string, PowerSetting>()
{
{"AC", new PowerSetting() },
{"DC", new PowerSetting() }
};
foreach (ManagementObject oObject in powerPlanManagementObject.GetRelated(powerSettingClass))
{
var instanceId = oObject["instanceId"];
string[] powerSourceSettings = instanceId.ToString().Split(new string[] { #"\" }, StringSplitOptions.RemoveEmptyEntries);
var powerSourceType = powerSourceSettings[2];
ManagementObjectCollection managementObjects = oObject.GetRelated("Win32_PowerSetting");
var elementName = string.Empty;
foreach (var managementObject in managementObjects)
{
elementName = managementObject["ElementName"].ToString();
}
var indexValue = uint.Parse(oObject["settingindexvalue"].ToString());
if (elementName.Equals("Hibernate after",StringComparison.OrdinalIgnoreCase))
{
if (powerSourceType.Equals("AC", StringComparison.Ordinal))
{
powerItems["AC"].HibernateAfter = indexValue;
}
}
}
Note the match to the string "Hibernate after". This works on a machine with locale en-us but does not work with a different locale. Is there any other way to get the WMI property independent of the machine's locale?

Probably you can use GUID in the InstanceID of Win32_PowerSetting class instead of ElementName. In my machine, it is Microsoft:PowerSetting\{9d7815a6-7ee4-497e-8888-515a05f02364}. Although I couldn't find official document, this GUID, 9d7815a6-7ee4-497e-8888-515a05f02364 seems to be common for some Windows versions and locales as the identifier for "hibernate after" or "hibernate idle".

Related

Get Parent property of network adapter device from c#

I need to get the Parent property of network adapter device from c# program
Please find the image here
Tried below code but the property "Parent" is not available
List mappingIpDeviceIds = new List();
Console.WriteLine("Reading Id and IP address...");
ManagementObjectSearcher adapters = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapter WHERE NetConnectionStatus = 2");
foreach (ManagementObject item in adapters.Get())
{
foreach (ManagementObject setting in item.GetRelated("Win32_NetworkAdapterConfiguration"))
{
var relationships = setting.GetRelationships();
var name = setting["Caption"].ToString();
string[] defaultIPGateway = (string[])setting.GetPropertyValue("DefaultIPGateway");
string[] compterips = (string[])setting.GetPropertyValue("IPAddress");
string dhcpserver = (string)setting.GetPropertyValue("DHCPServer");
foreach (ManagementObject win32PnPEntity in item.GetRelated("Win32_PnPEntity"))
{
var x = win32PnPEntity.Properties;
foreach (var prop in x)
{
Console.WriteLine("::: PROPERTY NAME ::: " + prop.Name);
Console.WriteLine("::: PROPERTY VALUE ::: " + prop.Value);
}
}
MappingIpDeviceId mappingIpDeviceId = new MappingIpDeviceId();
string deviceid = (string)item.GetPropertyValue("PNPDeviceID");
string deviceid1 = (string)item.GetPropertyValue("ProductName");
string[] devicenames = deviceid.Split(new Char[] { '\\' });
foreach (string dn in devicenames)
{
mappingIpDeviceId.OWLIP = dhcpserver;
mappingIpDeviceId.ComputerIP = compterips[0];
mappingIpDeviceId.DeviceId = dn;
mappingIpDeviceIds.Add(mappingIpDeviceId);
}
}
}
There are two ways you can refer to:
Using PowerShell command Get-PnpDeviceProperty: Get-PnpDeviceProperty -KeyName 'DEVPKEY_Device_Parent' -InstanceId 'xxxxxxxxxxxxxxxx'
Use CM_Get_Parent. "Determining the Parent of a Device".

Why is PropertyDataCollection object persisting multiple records to database

I have a utility that reads the status of MicrosoftBizTalk Server resources .. specifically the ReceiveLocation component. My problem is that the program is submitting multiple entries of each item i.e each item in the data returned is being multiplied by 25 such that instead of persisting only 5 rows the data being persisted is 125. So for example instead of having just 1 row for my first row returned i have 25.
This is my program :
public List<BizTalk> GetBizTalkServicesStatistics()
{
List<BizTalk> model = new List<BizTalk>();
try
{
//Create the WMI search object.
ManagementObjectSearcher Searcher = new ManagementObjectSearcher();
ConnectionOptions options = new ConnectionOptions
{
Username = "+username+",
Password = "+password+",
Authority = "+domain+"
};
var server = "+server+";
// create the scope node so we can set the WMI root node correctly.
ManagementScope Scope = new ManagementScope("\\\\" + server + "\\root\\MicrosoftBizTalkServer", options);
Searcher.Scope = Scope;
// Build a Query to enumerate the MSBTS_ReceiveLocation instances if an argument
// is supplied use it to select only the matching RL.
//if (args.Length == 0)
SelectQuery Query = new SelectQuery();
Query.QueryString = "SELECT * FROM MSBTS_ReceiveLocation";
// else
//Query.QueryString = "SELECT * FROM MSBTS_ReceiveLocation WHERE Name = '" + args[0] + "'";
// Set the query for the searcher.
Searcher.Query = Query;
// Execute the query and determine if any results were obtained.
ManagementObjectCollection QueryCol = Searcher.Get();
// Use a bool to tell if we enter the for loop
// below because Count property is not supported
bool ReceiveLocationFound = false;
// Enumerate all properties.
foreach (ManagementBaseObject envVar in QueryCol)
{
// There is at least one Receive Location
ReceiveLocationFound = true;
PropertyDataCollection envVarProperties = envVar.Properties;
foreach (PropertyData envVarProperty in envVarProperties)
{
BizTalk bizTalk = new BizTalk();
bizTalk.Name = Convert.ToString(envVar["Name"]);
bizTalk.TransportType = Convert.ToString(envVar["AdapterName"]);
bizTalk.Uri = Convert.ToString(envVar["InboundTransportURL"]);
bizTalk.Status = Convert.ToString(envVar["Name"]);
bizTalk.ReceiveHandler = Convert.ToString(envVar["HostName"]);
bizTalk.ReceivePort = Convert.ToString(envVar["ReceivePortName"]);
bizTalk.RunDate = DateTime.Now;
bizTalk.ApplicationId = 24;
bizTalk.ServerId = 8;
bizTalk.InstanceName = "FBCZOP";
model.Add(bizTalk);
}
}
if (!ReceiveLocationFound)
{
Console.WriteLine("No receive locations found matching the specified name.");
}
}
catch (Exception excep)
{
ExceptionLogger.SendErrorToText(excep);
}
return model;
}
Save Function
public void SaveStatistics(BizTalk entity)
{
List<BizTalk> ServerInfo = new List<BizTalk>();
ServerInfo = GetBizTalkServicesStatistics();
foreach (var di in ServerInfo)
{
entity.RunDate = di.RunDate;
entity.Name = di.Name;
entity.Status = di.Status;
entity.Uri = di.Uri;
entity.InstanceName = di.InstanceName;
entity.ReceivePort = di.ReceivePort;
entity.TransportType= di.TransportType;
entity.RunDate = DateTime.Now;
entity.ReceiveHandler = di.ReceiveHandler;
entity.ServerId = entity.ServerId;
entity.ApplicationId = entity.ApplicationId;
appEntities.BizTalk.Add(entity);
appEntities.SaveChanges();
}
}
When i step through the code variable envVarProperties shows record count as 125 under envVarProperties << ResultsView :
Link 1
whilst QueryCol variable shows count of 5 :
Link 2
It looks like you're iterating an extra time in your GetBizTalkServicesStatistics() method.
Remove the foreach loop that starts with foreach (PropertyData envVarProperty in envVarProperties). This is looping through each property the object has (All 25 properties) for each instance (5 instances)... 25 * 5 = 125 values you are retrieving. You only want to iterate through your instances and pull the properties you want. That way you end up with 5 objects in your model object.
I'd suggest maybe something like this (untested because I don't have BizTalk)
public List<BizTalk> GetBizTalkServicesStatistics()
{
List<BizTalk> model = new List<BizTalk>();
try
{
//Create the WMI search object.
ConnectionOptions options = new ConnectionOptions
{
Username = "+username+",
Password = "+password+",
Authority = "+domain+"
};
var server = "+server+";
// create the scope node so we can set the WMI root node correctly.
ManagementScope Scope = new ManagementScope("\\\\" + server + "\\root\\MicrosoftBizTalkServer", options);
ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Scope, new ObjectQuery("SELECT * FROM MSBTS_ReceiveLocation"));
// Enumerate all properties.
foreach (ManagementObject instance in Searcher.Get())
{
{
BizTalk bizTalk = new BizTalk();
bizTalk.Name = instance.Properties["Name"]?.Value?.ToString();
bizTalk.TransportType = instance.Properties["AdapterName"]?.Value?.ToString();
bizTalk.Uri = instance.Properties["InboundTransportURL"]?.Value?.ToString();
bizTalk.Status = instance.Properties["Name"]?.Value?.ToString();
bizTalk.ReceiveHandler = instance.Properties["HostName"]?.Value?.ToString();
bizTalk.ReceivePort = instance.Properties["ReceivePortName"]?.Value?.ToString();
bizTalk.RunDate = DateTime.Now;
bizTalk.ApplicationId = 24;
bizTalk.ServerId = 8;
bizTalk.InstanceName = "FBCZOP";
model.Add(bizTalk);
}
}
// Determine
if (model.Count == 0)
{
Console.WriteLine("No receive locations found matching the specified name.");
}
}
catch (Exception excep)
{
ExceptionLogger.SendErrorToText(excep);
}
return model;
}
Also, this can be simplified more if you remove the connectionoptions (unless you are hard coding credentials which is highly advised against). If you are just using the identity of the executing user, that data is not needed.
-Paul
You are adding the same entity 25 times and overwrite its properties by reference. You need to initialize a new entity inside your loop:
foreach (var di in ServerInfo)
{
var entity = new BizTalk();
entity.RunDate = di.RunDate;
entity.Name = di.Name;
entity.Status = di.Status;
entity.Uri = di.Uri;
entity.InstanceName = di.InstanceName;
entity.ReceivePort = di.ReceivePort;
entity.TransportType= di.TransportType;
entity.RunDate = DateTime.Now;
entity.ReceiveHandler = di.ReceiveHandler;
entity.ServerId = entity.ServerId;
entity.ApplicationId = entity.ApplicationId;
appEntities.BizTalk.Add(entity);
appEn.SaveChanges();
}
}
As you don't show the code where "SaveStatistics" is called it's not sure this will fix your complete problem, but it's at least one method that does not do what you expect it to do.

Use "arp -a" to retreive MAC address of corresponding IP Adress

I was trying to convert the MAC address of my phone to it's IP address.
var arpStream = ExecuteCommandLine("arp", "-a");
List<string> result = new List<string>();
while (!arpStream.EndOfStream)
{
var line = arpStream.ReadLine().Trim();
result.Add(line);
}
Using the above code, I store it in a list in the following form:
192.168.137.1 2e-bb-58-0a-2f-34 dynamic
192.168.137.44 a8-3e-0e-61-3f-db dynamic
192.168.137.91 d4-63-c6-b2-ac-38 dynamic
224.0.0.22 01-00-5e-00-00-16 static
224.0.0.252 01-00-5e-00-00-fc static
What I can't figure out is, how to retrieve a specific IP for the given MAC.
Assume that my phone is the device with the physical address: a8-3e-0e-61-3f-db, how can I store it's IP as a string somewhere?
I'm assuming you've got the list of strings somehow (ExecuteCommandLine method) and want to be able to filter it based on arp value. Regex can be an option then:
void Main()
{
// just setting it up for testing
List<string> result = new List<string>();
result.Add("192.168.137.1 2e-bb-58-0a-2f-34 dynamic");
result.Add("192.168.137.44 a8-3e-0e-61-3f-db dynamic");
result.Add("224.0.0.22 01-00-5e-00-00-16 static");
result.Add("224.0.0.22 01-00-5e-00-00-16 static");
result.Add("192.168.137.91 d4-63-c6-b2-ac-38 dynamic");
result.Add("224.0.0.22 01-00-5e-00-00-16 static");
result.Add("224.0.0.252 01-00-5e-00-00-fc static");
// this is the part you want
ConcurrentDictionary<string,string> arps = new ConcurrentDictionary<string, string>();
foreach (var s in result)
{
var matches = Regex.Match(s, #"((?:\d+\.?){4})\s+((?:[0-9a-f]{2}-?){6}).*");
arps.TryAdd(matches.Groups[2].Value, matches.Groups[1].Value);
}
Console.WriteLine(arps["01-00-5e-00-00-16"]);
}
note: opting for dictionary here has benefits as well as drawbacks.
you will get O(1) element access times, but you can't have duplicate MAC addresses there. Without knowing your specific use case it's a bit hard to say whether this tradeoff will apply to you, I'm just pointing this out as an option.
You can create a model class that will store the IP information like :
public class DeviceIPAddress
{
public string IPv4 { get; set; }
public string MAC { get; set; }
public string IPType { get; set; }
}
Now, we can use this model to parse the provided list, in which will make it easier for us to handle :
var ips = new List<DeviceIPAddress>();
foreach (var ip in result)
{
var info = ip.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
ips.Add(new DeviceIPAddress { IPv4 = info[0].Trim(), MAC = info[1].Trim(), IPType = info[2].Trim() });
}
now using the ips list, we can manage the received data easily :
var getIP = ips.First(x => x.MAC.Equals("a8-3e-0e-61-3f-db", StringComparison.InvariantCultureIgnoreCase));
// call getIP.IPv4 will to get the IP 192.168.137.44
String s = "";
for (int i = 3; i < result.Count(); i++)
{
s = Convert.ToString(result[i]);
if (s.Contains(macAddress))
{
break;
}
}
char[] ip = new char[15];
StringBuilder ipaddr = new StringBuilder();
for (int i = 0; s[i].CompareTo(' ') != 0; i++)
{
ipaddr.Append(s[i]);
}
return ipaddr;
I used each entry in the result list as a string and looked for my MAC as a substring inside all of the entries.
You can use a Dictionary data structure in C# to hold key-value pair information in your case it is Ipaddress-Macaddress information
Usage
var macofIpaddress = dict["192.168.137.1"];
Code
string output = "";
var proc = new ProcessStartInfo("cmd.exe", "/c arp -a")
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
WorkingDirectory = #"C:\Windows\System32\"
};
Process p = Process.Start(proc);
p.OutputDataReceived += (sender, args1) => { output += args1.Data + Environment.NewLine; };
p.BeginOutputReadLine();
p.WaitForExit();
var dict = new Dictionary<string, string>();
var lines = output.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach(var line in lines)
{
if (line.Contains("static") || line.Contains("dynamic"))
{
var elements = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
var ipAdd = elements[0].Trim();
var macAdd = elements[1].Trim();
dict.Add(ipAdd,macAdd);
}
}
Output:

Foreach loop Cannot convert char to System.Management.ManagementObject?

I have a foreach loop that loops through all WMI services which only looks for certain services that contains specific key words to include and exclude. Therefore you can stop certain services that contains the included and excluded words. Unfortunately I'm receiving this error on the foreach loop that states Cannot convert type 'char' to 'System.Management.ManagementObject'. Hopefully you guys know. Thanks for the help.
public static void Test()
{
string include = "SQL";
string exclude = "EXPRESS, Writer";
string[] includeArray = include.Split(',');
string[] excludeArray = exclude.Split(',');
ConnectionOptions options = new ConnectionOptions();
//Scope that will connect to the default root for WMI
ManagementScope theScope = new ManagementScope(#"root\cimv2");
//Path created to the services with the default options
ObjectGetOptions option = new ObjectGetOptions(null, TimeSpan.MaxValue, true);
ManagementPath spoolerPath = new ManagementPath("Win32_Service");
ManagementClass servicesManager = new ManagementClass(theScope, spoolerPath, option);
using (ManagementObjectCollection services = servicesManager.GetInstances())
{
foreach (ManagementObject item in services.ToString().Where(x => includeArray.ToList().Any(a => x.ToString().Contains(a)) && !excludeArray.Any(a => x.ToString().Contains(a))))
{
if (item["Started"].Equals(true))
{
item.InvokeMethod("StopService", null);
}
}
}
}
You can't use Linq on WMI objects like that.
What you can do is loop over the services and check the name: note also I removed the extra space in the exclude variable.
void Main()
{
string include = "SQL";
string exclude = "EXPRESS,Writer";
string[] includeArray = include.Split(',');
string[] excludeArray = exclude.Split(',');
ConnectionOptions options = new ConnectionOptions();
//Scope that will connect to the default root for WMI
ManagementScope theScope = new ManagementScope(#"root\cimv2");
//Path created to the services with the default options
ObjectGetOptions option = new ObjectGetOptions(null, TimeSpan.MaxValue, true);
ManagementPath spoolerPath = new ManagementPath("Win32_Service");
ManagementClass servicesManager = new ManagementClass(theScope, spoolerPath, option);
using (ManagementObjectCollection services = servicesManager.GetInstances())
{
foreach (ManagementObject item in services)
{
var serviceName = item["Name"];
if (includeArray.Any(a => serviceName.ToString().Contains(a)) && !excludeArray.Any(a => serviceName.ToString().Contains(a)))
{
if (item["Started"].Equals(true))
{
item.InvokeMethod("StopService", null);
}
}
}
}
}
If you want to work with Collections so you can use Linq easily, you can user ORMi
var list = helper.Query("select * from Win32_Service").ToList().Where(p => p.Contains("reserverWord"));

Obtaining raw property value with .NET DirectoryServices

Does anyone know if it's possible to get value of any LDAP object's property X? It seems like that .NET or ADSI removes stuff it cannot handle (de.Properties.Values.Count == de.Properties.PropertyNames.Count > de.Properties.Values.props.valueTable.Count).
binddn.Text = "cn=admin,o=system";
bindpass.Password = "XXXXX";
server.Text = "10.X.X.X";
basedn.Text = "cn=server,o=system";
StringBuilder basepath = new StringBuilder("LDAP://");
basepath.Append(server.Text).Append("/").Append(basedn.Text);
DirectoryEntry myDirectoryEntry = new DirectoryEntry(basepath.ToString());
myDirectoryEntry.Username = binddn.Text;
myDirectoryEntry.Password = bindpass.Password;
myDirectoryEntry.AuthenticationType = AuthenticationTypes.ServerBind;
foreach (string key in myDirectoryEntry.Properties.PropertyNames)
{
object val = myDirectoryEntry.Properties[key].Value;
}
This crashes on networkAddress property which is binary field ( http://ldapwiki.willeke.com/wiki/Ldapsearch%20Networkaddress ).

Categories

Resources