WQL Like statement & syntax - c#

I've seen atleast two other questions regarding WMI but none had an answer to my question, so here it is;
I was experimenting with the WMI interface in my code. Basically this is what i have right now and it works. But it seems to me i could write it more efficiently:
public bool GetUsbStateById(string id)
{
bool returnValue = false;
try
{
ObjectQuery query = new ObjectQuery();
query.QueryString = string.Format("Select * From Win32_PnPDevice");
ManagementObjectSearcher mySearcher = new ManagementObjectSearcher(query);
List<ManagementObject> results = (from ManagementObject mo in mySearcher.Get().AsParallel()
where mo["SystemElement"].ToString().ToUpper().Contains(id.ToUpper())
select mo).ToList();
if (results.Count > 0)
returnValue = true;
}
catch (Exception ex)
{
// TODO: implement logging
}
return returnValue;
}
So what happens here is that i get a list of ManagementObjects from the ManagementObjectSearcher. This works fine and also returns the exact results as i expect it to work.
But it seems redundant to me. Because, first i get the whole list, and then filter it. But because it uses WQL to fill the list, i assumed that i could implement something like this:
query.QueryString = string.Format("Select * From Win32_PnPDevice where SystemElement Like '%{0}%'",id);
this keeps throwing an exception that the query is not correct.
so i tried this instead:
query.QueryString = string.Format("Select SystemElement From Win32_PnPDevice);
This works as well, so next i tried Win32_PnPDevice.SystemElement, but this didn't work either.
any examples i looked at on the internet showed something like this
Select * From Win32_Service
Where Name Like "%SQL%"
but c# can't parse the double quotes that surround the %SQL% statement there, using an the \ escape character yielded no results either.
To test my code and the code posted below i used the WMI Code Creator from Microsoft

if you want to run like query in WMI then you can use below example:
using System;
using System.Management;
using System.Windows.Forms;
namespace WMISample
{
public class MyWMIQuery
{
public static void Main()
{
try
{
string strSearchText="win";
string strSearchQuery=string.Format("SELECT * FROM Win32_Service where Name like '%{0}%'",strSearchText);
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2",strSearchQuery );
foreach (ManagementObject queryObj in searcher.Get())
{
Console.WriteLine("-----------------------------------");
Console.WriteLine("Win32_Service instance");
Console.WriteLine("-----------------------------------");
Console.WriteLine("Name: {0}", queryObj["Name"]);
}
}
catch (ManagementException e)
{
MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
}
}
}
}
But you can not apply like query on Win32_PNPDevice as discussed

Related

Getting Data from WIN32_PnPDeviceProperty using C#

I read data from class WIN32_PnPDeviceProperty using Powershell and command PS
C:> Get-PnpDeviceProperty -InstanceId ''.
Similarly I want to read data using C# framework, so I wrote sample code like follow
ObjectQuery query = new ObjectQuery("SELECT * FROM SWD\\PRINTENUM\\{E82E5EFD-6616-4E4F-9A96-7D94554A8BF0}");
ManagementObjectSearcher deviceSearch = new ManagementObjectSearcher(query);
foreach (ManagementObject device in deviceSearch.Get())
{
try
{
Console.WriteLine("Driver ----------------------------------------");
foreach (var item in device.Properties)
Console.WriteLine("{0} : {1}",item.Name,item.Value);
Console.WriteLine();
}
catch (Exception ex) { Console.WriteLine(ex.Message); }
}
But Query returns empty. I am not entirely sure the way to run query or get info using above method is correct or not.
Is there any other way to read data from the mentioned class ?

WMI, Win32_Process

I want to find which processes are using a particular dll using C# and WMI. Tried 3 approaches...
Getting CIM_DataFile object for the file and then get related processes.. It works for system dlls but not for My application dll.. It wont show any process associated with that even though process explorer shows the same.
Enumerating through all the processes and then enumerating through the process modules to find the DLL is being used or not.. Here also same issue.. working for system dlls but not for my application dlls.
Getting CIM_ProcessExecutables objects and getting DLLS/EXE and its linked processes... here also same thing is happening...
Is there anything im missing?
enter code here
using System;
using System.Management;
// Search the processes which have a certain file open
class App
{
public static void Main()
{
WhoHasThisFileOpen("c:\\\\users\\\\pawarnit\\\\source\\\\repos\\\\myprogram\\\\myprogram\\\\bin\\\\debug\\\\differentDllFile.dll");
Console.ReadLine();
}
static void WhoHasThisFileOpen(string objectQry)
{
SelectQuery query = new SelectQuery("select name from cim_datafile where name = '" + objectQry +"'" );
using (ManagementObjectSearcher searcher = new
ManagementObjectSearcher(query))
{
foreach (ManagementObject mo in searcher.Get())
{
Console.WriteLine("File Name: {0} \nIs currently opened by:",
mo.Properties["Name"].Value);
// Get processes having this File open
foreach (ManagementBaseObject b in mo.GetRelated("Win32_Process"))
{
ShowProcessProperties(b.ToString());
b.Dispose();
}
}
}
}
static void ShowProcessProperties(string objectClass)
{
using (ManagementObject process = new ManagementObject(objectClass))
{
process.Get();
PropertyDataCollection processProperties = process.Properties;
Console.WriteLine("ProcessID: {0,6} \tCommandLine: {1}",
processProperties["ProcessID"].Value,
processProperties["CommandLine"].Value);
}
}
}

Simple C# WMI Get & Put

I am trying to Read & Put values from and to WMI using C#.
The current example uses ccm namespace, for configmgr client.
The read functions works correctly, able to read ADV_RepeatRunBehavior value.
Though the Put(); doesn't work as expected, the values are not stored back and Invalid Class exception is thrown.
Some advice would be nice as I am new to this, many thanks.
static void Main(string[] args)
{
try
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher(
"root\\ccm\\Policy\\Machine",
"SELECT * FROM CCM_SoftwareDistribution WHERE PKG_PackageID='XXXXXXXX'");
foreach (ManagementObject queryObj in searcher.Get())
{
//Read works
//Console.WriteLine(queryObj["ADV_RepeatRunBehavior"].ToString());
//Console.ReadLine();
//Put doesn't
queryObj["ADV_RepeatRunBehavior"] = "RerunNever";
queryObj.Put();
}
}
catch (ManagementException z)
{
Console.WriteLine("An error occurred: " + z.Message);
Console.ReadLine();
}
}
Found the resolution for this.
You have to run Visual Studio as Administrator if testing on localhost
The connection to WMI has to be \\root\\ccm\\Policy\\Machine\\ActualConfig then its possible to Put() values.

