Simple C# WMI Get & Put - c#

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.

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);
}
}
}

Query User Sessions in Windows

There is a built-in tool: query.exe that allows you to view all active users and sessions in Windows.
It's output looks like:
PS C:\> query.exe user
USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME
>testusr console 1 Active none 12/16/2014 9:29 AM
Right now I have code that just parses the query.exe output, but some of us are concerned that future OS upgrades might change query's output so we're looking for an API call that can be used instead.
Is there anyway .Net way to gather the same information?
For alternatives, we don't necessary need all the fields, but we do need: Username, State, and Logon Time. We also need to run this code from the System context so any code or WMI classes that requires the user context won't work for us.
Well what I found and I think could be useful for you is Cassia project.
There is almost ready for you example in main page:
ITerminalServicesManager manager = new TerminalServicesManager();
using (ITerminalServer server = manager.GetLocalServer())
{
server.Open();
foreach (ITerminalServicesSession session in server.GetSessions())
{
Console.WriteLine("Hi there, " + session.UserAccount + " on session " + session.SessionId);
Console.WriteLine("It looks like you logged on at " + session.LoginTime +
" and are now " + session.ConnectionState);
}
}
As you can see when you get a TerminalServicesSession you will find UserName, LoginTime and ConnectionState.
Hope this will help you.
You can simply get the last logon time using WMI:
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 * FROM Win32_LogonSession");
foreach (ManagementObject queryObj in searcher.Get())
{
Console.WriteLine("-----------------------------------");
Console.WriteLine("Win32_LogonSession instance");
Console.WriteLine("-----------------------------------");
Console.WriteLine("Last Logon: {0}", queryObj["StartTime"]);
}
}
catch (ManagementException e)
{
MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
}
}
}
}
Sounds like you want NetWkstaUserEnum. I couldn't find a native .NET version of this but it seems like a fairly light interop call.

WQL Like statement & syntax

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

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