Call an external program to run as standard user from a requiredAdministrator program - vb.net

My Visual Basic program will copy files to a program files folder, so I have to use requiredAdministrator privileges since asInvoker won't allow to write in the program files folder.
After I copy the files I invoke an AutoIt script automating setup of files within the external program (for that the script calls the external program to start automation). The program that creates and copies the files to the "end" program functions fine. The script that calls the "end" program and does the automatic setup also works.
When I combine the 2 the "end" program (which I didn't write nor have the source code of) behaves erratically when run as admin (doesn't read the database or the needed files return an error and terminates itself). So run as admin is not an option. But since my program has to run as admin it looks like it passes the sames privileges to the AutoIt script which calls the "end" program as admin as well. It also happens if I call the "end" program from my app instead of the AutoIt script.
Is there any way to demote my app from admin to standard user after it copies the files, right before it calls either the AutoIt script or the "end" program so that the "end" program is not run as admin or a parameter that specifically makes the app to call the external program as standard user?
I'm using Process.start("autoitscript.exe") to call it. Or any other workaround that doesn't involve the AutoIt script calling the "end" program and my app because that works but not as I intent.

This is a tricky task to perform, but how about this:
Have your application start asInvoker, don't show any windows, and make check if it runs with elevated privileges using this code:
Public Shared Function IsAdministrator() As Boolean
Return (New WindowsPrincipal(WindowsIdentity.GetCurrent())).IsInRole(WindowsBuiltInRole.Administrator)
End Function
If it's not running with elevated privileges make it start an invisible cmd instance where you redirect the standard input.
Get the cmd process's PID and now start a new instance of your application with elevated privileges (can be done by setting StartInfo.Verb = "runas") and pass the PID as a command-line parameter.
Now your new instance of the app starts and IsAdministrator() should return True.
So now that you know that your app has administrator privileges you can check if the app has a command-line parameter that is parsable to an Integer. If so, store that Integer somewhere and then do all your admin-required work.
In the end where you want to start the autoitscript.exe application you create a process variable and assigns Process.GetProcessById(<your PID Integer here>) to it.
For example:
Dim cmdProcess As Process = Process.GetProcessById(cmdPID)
Now that you have control over the cmd instance again you just have to write to it's standard input (this article describes a little how it works).
You want to write two lines. The first is to start the other application:
autoitscript.exe
and the second is to close the cmd instance:
exit
If anything's unclear just let me know.

Related

Is it possible to have .net console application that embed another executable file?

