I have a program that runs as a scheduled task. The program runs on XP as SYSTEM.
The idea is that the program will run in the background, while USER is active.
I need the program to logoff USER when specific conditions occur.
I tried using:
[DllImport("user32.dll")]
public static extern int ExitWindowsEx(int uFlags, int dwReason);
but that appears to not log USER off.
I think maybe it's logging SYSTEM off, as it is running as SYSTEM.
How can i logogg USER?
Thanks,
SummerBulb.
I think that you will need to run some code as that user. Create an app that runs when a user logs in and then monitors an event. Have your service set the event and then the code will call the ExitWindowsEx method. You will still need to use the forceifhung and logoff params as James mentioned.
It would help if you showed the flags for ExitWindowsEx, but you may need to impersonate the user, though I think this is unlikely. If I remember logging off the current user was enough, but you may have to force the logoff, as it can be cancelled otherwise, if the user hasn't saved some changes for example.
But to impersonate a user you can look at this:
http://www.codeproject.com/KB/system/UserImpersonation.aspx
I would start with looking here, and include both the logoff and forceifhung values:
http://msdn.microsoft.com/en-us/library/aa376868(VS.85).aspx
It would be similar to EWX_FORCEIFHUNG | EWX_LOGOFF as the parameter.
UPDATE:
I expect Mike is correct that impersonation won't help here.
Related
I am having an issue with a process being run, where the profile directory of the process' user has not yet been created.
To explain, here are the details of how this is happening:
We run a large distributed server grid, and are using (parts of) DataSynapse to execute processes on this grid. For those familiar with DataSynapse, the Engine is configured to run the particular service with "RunAs", where we use a certain AD domain service account for the service processes. I believe the problem is that DataSynapse, when running the process under "runas", does not set the LoadUserProfile flag (nor should it). Whatever the precise reason, if the "runas" service account (and AD domain account) has never logged on to some of the grid machines, then those machines will not have the user profile directory for the account.
For those not familiar with DataSynapse, here is a more generic explanation. On each machine on the grid, there is a process running, I'll call it dsService, and it runs under the credentials of the local machine's system account (or some similar account with elevated credentials). The process dsService will spawn a child process, say childProcess, but it runs childProcess under the credentials of our AD domain account, which I'll call serviceUser. There are thousands of machines on the grid, and typically they are never logged on to manually. In particular, the profile directory C:\users\serviceUser may not initially exist. Once it is created once, there are not further issues. But if new nodes are added to the grid, typically they will not have the C:\users\serviceUser initially. The problem is that when the dsService spawns childProcess, C:\users\serviceUser does not get created, and we need it.
I believe that this is because dsService does not set the LoadUserProfile flag to true when spawning childProcess, though I am not certain.
In any event, childProcess is a (.net) process (running as serviceUser) under our control, and I would like to know if there is a way (in C#) that childProcess can force the OS to create the running user's profile directory C:\users\serviceUser when it determines that it does not yet exist?
Edit:
Experimentation has confirmed that if one starts a process under another user ID, and the user's profile directory is not there (more specifically, if the user's local profile has not been created yet - merely deleting a pre-existing profile directory creates a different situation, one we're not interested in anyway), then (1) the profile directory (and one presumes, the local profile) gets created if the process is started with the LoadUserProfile set to true; and (2) the profile directory (and one presumes, the local profile) does NOT get created if the process is started with the LoadUserProfile set to false. This makes sense, and is as one would expect.
Related post: stackoverflow.com/q/9008742/1082063
If the running account has admin privileges, the following code will cause the creation of the running account's profile, including its UserProfile directory. Without admin, I don't know if it is possible:
using System.Runtime.InteropServices;
...
[DllImport("userenv.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int CreateProfile(
[In] string pszUserSid,
[In] string pszUserName,
System.Text.StringBuilder pszProfilePath,
int cchProfilePath);
....
public static string getUserProfilePath()
{
string userProfilePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
if(string.IsNullOrWhiteSpace(userProfilePath) || !Directory.Exists(userProfilePath))
{ //This will only work if we have admin...
var pathBuf = new System.Text.StringBuilder(240);
var Up = System.DirectoryServices.AccountManagement.UserPrincipal.Current;
if( 0 == CreateProfile(Up.Sid.ToString(), Up.SamAccountName, pathBuf, pathBuf.Capacity) }
{
userProfilePath = pathBuf.ToString();
}
}
return userProfilePath;
}
If anyone can tell me how to do this when the account is not admin, they will get their answer accepted as the correct answer. Until then, this at least gives others some idea.
Referring to this question: .net - Reboot machine from a C#/WPF App
I am attempting to create a c#/.net app that can restart the machine even if the session is locked (i.e., user is logged in, this app is running, but session is locked).
I tried this from the question: System.Diagnostics.Process.Start("shutdown.exe", "-r -t 0");
but apparently that only works if the session is unlocked. Additionally, after reading this: MSDN - InitiateSystemShutdown Function it seems the InitiateSystemShutdown function will display the System Shutdown dialog box, which doesn't seem like it will suite my purposes.
Are there any other methods of doing this?
The ExitWindowsEx function accomplished what I was trying to do.
Using:
[DllImport("user32.dll", SetLastError = true)]
public static extern int ExitWindowsEx(ExitWindows uFlags, ShutdownReason dwReason);
after adjusting token privileges, and using uFlags 0x06 (reboot / force). I used dwReason 0 as well. This function will restart the machine whether or not the session is locked.
here
I have a windows forms application that will be run in both domain and on non-domain (local desktop) environments. I'm trying to understand how the windows security works in these different environments. I need to programmatically identify when the windows user running my application as an Administrator which I'm assuming is different for domain and local environments (and possibly when the UAC is in control?? ).
I'm also a little confused as to whether the UAC supersedes a domain log in if turned on?
I expect most remote users of the product will be set as local Administrators too, and restricted by the UAC.
How do you check for privileges under these conditions? (vb.net app but c# is also fine - thank you)
Cheers, Tim.
Public Function isWindowsAdministrator() As Boolean
My.User.InitializeWithWindowsUser()
If My.User.IsAuthenticated Then
If My.User.IsInRole(Microsoft.VisualBasic.ApplicationServices.BuiltInRole.Administrator) Then
Return True
End If
End If
Return False
End Function
There is probably a nonVB/'pure' NET alternative, I just dont know the equivalents. There is also a way to test if the user can elevate to Admin, but it is a PInvoke, messy win32 thing, and doesnt actually elevate, just tests.
UAC will still pop up, the above just lets you know in advance if the user can authorize.
Vb.Net:
Public Function IsUserAnAdmin() As Boolean
End Function
C#:
[DllImport("shell32.dll")]
public static extern bool IsUserAnAdmin();
As you can see returns a Boolean by calling IsUserAnAdmin (you could obviously use an alias). for clarity I believe this works in all scenarios I mentioned but I haven't fully completed my Domain testing.... yet
I am trying to achive a situation:
I am logged as a user on my account.
I've created a two more accounts which I will try to log on in the
"background"
And now I want to execute my code to log on different user in the background,
so that if i can click ctrl+alt+del and go to the switch user screen
i can see that another account was logged on the system.
During investigation I've read that this was possbile with some undocumented winapi methods before Microsoft implemented Fast User Switch(FUS) which replaced GINA.
I don't want to Impersonate code as user. I want to start up the whole windows session for a user from code.
I've tried to do sth with CreateProcessWithLogonW() but this was unsuccessful.
Big virtual beer for anybody who can give me a hand with this! :)
Okay had to do a bit of digging to figure this out my self.
Essentially you would need to run a command in command prompt.
This should load explorer.exe as a second user.
runas /user:*computer name\*account name explorer.exe
Follow this to get an idea on running a command line command via c#:
How To: Execute command line in C#, get STD OUT results
Other sources:
http://www.computerhope.com/runas.htm
http://lifehacker.com/290435/switch-user-accounts-from-the-command-prompt
I have an app with a manifest that requires running as administrator, but part of the app is to map a drive using WNetAddConnection2 which I believe requires it to be run in the normal user context due to credentials etc. Is there a way to execute this bit of code in the normal user context without creating a separate process.
EDIT
From the comments I have got this far but it doesnt work. I expected it not to as I dont really understand quite how I should use this. Perhaps it best if I open a new question?
class Program
{
[DllImport("advapi32.DLL")]
public static extern bool ImpersonateLoggedOnUser(IntPtr hToken);
[DllImport("advapi32.DLL")]
public static extern bool RevertToSelf();
static void Main(string[] args)
{
IntPtr phToken = IntPtr.Zero;
ImpersonateLoggedOnUser(phToken);
MapDrives();
RevertToSelf();
}
}
EDIT
If the current user has admin privileges then the main process is elevated with the manifest, in the code which is elevated I want to run a command in the users non-elevated space as this appears to have different environment variables etc. I believe once a thread is started it cant change itself, it needs to run a new one.
take a look on A small C# Class for impersonating a User code project article. It implements an IDisposable class (that releases the authentication token after its use). I've seen .NET code leaking due to not releasing the impersonation tokens.
You can impersonate a user only for a block of code that will access the network resource you need to access as a different user. Your code will look like
using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
{
/* code that executes under the new context */
...
}
I hope it helps.
First you need to obtain the user token that you want to start the app as, you can do this using WTSQueryUserToken. If the user is not yet logged on you can use LogonUser Win32 API to obtain a new one in a new session. To get all the sessions on your computer you can use WTSEnumerateSessions.
Then once you have the token you can use CreateProcessAsUser or else ImpersonateLoggedOnUser Win32 APIs.
Please make sure to call CloseHandle on the handles you obtain, they are especially bad leaks for this type of work.
Im not sure this is a way to do this without creating a new process, ImpersonateLoggedOnUser will only work from a service, and I dont want to provide credentials.
correct me if I am wrong