How to check in C# if user account is active

How can I check from C# if a local user account (namely the local Administrator account) is active?
What I actually want is a C# replacement for the "Account Active" = "Yes" (or "No") output from the "net user Administrator" command.
I'm afraid this question looks like a duplicate to this one, but I don't know what to pass in for the parameter for the root DirectoryEntry object. Tried different things like "ldap://" + Environment.MachineName, "ldap://127.0.0.1", "WinNT://" + Environment.MachineName, but none of them worked. I get an exception thrown by the searcher.FindAll() call in all three cases.
class Program
{
static void Main(string[] args)
{
// Create the context for the principal object.
PrincipalContext ctx = new PrincipalContext(ContextType.Machine);
UserPrincipal u = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, "Administrator");
Console.WriteLine(String.Format("Administrator is enable: {0}", u.Enabled));
}
}
You can query WMI's Win32_UserAccount
This is boilerplate what MS's wmi code creator spits out as a reference;
using System;
using System.Management;
using System.Windows.Forms;
namespace WMISample
{
public class MyWMIQuery
{
public static void Main()
{
try
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT Disabled FROM Win32_UserAccount WHERE name = 'alexk'");
foreach (ManagementObject queryObj in searcher.Get())
{
Console.WriteLine("-----------------------------------");
Console.WriteLine("Win32_UserAccount instance");
Console.WriteLine("-----------------------------------");
Console.WriteLine("Disabled: {0}", queryObj["Disabled"]);
Console.ReadKey();
}
}
catch (ManagementException e)
{
MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
}
}
}
}
(I'd link the tool but as usual the msdn links are dead)
Try this.
var server = "YOURMACHINENAME";
var username = "Guest";
var de = new DirectoryEntry {Path = "WinNT://" + server + ",computer"};
var result = de.Children
.Cast<DirectoryEntry>()
.First<DirectoryEntry>(d => d.SchemaClassName == "User" && d.Properties["Name"].Value.ToString() == username);
var flags = (int)result.Properties["UserFlags"].Value;
var disabled = (flags & 2) == 2;
This isn't quite the same but they use DirectoryEntry directoryEntry = new DirectoryEntry(string.Format("WinNT://{0}/{1}", computerName, username)); Would that help?
Considering it's a local user, you need to call the win32 api funcion NetGetUserInfo to get what you need.
The example in pinvoke.net is almost what you need, however you need to change the level parameter to 2 to get the neccesary info

How do I retrieve the username that a Windows service is running under?

Given a service name, I would like to retrieve the username that it runs under (i.e. the username shown in the 'Log On' tab of a service's properties window).
There doesn't appear to be anything in the ServiceController class to retrieve this basic information. Nothing else in System.ServiceProcess looks like it exposes this information either.
Is there a managed solution to this, or am I going to have to drop down into something lower-level?
Using WMI, with the System.Management you can try the following code:
using System;
namespace WindowsServiceTest
{
class Program
{
static void Main(string[] args)
{
System.Management.SelectQuery sQuery = new System.Management.SelectQuery(string.Format("select name, startname from Win32_Service")); // where name = '{0}'", "MCShield.exe"));
using (System.Management.ManagementObjectSearcher mgmtSearcher = new System.Management.ManagementObjectSearcher(sQuery))
{
foreach (System.Management.ManagementObject service in mgmtSearcher.Get())
{
string servicelogondetails =
string.Format("Name: {0} , Logon : {1} ", service["Name"].ToString(), service["startname"]).ToString();
Console.WriteLine(servicelogondetails);
}
}
Console.ReadLine();
}
}
}
You can then later substitute the commented code with your service name, and it should only return the instances of your service process that is running.
WMI is your friend. Look at Win32_Service, specifically the StartName property. You can access WMI from C# via the System.Management.ManagementClass.
If you've not used WMI before, this article seems to be quite a good tutorial.
You can find this using the Windows Registry, reading the following string value, replacing [SERVICE_NAME] with the name of the Windows Service:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\[SERVICE_NAME]\ObjectName
Try this:
System.Security.Principal.WindowsIdentity.GetCurrent();
but the most obvious you will get LOCAL SYSTEM or NETWORK. The reason that you cannot show this user - that service can manage multiple users (shared by desktop, attached to current windows session, using shared resource ...)
System starts service, but any user can use it.
This solution works fine for me:
ManagementObject wmiService = new ManagementObject("Win32_Service.Name='" + this.ServiceName + "'");
wmiService.Get();
string user = wmiService["startname"].ToString();
public String getUsername() {
string username = null;
try {
ManagementScope ms = new ManagementScope("\\\\.\\root\\cimv2");
ms.Connect();
ObjectQuery query = new ObjectQuery
("SELECT * FROM Win32_ComputerSystem");
ManagementObjectSearcher searcher =
new ManagementObjectSearcher(ms, query);
foreach (ManagementObject mo in searcher.Get()) {
username = mo["UserName"].ToString();
}
string[] usernameParts = username.Split('\\');
username = usernameParts[usernameParts.Length - 1];
} catch (Exception) {
username = "SYSTEM";
}
return username;
}

Categories