Get a process's user name

  • Thread starter Thread starter Phil
  • Start date Start date
P

Phil

The Windows Task Manager, under the Processes tab, lists
the user name next to each process.

Is there a way to programmatically get the user name of a
process?

I am refining my application to work on Terminal Server
and only want to retrieve the processes running within
the user session, rather than all processes running on
the machine. I am using the System.Diagnostics.Process
class. I can use SystemInformation.UserName to get the
current user name.

Many thanks for any help.

Phil
 
This following code gives you all

using System;
using System.Management;

namespace WMITest
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class clsMain
{
static void Main(string[] args)
{
GetWMIStats();
Console.ReadLine();
}

static void GetWMIStats()
{
long mb = 1048576; //megabyte in
# of bytes 1024x1024

//Connection credentials to the
remote computer - not needed if the logged in account has
access
ConnectionOptions oConn = new
ConnectionOptions();
//oConn.Username = "username";
//oConn.Password = "password";
System.Management.ManagementScope
oMs = new System.Management.ManagementScope
("\\\\localhost", oConn);

//get Fixed disk stats
System.Management.ObjectQuery
oQuery = new System.Management.ObjectQuery("select
FreeSpace,Size,Name from Win32_LogicalDisk where
DriveType=3");
ManagementObjectSearcher
oSearcher = new ManagementObjectSearcher(oMs,oQuery);
ManagementObjectCollection
oReturnCollection = oSearcher.Get();

//variables for numerical
conversions
double fs = 0;
double us = 0;
double tot = 0;
double up = 0;
double fp = 0;

//for string formating args
object[] oArgs = new object[2];
Console.WriteLine
("*******************************************");
Console.WriteLine("Hard Disks");
Console.WriteLine
("*******************************************");

//loop through found drives and
write out info
foreach( ManagementObject oReturn
in oReturnCollection )
{
// Disk name
Console.WriteLine
("Name : " + oReturn["Name"].ToString());

//Free space in MB
fs = Convert.ToInt64
(oReturn["FreeSpace"])/mb;

//Used space in MB
us = (Convert.ToInt64
(oReturn["Size"]) - Convert.ToInt64(oReturn
["FreeSpace"]))/mb;

//Total space in MB
tot = Convert.ToInt64
(oReturn["Size"])/mb;

//used percentage
up = us/tot * 100;

//free percentage
fp = fs/tot * 100;

//used space args
oArgs[0] = (object)us;
oArgs[1] = (object)up;

//write out used space
stats
Console.WriteLine("Used:
{0:#,###.##} MB ({1:###.##})%", oArgs);

//free space args
oArgs[0] = fs;
oArgs[1] = fp;

//write out free space
stats
Console.WriteLine("Free:
{0:#,###.##} MB ({1:###.##})%", oArgs);
Console.WriteLine
("Size : {0:#,###.##} MB", tot);
Console.WriteLine
("*******************************************");
}

// Get process info including a
method to return the user who is running it
oQuery = new
System.Management.ObjectQuery("select * from
Win32_Process");
oSearcher = new
ManagementObjectSearcher(oMs,oQuery);
oReturnCollection = oSearcher.Get
();

Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine
("*******************************************");
Console.WriteLine("Processes");


Console.WriteLine
("*******************************************");
Console.WriteLine("");

//loop through each process - I
limited it to first 6 so the DOS buffer would not
overflow and cut off the disk stats
int i=0;
foreach( ManagementObject oReturn
in oReturnCollection )
{
if(i==6)
break;
i++;
Console.WriteLine
("*******************************************");
Console.WriteLine(oReturn
["Name"].ToString().ToLower());
Console.WriteLine
("*******************************************");
//arg to send with method
invoke to return user and domain - below is link to SDK
doc on it

//http://msdn.microsoft.com/library/default.asp?
url=/library/en-
us/wmisdk/wmi/getowner_method_in_class_win32_process.asp?
frame=true
string[] o = new String
[2];
oReturn.InvokeMethod
("GetOwner",(object[])o);
//write out user info
that was returned
Console.WriteLine
("User: " + o[1]+ "\\" + o[0]);
Console.WriteLine("PID: "
+ oReturn["ProcessId"].ToString());

//get priority
if(oReturn["Priority"] !=
null)
Console.WriteLine
("Priority: " + oReturn["Priority"].ToString());

//get creation date -
need managed code function to convert date -
if(oReturn
["CreationDate"] != null)
{
try
{
//get
datetime string and convert
string s
= oReturn["CreationDate"].ToString();
DateTime
dc = ToDateTime(s);

//write
out creation date

Console.WriteLine("CreationDate: " + dc.AddTicks(-
TimeZone.CurrentTimeZone.GetUtcOffset
(DateTime.Now).Ticks).ToLocalTime().ToString());
}
//just in
case - I was getting a weird error on some entries
catch(Exception
err)
{

Console.WriteLine(err.Message);
}
}
//this is the amount of
memory used
if(oReturn
["WorkingSetSize"] != null)
{
long mem =
Convert.ToInt64(oReturn["WorkingSetSize"].ToString()) /
1024;
Console.WriteLine
("Mem Usage: {0:#,###.##}Kb",mem);
}
Console.WriteLine("");
}

}

//There is a utility called mgmtclassgen
that ships with the .NET SDK that
//will generate managed code for existing
WMI classes. It also generates
// datetime conversion routines like this
one.
//Thanks to Chetan Parmar and
dotnet247.com for the help.
static System.DateTime ToDateTime(string
dmtfDate)
{
int year =
System.DateTime.Now.Year;
int month = 1;
int day = 1;
int hour = 0;
int minute = 0;
int second = 0;
int millisec = 0;
string dmtf = dmtfDate;
string tempString =
System.String.Empty;

if (((System.String.Empty ==
dmtf) || (dmtf == null)))
{
return
System.DateTime.MinValue;
}

if ((dmtf.Length != 25))
{
return
System.DateTime.MinValue;
}

tempString = dmtf.Substring(0, 4);
if (("****" != tempString))
{
year = System.Int32.Parse
(tempString);
}

tempString = dmtf.Substring(4, 2);

if (("**" != tempString))
{
month = System.Int32.Parse
(tempString);
}

tempString = dmtf.Substring(6, 2);

if (("**" != tempString))
{
day = System.Int32.Parse
(tempString);
}

tempString = dmtf.Substring(8, 2);

if (("**" != tempString))
{
hour = System.Int32.Parse
(tempString);
}

tempString = dmtf.Substring(10,
2);

if (("**" != tempString))
{
minute =
System.Int32.Parse(tempString);
}

tempString = dmtf.Substring(12,
2);

if (("**" != tempString))
{
second =
System.Int32.Parse(tempString);
}

tempString = dmtf.Substring(15,
3);

if (("***" != tempString))
{
millisec =
System.Int32.Parse(tempString);
}

System.DateTime dateRet = new
System.DateTime(year, month, day, hour, minute, second,
millisec);

return dateRet;
}
}
}
 
You will have to resort to Pinvoke and call Win32 TS API's (Wtsapi32 ).
Here 's a complete sample...


using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Security;
// Using Wtsapi32 (available on Windows.NET and XP)
// Get Process information using Terminal server API's

using HANDLE = System.IntPtr;
class ProcIdent {

[DllImport("wtsapi32", CharSet=CharSet.Auto, SetLastError=true),
SuppressUnmanagedCodeSecurityAttribute]
static extern bool WTSEnumerateProcesses (
HANDLE ProcessHandle, // handle to process (from WTSOpenServer)
int Reserved, // dmust be 0
uint Version, // must be 1
ref IntPtr ppProcessInfo, // pointer to pointer to Processinfo
ref uint pCount // no. of processes
);

[DllImport("wtsapi32", SetLastError=true),
SuppressUnmanagedCodeSecurityAttribute]
static extern IntPtr WTSOpenServer (
string ServerName // Server name (NETBIOS)
);

[DllImport("wtsapi32", SetLastError=true),
SuppressUnmanagedCodeSecurityAttribute]
static extern void WTSCloseServer (
HANDLE hServer // Handle obtained by WTSOpenServer
);

[DllImport("wtsapi32", SetLastError=true),
SuppressUnmanagedCodeSecurityAttribute]
static extern void WTSFreeMemory (
IntPtr pMemory );

[StructLayout(LayoutKind.Sequential)]
struct WTSProcessInfo {
internal uint SessionId;
internal uint ProcessId;
[MarshalAs(UnmanagedType.LPTStr)] internal string pProcessName;
internal IntPtr pUserSid;
}
[DllImport("advapi32", CharSet=CharSet.Auto)]
static extern bool ConvertSidToStringSid(
IntPtr pSID,
[In,Out,MarshalAs(UnmanagedType.LPTStr)] ref string pStringSid);

[DllImport("advapi32", CharSet=CharSet.Auto, SetLastError=true)]
static extern bool LookupAccountSid
(
string lpSystemName, // name of local or remote computer
IntPtr pSid, // security identifier
StringBuilder Account, // account name buffer
ref int cbName, // size of account name buffer
StringBuilder DomainName, // domain name
ref int cbDomainName, // size of domain name buffer
ref int peUse // SID type
);


const int ERROR_NO_MORE_ITEMS = 259;

public static void Main() {
HANDLE hServer = IntPtr.Zero;
IntPtr pInfo = IntPtr.Zero;
IntPtr pInfoSave = IntPtr.Zero;
WTSProcessInfo WTSpi; // Reference to ProcessInfo struct
uint count = 0;
int iPtr = 0;
try {
hServer = WTSOpenServer(System.Environment.MachineName);
if(hServer == IntPtr.Zero)
Console.WriteLine(Marshal.GetLastWin32Error());
if (WTSEnumerateProcesses(hServer, 0, 1, ref pInfo, ref count))
{
pInfoSave = pInfo;
Console.WriteLine("Number of processes :{0}", count);
for(int n = 0; n < count; n++) {
WTSpi = (WTSProcessInfo) Marshal.PtrToStructure(pInfo,
typeof(WTSProcessInfo) );
iPtr = (int)(pInfo) + Marshal.SizeOf(WTSpi);
pInfo = (IntPtr)(iPtr);
if(WTSpi.ProcessId != 0)
Console.WriteLine(WTSpi.pProcessName + "\t" + WTSpi.ProcessId + "\t" +
DumpAccountFromSid(WTSpi.pUserSid));
else
Console.WriteLine("Idle pseudo proc");
}
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
// Free memory used by WTSEnumerateProcesses
WTSFreeMemory(pInfoSave);
// Close server handle
WTSCloseServer(hServer);
}
}

static string DumpAccountFromSid(IntPtr SID)
{
int cchAccount = 0;
int cchDomain = 0;
int snu = 0 ;
StringBuilder sb = new StringBuilder();

// Caller allocated buffer
StringBuilder Account= null;
StringBuilder Domain = null;
// Lookup account name on local system
// First call to get required buffer sizes
bool ret = LookupAccountSid(null, SID, Account, ref cchAccount, Domain,
ref cchDomain, ref snu);
if ( ret == true )
if ( Marshal.GetLastWin32Error() == ERROR_NO_MORE_ITEMS )
return "Error";
Account = new StringBuilder( cchAccount );
Domain = new StringBuilder( cchDomain );
ret = LookupAccountSid(null, SID, Account, ref cchAccount, Domain, ref
cchDomain, ref snu);
if (ret)
{
sb.Append(Domain);
sb.Append(@"\");
sb.Append(Account);
}
else
sb.Append("Win32 Error: " + Marshal.GetLastWin32Error());
return sb.ToString();
}
}

Willy.
 
Thanks to both of you guys for the help. Its much
appreciated. You're both obviously experienced in the
area...

so to follow on, will either of these code snippets be
able to be run under a standard user account on Terminal
Server without Administrator (or other higher) rights?

I read recently that Windows Server 2003 does not grant
standard users permission to some detailed Process
information using the .NET framework. I'm wondering of
the same applies to this code?

Many Thanks

Phil
 
Back
Top