Execute several elevated commands in shell (or similar) - c#

I have a requirement to execute several commands with elevated rights, something like:
call program that modifies a .config file of a service (needs admin rights)
net stop myservice (needs admin rights)
net start myservice (needs admin rights)
All of this dynamic, e. g. the first line could contain proxy settings, including user name and password, or any other modification to the settings file. (Settings file is in program folder, program to modify the settings file is externally provided. The actual info would be user entered through a GUI.)
I thought to create a very flexible solution, using a cmd.exe process with redirected stdin and stdout. But.. it looks like "runas" (needs ShellExecute) and redirected in-/output are exclusive.
(Also, I noticed that redirection and cmd.exe are quite hard to handle.. I had to write my own functions e. g. as a replacement for ReadLine, since the ReadLine expects a NewLine at the end and waits e. g. if there is a command prompt (meaning you have text in the line like c:\bla> but no NewLine. Still, not knowing what one gets as a result makes writing something generic difficult.)
There are 3 alternatives I can think of:
get the UAC prompt for every single command (I would not like that)
start a process that is elevated, this can then call whatever it wants -> needs an additional project (.exe) which I would like to avoid, also makes deployment more difficult (additional file)
create a batch file on the fly, run it elevated. This I also want to avoid, since there could be password information in plain text in that file (e. g. user/password for proxy). I would at least have to make sure to always overwrite its contents and then delete it.
How to handle this?

I think you've already diagnosed the issue, and enumerated your available options. To my mind the best option is to use runas to create a new elevated process, and get that process to do the work.
The other process need not be a different executable it could be your existing executable started with particular command line arguments. Once you have another process running elevated, you can certainly use cmd with redirected stdin/stdout to do the work. However, why use net stop/start rather than the service API? And can you do the .config file modification without starting a separate process?

Related

How to programmatically determine which process created a file in .net?

There are several threads on SO that describe how to check which application creates a file with tools like Sysinternals process monitor. Is something like this possible programmatically from .net?
Background: My program has to remote-control a proprietary third party application using its automation interface, and one of the functions I need from this application has a bug where it creates a bunch of temporary files in %TEMP% that are called tmpXXXX.tmp (the same as .net's Path.GetTempFileName() does) but does not delete them. This causes the C drive to become full over time, eventually failing the application. I already filed a bug to the manufacturer, but we need a temporary workaround for the time being, so I thought of putting a FileSystemWatcher on %TEMP% that watches tmp*.tmp, collects these files, and after the operation on the third-party application finishes, deletes them. But this is risky as another application might also write files with the same file name pattern to %TEMP% so I only want to delete those created by NastyBuggyThirdPartyApplication.exe.
Is this anyhow possible?
This kind of things is possible, but maybe a bit tricky.
To know who created the file, look at the user that owns it. Therefore you might need to create a specific user, and that application will run under this specific user. In order to do that, you need to create a small application that will start your buggy app by impersonating another user, so anything done within the app will be under this user so as file creating...
I don't know how to monitor and get triggered when a file is created, but nothing can prevent you from setting a timer that wakes up every five or ten minutes, then checks if any file in the directory is owned by the application user and closed, so it deletes it.
Maybe if they react fast for this bug fixing, you won't need your app very long time. So another solution, if possible might just to change the Temp folder into another drive, which has lots of space...
One solution is that you use a FileWatcher to automatically delete all the files but before deleting you should check if the file is not currently locked or used by other process, for example the Sysinternal Suite has a tool called handle.exe that can do this. Use it from the command line:
handle.exe -a
You can invoke this from a c# program (there might be some performance issues though)
So what you would do is when a file is created you verify if it is in use or locked (for example u can use the code provided in Is there a way to check if a file is in use?) and then delete it.
Most of the time when an app is using a temp file it will lock it to prevent just what you fear, that you might delete files from other processes.
As far as I can tell there is no sure way to identify which process created a specific file.

using CreateProcessAsUser to launch a url

Recently I bumped into an issue where I need to open a webpage from an elevated application. I need the browser to be opened non elevated so I looked around and found this solution
This would definitely solve my issue except that CreateProcessAsUser does not accept URIs as a filename, the execution will fail with the error message being "The filename, directory name, or volume label syntax is incorrect"
Can someone tell me if there is a way to launch a website through CreateProcessAsUser or if there is a similar API that does the job.. Please note that my actual application is always elevated and thus I cannot uses the usual Process.Start(), CreateProcess() or ShellExecute()
There are two distinct families of functions that you will need to use to get this task done:
CreateProcess and related functions. These can be used to start a new process. You must supply a filename of an executable image.
ShellExecute and friends. These will apply verbs to files using the shell's rules for associating file classes to executables.
In order to open a URI you need to use one of the ShellExecute family. And in order to execute as a standard user from your elevated process, you need to use one of the CreateProcess family.
You cannot meet both your requirements with a single function. Your solution therefore is to use one of the CreateProcessXXX functions to create a process that runs as standard user. That process in turn will call ShellExecuteXXX. You will pass the URI as command line arguments to CreateProcessXXX.
You will therefore need to either create a distinct executable as your standard user launcher. Or re-use your existing executable but make it switch into launcher mode depending on the arguments that you pass it.

Generate an .exe file with embedded settings

I have a window application which performs some tasks, One of which is opening some files and we all know .net provides exe file for the application, which can be used as click to start.
I am calling this application application1.
Now I want to generate one more window application(simple exe), let us call it application2, which will open a form with some options(say the names of the files to be opened by application1) and a generate button.
On clicking the generate button, it should generate the exe file for the application1 with the data passed from application2.
Please suggest how can I do it.
EDIT
I need to generate exe which will be available on different systems which will perform some task on regular intervals. and the interval colud be different for different computers.
so I am asked to generate which will accept the time interval and will generate the exe for that interval
There are a number of ways to consider doing this:
use a reg key with the name of the settings file to read in, and then store the settings you write from app2, for app1 in the file, so app 1 can run it
you call app1 with a parameter with either the name of a file, or commandline parameters, and it updates its own applications settings file.
put the settings in a database, so any copy of app1 anywhere can find it, assuming all users would be able to see the db server
if app1 is always to be running while app2 is you could go with some interprocess communication but probably this is the more complex of the 4
Rather than recompiling an exe, it would make sense to have a config file that goes with.
Failing that, compiling .net is only that, you can have an exe that generates a .cs file (or updates one, and reruns the whole compile and outputs an exe.. take a google, on command line compilation) but I wouldnt be my choice.
I think what your looking for is for application1 to be able to receive command line arguments and application2 to allow you to pick files and run application1 and pass in those arguments.
I don't think its wish to be generating .exe's
Another way, although not that easy, would be to
write application 1 to try and read settings from class that does not exist, say SettingsOverride, by reflection; if not found, fall back to its own hard-coded settings
application 2 uses CodeDOM or similar to create a new assembly that provides a SettingsOverride class with the new saved settings
application 2 uses ILMerge to build the new .exe from application 1 and the settings assembly; the reflection code in application 1 should now pick up the new settings.
It's probably also possible to do this with embedded resources, though I'm not sure how. Finally you could put a string constant in your .exe, say 400 X characters, and then application 2 could scan the file to find that (as Unicode/UTF-16 text) and replace that with a string containing the new settings - but I'm not 100% if you then need to recompute a checksum or similar.

How to check if application runs from \program files\

Is there a reliable method to check if an application is run from somewhere beneath program files?
If the user installs the application to program files on local machine, we need to put writable files somewhere else to avoid virtualization on Vista and Win7. When installed to a network disk, though, we want to keep these files with the installation for shared access among users.
Today we do an string comparison between startup path and CSIDL_PROGRAM_FILES, but something tells me this is a very unreliable method.
Any smart solution out there?
Is there a 'IsRunningFromProtectedFolder( )'-api that I do not know about?
Are there any other folders giving the same problems as program files do?
This is not a terribly good idea, as a user can install it wherever they want to, and then the check might fail. Instead have a checkbox when the user installs the app, deciding if it is installed locally or on a server.
As you I also found problems dealing with UAC folder virtualization.I suggest a workaround, it seems that it should work.
It comes from the assumption that elevated processes always use original copies and not the virtualized ones (CMIIW). Also I assume that you setup processed was executed elevated
The idea is to create a "general" process (non-elevated, legacy), that your main installer should run. This process will create a file name in the user chosen folder with a name and contents that both your programs know (for example, test73819704.bin). If the folder virtualized, this file should appear in the user VirtualStore and SHOULD NOT in the original one (from the point of view and privileges of the installer).
So for chosen C:\Program_Files_But_Not_Necessarily and Process-1 (elevated)
Process-1 ensures there's no file C:\Program_Files_But_Not_Necessarily\test73819704.bin
It launches Process-2 with no elevation
Process-2 creates C:\Program_Files_But_Not_Necessarily\test73819704.bin and checks whether it really exists. If exists it would return with a good return code, otherwise with a "failed" one.
Process-1 waits for Process-2 and analize the result. If good, checks for C:\Program_Files_But_Not_Necessarily\test73819704.bin, if it exists, go for "Bingo! No virtualization occured", if doesn't exist, "Bad, let's find some other storage place". If the code from the Process-2 is "failed" one, show the user some error message.
Unfortunately I could not test it right now, but I guess it should work and there's a logic behind this, with Process-2 you just emulate the behavior of your main program )
We allow our users to install anywhere...
If the user has taken the default, and is installed in Program Files, we make the assumption that we need to write to Documents and Settings/Users. Otherwise, we write our data to a folder under the directory the software is in. This of course can still cause problems, and the install does indeed allow people to choose a different data location if they choose to not go for the default.
On top of that, it's a simple ini file change and a copy to move the data.
On start up we detect if we are in the Program Files directory by comparing the value we obtain from SHGetFolderPath(CSIDL_PROGRAM_FILES) with the start of the path the executable is in.

Allow access permission to write in Program Files of Windows 7

My application throws 'Access denied' errors when writing temporary files in the installation directory where the executable resides. However it works perfectly well in Windows XP. How to provide access rights to Program Files directory in Windows 7?
EDIT:
How to make the program ask the user to elevate rights? (ie run program with full admin rights)
Your program should not write temporary files (or anything else for that matter) to the program directory. Any program should use %TEMP% for temporary files and %APPDATA% for user specific application data. This has been true since Windows 2000/XP so you should change your aplication.
The problem is not Windows 7.
You can ask for appdata folder path:
string dir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
or for TEMP path
string dir = Path.GetTempPath()
Your program has to run with Administrative Rights. You can't do this automatically with code, but you can request the user (in code) to elevate the rights of your program while it's running. There's a wiki on how to do this. Alternatively, any program can be run as administrator by right-clicking its icon and clicking "Run as administrator".
However, I wouldn't suggest doing this. It would be better to use something like this:
Environment.GetFolderPath(SpecialFolder.ApplicationData);
to get the AppData Folder path and create a folder there for your app. Then put the temp files there.
Options I can think of:
Run entire app as full admin priv. using UAC
Run a sub-process as full admin for only those things needing access
Write temporary files elsewhere
Add new item in the project: Application Manifest and save it.
Now open this file and look for <requestExecutionLevel>. It must be set to asInvoker.
Change it to highestAvailable. Now on executing your application, a prompt will appear asking for permission. Click yes!
Thats all :) now you can write and read from the system32 or any other file which requires admin right
You can verify your application by sigcheck.
sigcheck.exe -m yourapp.exe
And in the output check for element requestedExecutionLevel.
Another way round it would be to stop UAC then restart it. Create a CMD file with the following code;
Rem Stop UAC
%windir%\System32\reg.exe ADD HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA /t REG_DWORD /d 0 /f
rem force reboot
Start ShutDown /R /F /T 30
You'll need to right click on the CMD file and use run as admin. once you have finished what you are doing restart UAC with the following code (no need to use run as admin this time);
%windir%\System32\reg.exe ADD HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA /t REG_DWORD /d 1 /f
rem force reboot
Start ShutDown /R /F /T 30
The down sides to using this method is have to right click and use run as admin to close UAC down and you have to reboot for it to take effect.
BTW there are several reasons why you would need to write to the forbidden areas...the first two that springs to mind would be to run a batch file to append host to prevent your browser going to dodgy sites or to copy license keys in a silent install.
You can't cause a .Net application to elevate its own rights. It's simply not allowed. The best you can do is to specify elevated rights when you spawn another process. In this case you would have a two-stage application launch.
Stage 1 does nothing but prepare an elevated spawn using the System.Diagnostics.ProcessStartInfo object and the Start() call.
Stage 2 is the application running in an elevated state.
As mentioned above, though, you very rarely want to do this. And you certainly don't want to do it just so you can write temporary files into %programfiles%. Use this method only when you need to perform administrative actions like service start/stop, etc. Write your temporary files into a better place, as indicated in other answers here.
I cannot agree with arguments, that it is better to write all files in other directories, e.g., %APPDATA%, it is only that you cannot avoid it, if you want to avoid running application as administrator on Windows 7.
It would be much cleaner to keep all application specific data (e.g. ini files) in the same folder as the application (or in sub folders) as to speed the data all over the disk (%APPDATA%, registry and who knows where else). This is just Microsoft idea of clean programming. Than of course you need registry cleaner, disk cleaner, temporary file cleaner, ... instead of e+very clean practice - removing the application folder removes all application specific data (exep user data, which is normally somewhere in My Documents or so).
In my programs I would prefer to have ini files in application directory, however, I do not have them there, only because I cannot have them there (on Windows).
I think there is an alternate solution to all these problems....
Make an two level application. As said above...
1) Launcher which will launch another Main App using code such as (VB)
Call ShellExecute(hwnd, "runas", App.Path & "\MainApp.exe", 0, 0, vbNormalFocus)
2) Main App, which is writing to protected areas, ie Program Files folder
I've successfully tried this with windows 7
I'm also developing an app which has online update feature. But it doesn't work in Vista/W7..
I agree with other peoples about Microsoft Policies and Standard Practices.
But my Question is ..
1) How to apply update to an existing application, which probably always remain in Program Files folder.
2) There might be some way to do this, otherwise how goolge updater, antivirus updater or any software updater workes?
I need answer to my questions..... :o
Prof. Rajendra Khope
(MIT, Pune, India)
If you have such a program just install it in C:\, not in Program Files. I had a lot of problems when I was installing Android SDK. My problem got solved by installing it in C:\.
I was looking for answers. I found only one.
None of these work for me. I am not trying to write temporary files, unless this is defined as nonsystem files. Although I am designated the admin on my user profile, with full admin rights indicated in the UAC, I cannot write to program files or windows. This is very irritating.
I try to save an image found online directly to the windows/web/wallpaper folder and it won't let me. Instead, I must save it to my desktop (I REFUSE to navigate to "my documents/pictures/etc" as I refuse to USE such folders, I have my own directory tree thank you) then, from the desktop, cut and paste it to the windows/web/wallpaper folder. And you are telling me I should do that and smile? As an admin user, I SHOULD be able to save directly to its destination folder. My permissions in drive properties/security and in directory properties/security say I can write, but I can't. Not to program files, program files (86) and windows.
How about saving a file I just modified for a game in Program Files (86) (name of game) folder. It won't let me. I open the file to modify it, I can't save it without first either saving it to desktop etc as above, or opening the program which is used for modifying the file first as admin, which means first navigating all the way over to another part of the directory tree where I store those user mod programs, then within the program selecting to open file and navigate again to the file I could have just clicked on to modify in the first place from my projects folder, only to discover that this won't work either! It saves the file, but the file cannot be located. It is there, but invisible. The only solution is to save to desktop as above.
I shouldn't have to do all this as an admin user. However, if I use the true admin account all works fine. But I don't want to use the real admin account. I want to use a user account with admin rights. It says I have admin rights, but I don't.
And, finally, I refuse to store my portables in %appdata%. This is not how I wish to navigate through my directory tree. My personal installations which I use as portables are stored in the directory I create as a navigation preference.
So, here is the tried and true answer I have found:
From what I have seen so far.... unless one uses the real admin account, these permissions just aren't ever really available to any other user with admin privileges in the Windows Vista and Windows 7 OS's. While it was simple to set admin privileges in Windows XP, later versions have taken this away for all but those who can comfortably hack around.
While M$ "best practices" is to not write data into the %programfiles% folder; I sometimes do. I do not think it wise to write temporary files into such a folder; as the TEMP environment variable might e.g. point to a nice, fast, RAM drive.
I do not like to write data into %APPDATA% however. If windows gets so badly messed up that one needs to e.g. wipe it and reinstall totally, perhaps to a different drive, you might lose all your settings for nearly all your programs. I know. I've done it many times. If it is stored in %programfiles%, 1) it doesn't get lost if I e.g. have to re-install Windows on another drive, since a user can simply run the program from its directory, 2) it makes it portable, and 3) keeps programs and their data files together.
I got write access by having my installer, Inno Setup, create an empty file for my INI file, and gave it the users-modify setting in the [Files] section. I can now write it at will.
I am working on a program that saves its data properly to %APPDATA%, but sometimes, there are system-wide settings that affect all users. So in these situations, it HAS to write to the programs installation directory.
And as far as I have read now, it's impossible to temporarily get write access to one directory. You can only run the whole application as administrator (which should be out of the question) or not be able to save that file. (all or nothing)
I guess, I will just write the file to %APPDATA% and launch an external program that copies the file into the installation folder and have THAT program demand admin privileges... dumb idea, but seems to be the only practical solution...
You can add an access to IIS User for folders of Website or Web Application that you want write or rewrite in it.
It would be neater to create a folder named "c:\programs writable\" and put you app below that one. That way a jungle of low c-folders can be avoided.
The underlying trade-off is security versus ease-of-use. If you know what you are doing you want to be god on you own pc. If you must maintain healthy systems for your local anarchistic society, you may want to add some security.

Categories