Execute uninstall with C# - c#

I've been looking around the internet for this, but I couldn't find it.
Is there a way to trigger an uninstaller (from the Programs and Features screen) via C#? Or is this blocked by Windows for security purposes?

You can use msiexec.exe. You can simply uninstall an application with its product code. Using command you can set whether to show UI during the uninstallation or make it a silent uninstallation,
string UninstallCommandString = "/x {0} /qn";
/qn: Set user interface level: None
/qb: Set user interface level: Basic UI
/qr: Set user interface level: Reduced UI
/qf: Set user interface level: Full UI (default)
C# code
string UninstallCommandString = "/x {0} /qn";
Process process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
process.StartInfo = startInfo;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardError = true;
startInfo.FileName = "msiexec.exe";
startInfo.Arguments = string.Format(UninstallCommandString, "Product Code");
process.Start();

Have a look at C# - Installing and uninstalling software and Programmatically Uninstall Programs With C#

You could invoke the executable file for the uninstaller using system.diagnostics.
Something like the following should do the trick:
System.Diagnostics.Process.Start("/path/to/uninstall.exe", "arguments for uninstaller if needed, else don't bother with this arg");
It's quick and dirty and /should/ work. Hope that helps.
edit- Just realised you want to do this from the add remove software screen. I'll leave this here anyway but my mistake.

Related

How to give a user the privilege to create symbolic links through C# or commandline?

I have a program I built in C# using WPF. It is reliant on the user having the ability to create symbolic links. After trying my software on a test machine I discovered normal users don't have this privilege by default.
Local Security Policy -> Local Policies -> User Rights Assignment -> Create symbolic links
The first run of the program requires it to be run as admin for setup but all subsequent runs it shouldn't need to be. During this first run I need to give the user this privilege. Can this be done from C# or can I launch a cmd or powershell process to do this?
I tried:
Process process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.FileName = "powershell.exe";
startInfo.Arguments = "secedit /export /cfg c:\\secpol.cfg; (gc C:\\secpol.cfg).replace(\"SeCreateSymbolicLinkPrivilege = \", \"SeCreateSymbolicLinkPrivilege = " + Environment.UserName +",\") | Out-File C:\\secpol.cfg; secedit /configure /db c:\\windows\\security\\local.sdb /cfg c:\\secpol.cfg /areas SECURITYPOLICY; rm -force c:\\secpol.cfg -confirm:$false";
startInfo.CreateNoWindow = true;
startInfo.Verb = "runas";
process.StartInfo = startInfo;
process.Start();
Process.Start("shutdown.exe", "-r -t 30 -c \"To use this program your computer must be restarted...\"");
The commands run successfully in PowerShell but after a reboot the Local Policy remains unchanged. Checking the log revealed that the registry values in secpol.cfg had applied successfully. I'm wondering if secedit can't change the policy I need to change since it doesn't have a registry key associated with it. I'd like to resolve this so I don't have to ask the user to manually change the setting. Any help would be appreciated.
There were two things I had to fix above.
The first is an issue escaping the double quotes in the powershell argument. To solve that I just changed them to single quotes.
The second issue is that I was using /areas SECURITYPOLICY when SeCreateSymbolicLinkPrivilege was actually in /areas USER_RIGHTS. Because we are just importing a configuration file created on the same system from moments ago I figure it's not necessary to use /areas at all so I just removed it.
The final code is:
// Allow user to create symbolic links
Process process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.FileName = "powershell.exe";
startInfo.Arguments = "secedit /export /cfg c:\\secpol.cfg; (gc C:\\secpol.cfg).replace('SeCreateSymbolicLinkPrivilege = ', 'SeCreateSymbolicLinkPrivilege = " + Environment.UserName + ",') | Out-File C:\\secpol.cfg; secedit /configure /db c:\\windows\\security\\local.sdb /cfg c:\\secpol.cfg; rm -force c:\\secpol.cfg -confirm:$false";
startInfo.CreateNoWindow = true;
startInfo.Verb = "runas";
process.StartInfo = startInfo;
process.Start();
Process.Start("shutdown.exe", "-r -t 30 -c \"To use this program your computer must be restarted...\"");
Of course if you want to use this code for a production app you'll want to ask the user for permission before changing this setting as #BionicCode mentioned and you'll want to handle the reboot better.

How to uninstall a program using product code in C# code or via command line

I have an installer project for VS 2019 and it has a product code + update code available, so in my application I am using it to uninstall the application programatically. Everywhere I looked this appears to be the right way to call msiexec and provide the product code but all I get is a popup window with info style output for msiexec and error code 1603. Even running it myself via powershell it does the same thing so is this no longer the correct way to uninstall something via command line? I would be happy to get it working in command line and can easily update code as well but nothing is working at the moment.
Referenced several other forum posts, codeproject site solutions, maybe this info is just dated or no longer accurate? Checked here most recently How to uninstall MSI using its Product Code in c#
Process process = new Process();
process.StartInfo.FileName = "MsiExec.exe";
process.StartInfo.Arguments = " /x " + productCode + " /Qn";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.UseShellExecute = false;
process.Start();
string output = process.StandardOutput.ReadToEnd();
string err = process.StandardError.ReadToEnd();
Debug.WriteLine(output);
Debug.WriteLine(err);
process.WaitForExit();
return (process.ExitCode == 0) ? true : false; //exit code 1603, popup appears from Start()

