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
Related
I have a .NET c# service running as LocalSystem on Windows10 64bit. It's job is to alter the "ProxyEnable" and "ProxyServer" values located under
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings
in the registry. It does so, for all "human" Users of the System (that is, the key starting with "S-1-5-21.."). It works fine and all browsers the user starts up use this configuration (proxy or no proxy).
However, browsers that are still running won't notice changes (turning the proxy setting on or off) until a long time - OR until i manually just open and close the Windows "Internet Options > Proxy Settings" (without doing changes or saving them) or restart the browser(s). The latter two make the System re-read and propagate the settings to all (other) open browsers.
Now DllImport'ing wininet.dll and using the InternetSetOption does work
[DllImport("wininet.dll", SetLastError = true)]
private static extern bool InternetSetOption(
IntPtr hInternet,
int dwOption,
IntPtr lpBuffer,
int lpdwBufferLength);
private const int INTERNET_OPTION_PROXY_SETTINGS_CHANGED = 95;
private const int INTERNET_OPTION_SETTINGS_CHANGED = 39;
private const int INTERNET_OPTION_REFRESH = 37;
...
InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY_SETTINGS_CHANGED, IntPtr.Zero, 0);
InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0);
InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
but only when i perform this piece of code as the logged in user. When the service performs it, it doesn't do anything. I guess it's because as LocalSystem the service is applying it to the wrong scope.
I have tinkered around a lot. Trying to start another process as the user is no option as this would require credentials. Also the service using LocalSystem is set.
I am just convinced that as LocalSystem, that is close to Administrator in terms of privileges, there must be a way to tell all applications and browsers, that the Proxy Settings have changed. Its just the propagation like opening and closing the Proxy Settings-GUI invokes, that i need to trigger somehow. But i don't know how. Do you?
This is how environment variables & Reg keys function in windows - as I understand it all new processes get a snapshot of all variables when they start, but thats it. They will only update when you restart the process.
See C# : How to change windows registry and take effect immediately
This is 335th time this question being asked, by I've found no answer.
I'm trying to send raw data directly to printer via WinSpool api from ASP.net C# application.
My code is just a copy from here.
Error goes here
if( OpenPrinter( szPrinterName.Normalize(), out hPrinter, IntPtr.Zero ) )
It works fine for local printer but for shared network printer the result of OpenPrinter (result of GetLastError actually) is always 5 - Access Denied.
I've tried
different values for PRINTER_DEFAULTS with different combinations of DesiredAccess
give administrator privileges to user
setup printer like this
I must note that I just want to print, not change printer config or something that require administrative rights.
I can print to this shared printer from server using Printer Option page and test tool embedded in it. So printer works. How to gain access to it via API?
Update: looks like this code is working fine if called from Windows Application or Console Application. Then why access denied in Web Application?
Update 2: problem may be caused by the fact that printer installed on host PC and shared with virtual PC (or in production: printer is installed inside domain and shared to PC in DMZ) and there is no proper way to grant rights to this printer to users of virtual PC (or users outside of domain)
Update 3: and here is one more fact. If I browse to host PC from virtual in explorer (like this \\host_pc\C$) I get notified to enter user name and password to access host PC. If I check "save password" after that the whole "access denied"-problem will go away until I change password on host PC.
By default, your ASP.Net website running under IIS runs under a low-privilege local user account IIS_APPPOOL\mysite. In order for you to allow clients to access domain resources from the website, you'll need to change the user that IIS runs under (known as the application pool identity) to a domain user that has the correct rights to everything (both the network printer, and IIS itself).
The simplest solution (there may be more secure ones) is to change the IIS APPPool to use the built-in NetworkService account. This account is automatically added to your domain as MyDomain\MyHostName$, so you can use that to grant printer permissions (or whatever else is needed).
To change the app pool identity, just open the IIS manager, select the right application pool and then hit "Advanced Settings", and look for the setting "Identity".
More info here:
http://www.iis.net/learn/manage/configuring-security/application-pool-identities
Adding my answer since the accepted answer didn't solve my issue, to any who may get this error this might be useful to you if:
You get an error building for AnyCPU or x64.
You don't get an error building for x86.
The issue seems to be in GC recycling the PRINTER_DEFAULTS struct and than the OpenPrinter tries writing to that location. The suggested solution is to use a class which will stay on the stack.
public class PrinterSettings
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal class PRINTERDEFAULTSClass
{
public IntPtr pDatatype;
public IntPtr pDevMode;
public int DesiredAccess;
}
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, PRINTERDEFAULTSClass pdc);
public DEVMODE GetPrinterSettings(string PrinterName)
{
DEVMODE dm;
var pdc = new PRINTERDEFAULTSClass
{
pDatatype = new IntPtr(0),
pDevMode = new IntPtr(0),
DesiredAccess = PRINTER_ALL_ACCESS
};
var nRet = Convert.ToInt32(OpenPrinter(PrinterName,
out hPrinter, pdc));
}
}
I am writing a program that shows/hides the window of some target application. I was testing it out earlier and noticed something strange. If I run the target application as Administrator (right-click->Properties, "Compatability" tab, "Run this program as administrator") it doesn't work.
To demonstrate I wrote a simple GUI app called "TargetApplication" and then I wrote the following code to test showing/hiding this application:
class Program
{
static void Main(string[] args)
{
IntPtr windowPtr = FindWindow(null, "TargetApplication");
ShowWindow(windowPtr, 0); // 0 = Hide
Console.WriteLine("The window is now hidden. Press Enter to restore");
Console.ReadLine();
ShowWindow(windowPtr, 9); // 9 = Restore
Console.WriteLine("The window is now restored. Press Enter to exit.");
Console.ReadLine();
}
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
If I start the windowed application without Administrator rights it doesn't work.
Would anyone mind testing this for me? I have uploaded the .exe's for both applications here:
TestShowWindow Download
All you have to do is download them and run TestApplication.exe then run TestShowWindow.exe. You will find that by changing TestApplication.exe to run as Administrator causes ShowWindow to no longer work.
Of course if you don't trust downloading my stuff you can always compile my code and test it on any target application in Windows that you are able to change compatability mode of.
P.S. I am not sure if it makes a difference but I am running Windows 8 Pro. 64-bit.
This is by design. It is the lesser known twin of UAC, called UIPI or User Interface Privilege Isolation. An un-elevated program cannot commandeer an elevated one. Given the capabilities of UI Automation, this is an obvious counter-measure to stop programs from hijacking the capabilities of an elevated process. A security violation called a shatter attack.
Workarounds are to provide a manifest with uiAccess = true for a program stored in c:\windows or c:\program files and provided with a certificate. And for the target program to call ChangeWindowMessageFilter to allow certain messages to be sent. In your case that ought to be WM_SHOWWINDOW.
If you don't mind the window acting like you minimized it to the taskbar; You can, generally, show and hide windows from elevated processes by posting WM_SYSCOMMAND with a wParam of SC_RESTORE or SC_MINIMIZE.
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.
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