I have a single command line windows executable that has many options built into this exe file.
Eg:
(It can take screenshot)
ToolGo.exe printscreen c:\temp\filename.jpg yyyymmdd
(It can show up)
ToolGo.exe showIP machineA
I want to write another command line application, possibly in .net , where it can embed/build a wrapper around this ToolGo.exe file into my application without the user be able to use the ToolGo.exe, and also users can only access one function of this main exe file.
In the example I want this other tool to access only the print screen function in this new exe file.
The new application will have this:
Tool2go.exe printscreen c:\temp\filename.jpg yyyymmdd
But if someone types the following, it will not work:
Tool2go.exe showIP machineA
Or
ToolGo.exe showIP machineA
Any ideas how I can write this code to do this in a .net command line application?
This is a multi-part question, so I'll just give the main part of the issue as the answer with suggestions on handling the rest.
You can embed a .exe into your program by clicking on Properties and navigating the the Resources section, and adding that .exe to it.
After that, it's just a matter of extracting it locally so you can pass your commands to it, and handle it's responses. (I'm not really aware of any way to do so w/out first extracting the. exe; the .exe itself needs to run somehow after all).
To extract the embedded .exe, you do this:
' Extract the MyProgram resource (i.e. your .exe)
Dim b() As Byte = My.Resources.MyProgram
' Write it to the user's Temp folder
File.WriteAllBytes(Environment.ExpandEnvironmentVariables("%TEMP%\MyProgram.exe"), b)
By extracting it to the user's Temp folder, you can pass it your commands, and since it's 'out of sight' the user probably won't even know it's there to directly use it themselves, unless they're a bit more advanced and visit their Temp folder often. You can slightly help to avoid this, but extracting the .exe when your program starts, and then deleting it when it exits, so it only exists on the user's system while your program is running.
As far as what the user can and cannot type in order to pass to the program, you can simply handle the filtering with your program; since your program is the one passing the commands to the .exe, just don't pass any commands that you don't allowed, and pass the ones you do want allowed.

Auto-start my program in administrative mode when system starts up without the UAC prompt

My problem :
I made a program and i have this program for example now under this directory : "C:\Program Files (x86)\AppName", now in the program i'm saving some images in my program directory, but since this is in the C drive, it's giving me a access denied error, now i made the program to always run in administrative mode and that worked just fine, but also there is in my program a feature to auto-start my program when the system starts up using a registry key, but when the "always run in administrative mode" is ON, the program will not start even though there is a start-up key in the registry, and when the "always run in administrative mode" is OFF, it will start.
What I have tried so far :
I tried making an another executable file that will start when the system starts up and then it will run my main program and close it self and i knew that will work but now every time i start my computer, the User Access Control prompt ask me if i trust this program even and that is not very user-friendly.
So i searched and i found that i can create scheduled task but i didn't find a lot of examples and but i tried creating one manually and it did work as wanted!
But here is a code which didn't work :
Imports Microsoft.Win32.TaskScheduler
Using ts As New TaskService("\\RemoteServer")
'Create a new task definition and assign properties
Dim td As TaskDefinition = ts.NewTask()
td.RegistrationInfo.Description = "Does something"
'Create a trigger that will fire the task at this time every other day
td.Triggers.Add(New DailyTrigger() With {
Key.DaysInterval = 2
})
'Create an action that will launch Notepad whenever the trigger fires
td.Actions.Add(New ExecAction("notepad.exe", "c:\test.log", Nothing))
'Register the task in the root folder
ts.RootFolder.RegisterTaskDefinition("Test", td)
End Using
And the problem with the code is :
It couldn't find the TaskService and it has no use of the TaskScheduler library!
Hope someone have some previous experience with that who can help me!
To answer your question:
To use that code you've got to download the Managed Task Scheduler Wrapper first. Then to make it run with administrative privileges you've got to set the RunLevel to TaskRunLevel.Highest on your TaskDefinition:
td.Principal.RunLevel = TaskRunLevel.Highest
However like Plutonix says you shouldn't be writing files to the directory of your program (as that's usually located in the restricted %ProgramFiles% folder).
Instead, use the %ProgramData% directory. You can get the path to it from your code via Environment.GetFolderPath():
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)
'Example:
Dim ConfigPath As String = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "AppName")
Dim ImagePath As String = Path.Combine(ConfigPath, "MyImage.png")
If Directory.Exists(ConfigPath) = False Then Directory.CreateDirectory(ConfigPath)

Running application as System (without PSTools)