How do I force standard output on a C# Process when UseShellExecute == false?

I am running processes from C# using the following code;
private static void ExecuteShellCMD(string workingDir, string commandWithArgs, bool bWait = true)
{
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "runas";
info.FileName = "cmd.exe";
info.WorkingDirectory = workingDir;
info.Arguments = "/C " + commandWithArgs;
info.UseShellExecute = false;
using (Process myProcess = Process.Start(info))
{
if (bWait)
{
myProcess.WaitForExit();
}
int ExitCode = myProcess.ExitCode;
//Log exit code here.
}
}
It loads an elevated command window and executes the code/bat file I pass it, but without logging anything to the console. This doesn't appear to be consistent on other machines, and has worked in the past on my machine, and I wondered if anyone had any ideas about how I can consistently make this Process just print logs into the command window the process makes.
I can see logs if I set UseShellExecute = true but then can't use Verb without accepting the elevation prompt which is undesirable.
I have tried looking for solutions around the web, and I am aware that I can redirect the output using other settings. Most of the questions and tutorials on this subject seem to deal with redirecting the ouput to somewhere else but I want to be able to keep track of the progress in the command window itself.
Perhaps I have missed an command line argument or similar?
Turns out this was actually a bug in Unity Hub. The process and output were working fine, however when ran from a Unity instance that was launched from Unity Hub it took control of the output and didn't release it. This was solved by just launching Unity directly and a bug report has been filed against Unity hub.

Launching an OSX process without a dock icon

I have two Unity3D applications - one launched by the other, with a -batchmode argument on the launched one so it has no graphics.
On Mac OSX the launched process still gets a dock icon that sits there bouncing forever; clicking it does nothing since it's non-graphical, and I'd really like to remove it.
I've tried modifying the Info.plist with a LSUIElement entry to get rid of the dock icon. That works perfectly if I launch the application myself, but it still gets a dock icon when I launch it as a process.
My process launching code is a little unusual which mightn't be helping. This works on Windows and Linux but not OSX and I'm not sure why (C#, mono):
ProcessStartInfo proc = new ProcessStartInfo();
proc.FileName = path + filename;
proc.WorkingDirectory = path;
proc.Arguments = commandlineFlags;
process = Process.Start(proc);
I've only got it to launch on OSX with this specific setup:
ProcessStartInfo startInfo = new ProcessStartInfo("open", "-a '" + path + filename + "' -n --args " + commandlineFlags);
startInfo.UseShellExecute = false;
process = Process.Start(startInfo);
You will need MonoMac for this if you are not already using it, either the older open-source version or the commercial version (Xamarin.Mac).
In the Unity app that you are launching as a 'sub-process' from the first app add a project reference to MonoMac and add a using clause for MonoMac:
using MonoMac;
Then in your static Main function:
MonoMac.AppKit.NSApplication.Init ();
MonoMac.AppKit.NSApplication.SharedApplication.ActivationPolicy = MonoMac.AppKit.NSApplicationActivationPolicy.Accessory;
That will hide the application/process from dock and task switcher... Of course you can conditional skip that code if you are running on Windows/Linux.
Answering my own question, but adding these to the ProcessStartInfo removed the dock icon:
startInfo.CreateNoWindow = true;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
I'm not sure if both of those is actually needed, but there doesn't seem to be any harm.
A PList edit seems to be needed as well. Specifically I'm adding:
<key>LSBackgroundOnly</key>
<string>1</string>
As found here.

Visual C # process arguments not working

ok this was working the other day and now it's not... i don't remember changing anything, but i can run this reg.exe command with the arguments below from CMD and it works fine and creates the output file. but running it in VC# it does not create the file test_output.txt???
System.Diagnostics.Process proc_cmd = new System.Diagnostics.Process();
proc_cmd.StartInfo.FileName = #"c:\windows\system32\reg.exe";
proc_cmd.StartInfo.Arguments = #"query ""HKLM\Software\test\test software"" /v BuildNumber >c:\test\test_output.txt";
proc_cmd.StartInfo.CreateNoWindow = true;
proc_cmd.StartInfo.RedirectStandardError = true;
proc_cmd.StartInfo.RedirectStandardOutput = true;
proc_cmd.StartInfo.RedirectStandardInput = true;
proc_cmd.StartInfo.UseShellExecute = false;
proc_cmd.Start();
proc_cmd.Close();
You should use the Registry class instead.
Your >output.txt is an instruction to the command interpreter (cmd.exe). That won't work calling reg.exe. Consider calling cmd.exe instead, or redirecting the stdout and writing it to the file yourself. See this SO answer link.
Of course, if there's no compelling reason to shell out to the Reg.exe, you should use the Registry class.

Categories

Resources