I'm writing a program that returns a list of users currently logged in a server.
Here's the code that does this:
private List<string> GetUsers(string server)
{
ConnectionOptions options = new ConnectionOptions();
ManagementScope moScope = new ManagementScope(#"\\" + server + #"\root\cimv2");
moScope.Connect();
ObjectQuery query = new ObjectQuery("select * from Win32_Process where name='explorer.exe'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(moScope, query);
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject m in queryCollection)
{
ManagementOperationObserver mo = new ManagementOperationObserver();
mo.ObjectReady += new ObjectReadyEventHandler(mo_ObjectReady);
m.InvokeMethod(mo, "GetOwner", null);
}
}
private void mo_ObjectReady(object sender, ObjectReadyEventArgs e)
{
string user = e.NewObject.Properties["user"].Value.ToString();
//I would like to return the username back to the GetUsers function. How can I do this?
}
The mo_ObjectReady can get one username that is currently logged in the server. How could I return the value to the GetUsers function so I can put them altogether in a List?
Thanks in advance.
Is there any possibility to determine how a c# application was being started?
In my case I want to check if this application (wpf) is being started by a shortcut located in a specific folder.
So, there are two ways to open my application
using direct shortcut
starting another application which is like an update manager to keep my application up to date. After checking, it starts my application with Process.Start()
And I want to ensure that the application is only able to be started with the update manager.
A trick you could use is to check the parent's PID, and then get some of the parent's process information.
If the parent's process name is something like "explorer.exe" then the application was started from the shortcut or directly by double-clicking it on explorer.
Otherwise, it was started from another application: it could be your updater application, it could also be another application with the same name as your updater application...
This means you have to re-think how deep you want to go for such a solution, and how deep do you want security control. You could pass arguments from your updater to your main application, or implement some inter-process communication with token exchanges... it is impossible to make a 100% secure system.
As someone commented above, this seems like a XY problem... or maybe not. Maybe it is just a security concern. It's recommended to revise what exactly are you aiming for this software.
In case you need sample code for retrieving process information in .NET (by using System.Management), then just give a try to the code listed below. All you have to do is to place it in a console application project named 'Updater', and correctly set the path to your main application in the code.
If you play a little bit with this example by starting and closing YourApplication.exe in different situations, then you should be able to see an output like this:
Parent process 'Updater.exe' [PID=5472]
Parent process 'explorer.exe' [PID=12052]
The code below was tested on VS2017 .Net 4.6.1
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Management;
class Program
{
static void Main(string[] args)
{
Process.Start(new ProcessStartInfo()
{
FileName = "YourApplication.exe" // path to your application
});
while (Console.ReadKey(true).Key != ConsoleKey.Escape)
{
Process process = Process.GetProcessesByName("YourApplication").FirstOrDefault(); // your application's process name
if (process == null)
{
Console.WriteLine($"Process is not running...");
continue;
}
ProcessManager pm = ProcessManager.FromLocalMachine();
var processProperties = pm.GetProcessProperties(process.Id);
int parentProcessId = Convert.ToInt32(processProperties[EProcessProperty.ParentProcessId]);
try
{
var parentProcessProperties = pm.GetProcessProperties(parentProcessId);
string parentProcessName = parentProcessProperties[EProcessProperty.Name].ToString();
Console.WriteLine($"Parent process '{parentProcessName ?? "Unknown"}' [PID={parentProcessId}]");
Console.WriteLine("---------------------------------");
}
catch { Console.WriteLine("Parent process information not found."); }
}
}
}
public class ProcessConnection
{
internal ManagementScope ManagementScope { get; }
internal ProcessConnection(string machineName, string user = null, string password = null, string domain = null)
{
ManagementScope = new ManagementScope
{
Path = new ManagementPath(#"\\" + machineName + #"\root\CIMV2"),
Options = new ConnectionOptions
{
Impersonation = ImpersonationLevel.Impersonate,
Authentication = AuthenticationLevel.Default,
EnablePrivileges = true,
Username = user == null ? null : (string.IsNullOrWhiteSpace(domain) ? user : $"{domain}\\{user}"),
Password = user == null ? null : password,
},
};
ManagementScope.Connect();
}
}
public class ProcessManager
{
public static ProcessManager FromLocalMachine() => new ProcessManager()
{
Machine = Environment.MachineName,
};
public static ProcessManager FromRemoteMachine(string machine, string user = null, string password = null, string domain = null) => new ProcessManager()
{
Machine = machine,
User = user,
Password = password,
Domain = domain,
};
private ProcessManager() { }
public string Machine { get; private set; }
public string User { get; private set; }
public string Password { get; private set; }
public string Domain { get; private set; }
private ProcessConnection Connection { get; set; }
private ManagementScope ManagementScope => Connection == null ? (Connection = new ProcessConnection(Machine, User, Password, Domain)).ManagementScope : Connection.ManagementScope;
public EProcessStartStatus StartProcess(string processPath)
{
ManagementClass mc = new ManagementClass($"\\\\{Machine}\\root\\CIMV2", "Win32_Process", null);
ManagementBaseObject process = mc.GetMethodParameters("Create");
process["CommandLine"] = processPath;
ManagementBaseObject createCode = mc.InvokeMethod("Create", process, null);
string createCodeStr = createCode["ReturnValue"].ToString();
return (EProcessStartStatus)Convert.ToInt32(createCodeStr);
}
public bool KillProcess(string processName)
{
try
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get()) mo.InvokeMethod("Terminate", null);
return true;
}
catch { return false; }
}
public bool KillProcess(int processId)
{
try
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE ProcessId = '{processId}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get()) mo.InvokeMethod("Terminate", null);
return true;
}
catch { return false; }
}
public void SetProcessPriority(string processName, EProcessPriority priority)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject managementObject in managementObjectSearcher.Get())
{
ManagementBaseObject methodParams = managementObject.GetMethodParameters("SetPriority");
methodParams["Priority"] = priority;
managementObject.InvokeMethod("SetPriority", methodParams, null);
}
}
public string GetProcessOwner(string processName)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get())
{
ManagementBaseObject methodParams = mo.GetMethodParameters("GetOwner");
ManagementBaseObject owner = mo.InvokeMethod("GetOwner", null, null);
return owner["User"].ToString();
}
return null;
}
public string GetProcessOwnerSID(string processName)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get())
{
ManagementBaseObject methodParams = mo.GetMethodParameters("GetOwnerSid");
ManagementBaseObject OwnerSid = mo.InvokeMethod("GetOwnerSid", null, null);
return OwnerSid["Sid"].ToString();
}
return null;
}
public IList<int> GetRunningProcesses()
{
IList<int> processes = new List<int>();
SelectQuery query = new SelectQuery("SELECT * FROM Win32_Process");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get()) processes.Add(int.Parse(mo["ProcessId"].ToString()));
return processes;
}
public IDictionary<EProcessProperty, object> GetProcessProperties(int processId)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE ProcessId = '{processId}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
Dictionary<EProcessProperty, object> properties = new Dictionary<EProcessProperty, object>();
foreach (ManagementObject mo in searcher.Get())
{
foreach (PropertyData pd in mo.Properties)
{
if (Enum.TryParse(pd.Name, out EProcessProperty e)) properties[e] = pd.Value;
else Console.WriteLine(pd.Name + " is not mapped in the properties enumeration.");
}
}
return properties;
}
public IDictionary<EProcessProperty, object> GetProcessProperties(string processName)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
Dictionary<EProcessProperty, object> properties = new Dictionary<EProcessProperty, object>();
foreach (ManagementObject mo in searcher.Get())
{
foreach (PropertyData pd in mo.Properties)
{
if (Enum.TryParse(pd.Name, out EProcessProperty e)) properties[e] = pd.Value;
else Console.WriteLine(pd.Name + " is not mapped in the properties enumeration.");
}
}
return properties;
}
public IList<int> GetProcessessFromExecutablePath(string executablePath)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE ExecutablePath = '{executablePath.Replace("\\", "\\\\")}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
return searcher.Get().Cast<ManagementObject>().Select(mo => Convert.ToInt32(mo["ProcessId"])).ToList();
}
}
public enum EProcessPriority : uint
{
IDLE = 0x40,
BELOW_NORMAL = 0x4000,
NORMAL = 0x20,
ABOVE_NORMAL = 0x8000,
HIGH_PRIORITY = 0x80,
REALTIME = 0x100
}
public enum EProcessStartStatus
{
Success = 0,
AccessDenied = 2,
NoPermissions = 3,
Unknown = 8,
FileNotFound = 9,
Invalid = 21,
}
public enum EProcessProperty
{
Caption,
CommandLine,
CreationClassName,
CreationDate,
CSCreationClassName,
CSName,
Description,
ExecutablePath,
ExecutionState,
Handle,
HandleCount,
InstallDate,
KernelModeTime,
MaximumWorkingSetSize,
MinimumWorkingSetSize,
Name,
OSCreationClassName,
OSName,
OtherOperationCount,
OtherTransferCount,
PageFaults,
PageFileUsage,
ParentProcessId,
PeakPageFileUsage,
PeakVirtualSize,
PeakWorkingSetSize,
Priority,
PrivatePageCount,
ProcessId,
QuotaNonPagedPoolUsage,
QuotaPagedPoolUsage,
QuotaPeakNonPagedPoolUsage,
QuotaPeakPagedPoolUsage,
ReadOperationCount,
ReadTransferCount,
SessionId,
Status,
TerminationDate,
ThreadCount,
UserModeTime,
VirtualSize,
WindowsVersion,
WorkingSetSize,
WriteOperationCount,
WriteTransferCount,
}
If there are only 2 ways of starting your app, the second method should pass a parameter (a GUID?) to Process.Start() - generated by your updater app.
Maybe devise some kind of algorithm that allows the app to start only with the token.
From what I know this is impossible in the way you would like it to be but there's one trick which you can use. Firstly change your WPF application's entry method to get the command line arguments, and ( for example ) use -u argument to distinct from where the application was started. Then after -u you can pass a HWND or a process ID that matches your updater. Of course you have to then check if that application is running and if it's your updater.
example :
// updated process start
ProcessStartInfo psi = new ProcessStartInfo("your/WPF/application.exe");
psi.Arguments = "-u " + Process.GetCurrentProcess().Id;
// fill up rest of the properties you need
Process.Start(psi);
// wpf application's entry point
void Main(string[] args)
{
string updaterProcessIdstr = string.Empty;
for (int i = 0; i < args.Length; i++)
{
if(args[i] == "-u")
{
updaterProcessIdstr = args[i + 1];
i++;
}
}
int pid = int.Parse(updaterProcessIdstr);
Process updaterProcess = Process.GetProcessById(pid);
// do some validation here
// send something to stdin and read from stdout
// to determine if it was started from that updater.
}
I want my program to check if Windows 10 has been activated
I have the following code
public static bool IsWindowsActivated()
{
bool activated = true;
ManagementScope scope = new ManagementScope(#"\\" + System.Environment.MachineName + #"\root\cimv2");
scope.Connect();
SelectQuery searchQuery = new SelectQuery("SELECT * FROM Win32_WindowsProductActivation");
ManagementObjectSearcher searcherObj = new ManagementObjectSearcher(scope, searchQuery);
using (ManagementObjectCollection obj = searcherObj.Get())
{
foreach (ManagementObject o in obj)
{
activated = ((int)o["ActivationRequired"] == 0) ? true : false;
}
}
return activated;
}
when trying to use this code, the debugger complains Invalid class, which I have no idea what it is
what should I do to fix this? or is there any other way to check the license status of Windows?
The WMI class Win32_WindowsProductActivation is only supported on windows XP. For windows 10 you need to use SoftwareLicensingProduct
public static bool IsWindowsActivated()
{
ManagementScope scope = new ManagementScope(#"\\" + System.Environment.MachineName + #"\root\cimv2");
scope.Connect();
SelectQuery searchQuery = new SelectQuery("SELECT * FROM SoftwareLicensingProduct WHERE ApplicationID = '55c92734-d682-4d71-983e-d6ec3f16059f' and LicenseStatus = 1");
ManagementObjectSearcher searcherObj = new ManagementObjectSearcher(scope, searchQuery);
using (ManagementObjectCollection obj = searcherObj.Get())
{
return obj.Count > 0;
}
}
Currently I'm using following methods to get hardware information (network adapter, processor, hdd)
ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectSearcher mbs = new ManagementObjectSearcher("Select * From Win32_processor");
ManagementObject dsk = new ManagementObject(#"win32_logicaldisk.deviceid=""c:""");
My app is desktop, client-server (app and db are installed on server).
This methods get information for client. Is there a way to get hardware information for some node on lan - I want to get hardware information for server?
This is a subroutine I use in order to query remote hosts (here I assume I already configured WMI on the remote computer):
public string getWMI(string[] parameters)
{
string ip = parameters[0];
string username = parameters[1];
string password = parameters[2];
string query = parameters[3];
string result = "";
ConnectionOptions options = new ConnectionOptions();
ManagementScope scope;
options.Username = username;
options.Password = password;
try
{
scope = new ManagementScope("\\\\" + ip + "\\root\\cimv2", options);
scope.Connect();
if (scope.IsConnected)
{
ObjectQuery q = new ObjectQuery(query);
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, q);
ManagementObjectCollection objCol = searcher.Get();
foreach (ManagementObject mgtObject in objCol)
{
result = result + mgtObject.GetText(TextFormat.CimDtd20);
}
}
else
{
}
}
catch (Exception e)
{
writeLogFile("WMI Error: " + e.Message);
writeLog("WMI Error: " + e.Message);
}
return result;
}
In that subroutine I use a direct query such as "select * from Win32_ComputerSystem" but you can use ManagementClass as well.
I want to get hardware information for server?
WMI can poin to another server as long as:
The eserver exposes WMI
The fireawall does not block it.
Your user account has the rights on the other server.
Simple like that.
How to check login user name from the system in c#
I tried it using this method
static string whoisLoggedIn(string HostOrIP)
{
GUFlag = true;
HostOrIP = Environment.MachineName;
System.Management.ConnectionOptions myConnectionOptions = new System.Management.ConnectionOptions();
myConnectionOptions.Impersonation = System.Management.ImpersonationLevel.Impersonate;
System.Management.ManagementScope objwmiservice;
System.Management.ManagementObjectSearcher myObjectSearcher2;
System.Management.ManagementObjectCollection myCollection2;
try
{
objwmiservice = new System.Management.ManagementScope(("\\\\" + (HostOrIP +
"\\root\\cimv2")), myConnectionOptions);
objwmiservice.Connect();
myObjectSearcher2 = new System.Management.ManagementObjectSearcher(objwmiservice.Path.ToString(),
"Select UserName from Win32_ComputerSystem");
myObjectSearcher2.Options.Timeout = new TimeSpan(0, 0, 0, 0, 7000);
myCollection2 = myObjectSearcher2.Get();
GUFlag = false;
foreach (System.Management.ManagementObject myObject in myCollection2)
{
if (!(myObject.GetPropertyValue("Username") == null))
{
string Userx = myObject.GetPropertyValue("Username").ToString();
int posx = Userx.LastIndexOf("\\");
if ((posx > 0))
{
Userx = Userx.Substring((posx + 1));
return Userx.ToUpper();
}
}
}
return "<Nobody>";
}
catch (Exception)
{
return "<Nobody>";
}
finally {
GUFlag = false;
}
}
But the problem is some time deadlock occur on myObjectSearcher2.Get();
Is there any way available to get login username
did you try that?
Environment.UserName
it will give you the user name of the user currently login on windows
EDIT
I found this bit of code here http://www.debugging.com/bug/20243, it may solve your issue.
solution by using WMI ( http://msdn.microsoft.com/en-us/library/system.management.aspx ):
private string GetUserName()
{
string result = "";
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT UserName, Name FROM Win32_ComputerSystem"))
{
foreach (ManagementObject mo in searcher.Get())
{
if (mo["UserName"] != null)
result = mo["UserName"].ToString();
if (mo["Name"] != null)
result += " (" + mo["Name"].ToString() + ")";
}
}
return result;
}
Unless I'm not understanding you correctly, I believe it's just:
using System.Security.Principal;
this.nametext = WindowsIdentity.GetCurrent().Name;