There are some registry keys that are owned by System, and I can't edit them unless I run as System. I want to be able to edit these keys from my VB application. Any tutorials I've found suggest using PSTools, the now deprecated At command, or schtasks. PSTools seems great, but its license seems to restrictive (about redistributing). At and schtasks are too messy, and require scheduling delays.
This is related to my previous question. I want to take what I discovered, and implement it via VB.
Modify audit policy (group policy)
I also found this, but am getting error 1314. I realized despite running VS2010 "requireAdministrator", and even Running my EXE as Administrator, it still says my username in Task Manager (running as me, not Administrator). I logged in as Administrator, and got Error 5 instead. Even after ensuring I had the rights set, as suggested by this post (CreateProcessAsUser error 1314), it still gave me Error 5.
Using a vb.net application running as SYSTEM, how do I start a detached process for each logged on user?
I changed the example to "TokenAccessLevels.Read and Duplicate" rather than MaximumAllowed.
If Not DuplicateTokenEx(hToken.DangerousGetHandle,
TokenAccessLevels.Read & TokenAccessLevels.Duplicate,
Nothing,
SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
TOKEN_TYPE.TokenPrimary,
phNewToken) Then
I get Error 5 from CreateProcessAsUser. This is while running VS2010 as Administrator.
http://forum.sysinternals.com/tip-run-process-in-system-account-scexe_topic16714.html
This post was the best I could do. Basically, install a service, run it, then delete it. According to the OP, this is his explanation.
So how does it work?
The & symbol tells cmd.exe to parse treat the text that follows as if it were a new line in a batch file (It basically is a new line
delimiter which allows multiple commands to be combined into 1 line)
To break it down: Create Service - sc create -- binPath= "cmd /c start
calc" type= own type= interact Start Service net start -- (This could
also be done with: sc start --) Delete Service sc delete --
Variables
Service Name: --
App to run: calc
Variables:
How it works:
cmd /c - allows us to pass in parameters to cmd (Without this initial
part, it will work if you copy & paste in cmd.exe, but not in the Run
Dialog. So this fixes it) sc create binPath= - Since cmd.exe does not
respond to service commands, when the SCM runs the app in binPath (Reg
= ImagePath) then it will terminate it, when not responding in a timely fasion, therefore cmd.exe cannot be used. It has to call
something else which in this case is calc.exe sc create type= This one
took a while to figure out. The inital problem is the Window Station
in which cmd.exe is launched in (which in turn is inherited by
calc.exe (its child process)). Luckily after reading Mark's Windows
Internals e4, I was able to solve it by specifying the service as
being Interactive. (Experimenting, it actually has to be BOTH
interactive(256) and own(16) (256|16 = 272) . Basically what this
allows is for the windows to run in \WinSta0\Default (The current
user's desktop, allowing the window to be displayed.) After some
research from being frustrated that sc would not accept type
=own|interact, I found out that it allows us to specify it again, and instead of overwriting Type (dword) it bitwise-ORs it (Adds it).
Problems Solved! net start - start the service (probably calls
StartService) cmd.exe runs with the command line (CL) of start [File]
in which start probably calls ShellExecute (Its ashame that MS didn't
allow start to specify a SW_* commands (like hide). Although it does
allowing us to min/max windows. cmd.exe opens the app/file, the SCM
terminates cmd.exe for not responding in a timely fashion to its
commands, and the window is now shown to the user. sc delete - Finally
we clean up our path by removing the service
For me, this worked.
cmd /c sc create -- binPath= "cmd /c start app.exe" type= own type= interact & net start -- & sc delete --
Now, I had trouble with getting absolute paths to work. I had to put my .EXE in System32 and SysWOW64, so I didn't have to use an absolute path. According to the site, this is supposed to allow absolute paths to work.
cmd /c sc create -- binPath= "cmd /c start \"\" \"C:\windows\regedit.exe\" " type= own type= interact & net start -- & sc delete --
It never worked for me, as it would hang for some time and never start the app. It should almost instantly complete.

Vb.Net win forms application not running on all computers

I have wrote a win forms application in VB that requires some external DLLs, It installs and runs flawlessly on several machines but it does not work on one laptop! I even put Filestreams to write exceptions to a text file. While it writes intended header text to the debug file on other computers, it does not write anything to the debug file on the aforementioned laptop. My guess is that it does not even reach Form1_Load() method.
This is the structure of the program:
Import namespaces from external programs
Public Class MyApp
''Varibale declarations:
Structures and classes based on DLLs
Other declarations based on .Net Objects
Stream writer declaration and initialization for the debug file
Private Sub Form1_Load(...)
Try
Write Start and time to the debug file
execute commands
catch
write debug info
end Try
End Sub
Other events and subs
End Class
IS there a way to see what happens between the initialization of the debug file and execution of Form1_Load() ??
As I said it works perfectly on all the machines that use this except one!!
What are the things that I need to check on that machine?
Chances are that the user of the laptop is not in the Administrators group and you're trying to write to the application program folder.
Have you tried to add a placeholder line in the debug file immediately after initialization, to check that the file is actually write-able?
Is the Form's constructor reachable? If you move the "Write Start and time to the debug file" code to the constructor, does it write anything?

Why is "My" namespace unavailable?

Our Winform app consists of a Main.exe and a Launcher.exe. The purpose of the Launcher app is to check for updated versions of the Main.exe.
If it finds no updates it launches Main.exe using System.Diagnostics.Process.Start
If it finds an update, it copies the new Main.exe into position and launches Main.exe the same way (in this case it will be a fresh copy of Main.exe).
Here's the Process.Start code:
Dim p As New ProcessStartInfo
p.FileName = "Main.exe"
p.WindowStyle = ProcessWindowStyle.Normal
Process.Start(p)
This code executes whether or not there's been an update and always successfully fires up Main.exe.
However our Main.exe, if it's being run for the first time (ie. after an update), will error on any line which references the My namespace, such as My.Settings or My.Computer.FileSystem
For example this line will cause an error:
Msgbox(My.Computer.FileSystem.SpecialDirectories.Desktop)
Here's the error:
System.IO.DirectoryNotFoundException:
Could not find special directory
'Desktop'. at
Microsoft.VisualBasic.FileIO.SpecialDirectories.GetDirectoryPath(String
Directory, String DirectoryNameResID)
at
Microsoft.VisualBasic.FileIO.SpecialDirectories.get_Desktop()
at
Microsoft.VisualBasic.MyServices.SpecialDirectoriesProxy.get_Desktop()
But while this example refers to Desktop remember it can't find any of the SpecialDirectories. It's not restricted to Desktop.
But only the first time it's run (ie. immediately after an update). Thereafter it will run fine.
If the process failed more spectacularly, to do with file system issues, locks or threads, it would be more understandable. But why just this "minor" problem with the My namespace?
I realise now it was nothing to do with the copied file and everything to do with a badly implemented System.Security.Principal.WindowsImpersonationContext.
Amazing how these things become clear 5 minutes after posting.