msi will not execute with processStart - c#

Running install programs from the c# code I can successfuly install .exe files and uninstall both exe and msi files... however whenever launching an msi for installation it just sits there and never does anything....
start = new ProcessStartInfo("msiexec.exe", "/i \"" + tempDir + "/" + s.executable + "\"");
start.WindowStyle = ProcessWindowStyle.Hidden;
start.CreateNoWindow = true;
Process.Start(start).WaitForExit();
can anyone spot my mistake. I understand the wait for exit will wait indefinatly and that is fine as there will be 10-12 installs going synchronously but It never actually installs.....

I had a look of msiexec.exe document. It seems that it only works with *.msi file. I tried your code with msi file, it works well.
There is a minor problem with your code. The directory path should be the other way around.
start = new ProcessStartInfo("msiexec.exe", "/i \"" + tempDir + "\\" + s.executable + "\"")

You have to tweak your command line on several issues to be optimal, and mainly to be supportable.
Don't use the ProcessWindowStyle.Hidden Option here. You don't need to.
As long as you are testing , use the "/qb" parameter.
For release, if you want no dialog, just use "/qn"
I think using not /qn but forbidding to open the window can be the source of the problem.
Assure that your program is already started with admin rights, otherwise you will have a more complicated UAC situation under Vista, Win7 ff. and you really need the dialog to allow the UAC dialog. If your program is already started with admin rights, you can use "/qn" and have other simplifications of scenarios which I would recommend for beginners to MSI.
Use logging.
Using backslashes in Windows is safer although slashes may work sometimes too.
=> I would recommend a resulting command line like this.
string msicmd;
msicmd="msiexec.exe /i \"" + tempDir + #"\" + msifile + #"\" /qb /L*v \"tempDir\mylogfile\"");
// Show a trace of this command line to debug it in case of errors :-)
...

Related

Trying to uninstall an application but getting an error

At work I have to uninstall the same application several times per day (and reinstall new versions). I'm trying to make a C# program that I can run that will do this all for me. Right now, I'm stuck on the uninstall process.
The code I have runs and attempts to uninstall the application, but Windows gives me an error during this.
Here's what I have right now:
static void Main(string[] args)
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
const string prodName = "myApp";
Console.WriteLine("searching...");
foreach (ManagementObject wmi in searcher.Get())
{
if (wmi["Name"].ToString() == prodName)
{
Console.WriteLine("found");
string productCode = "/x {" + wmi.Properties["IdentifyingNumber"].Value.ToString() + "}";
Process p = new Process();
p.StartInfo.FileName = "msiexec.exe";
p.StartInfo.Arguments = productCode;
p.Start();
Console.WriteLine("Uninstalled");
break;
}
}
Console.ReadLine();
}
This is the error I get when it tries to do the uninstall:
"This installation package could not be opened. Verify that the package exists and that you can access it, or contact the application vendor to verify that this is a valid Windows Installer package"
Uninstall Reference: This old answer might have what you need: Uninstalling an MSI file from the command line without using msiexec. It shows various ways to uninstall an MSI.
DTF: The DTF (Desktop Tools Foundation) included with the WiX toolset can be used to uninstall. Here is some sample C# code:
Uninstalling program
- run elevated, quick link to sample.
VBScript / COM: Here are some links to VBScript samples and various ways to uninstall (uninstall by product name, uninstall by upgrade code, etc...): WIX (remove all previous versions) - the uninstall by upgrade code (sample code towards bottom) is interesting because it generally works for all versions and incarnations of your installer (upgrade code tends to remain stable across releases).
CMD.EXE: Personally I might just use an install and an uninstall batch file. More of these samples in section 3 here. Just create two different files:
Install: msiexec.exe /i "c:\Setup.msi" /QN /L*V "C:\msi.log" REBOOT=ReallySuppress
Uninstall: msiexec.exe /x "c:\Setup.msi" /QN /L*V "C:\msi.log" REBOOT=ReallySuppress

C# MsiExec installs program to a wrong location

I am using a C# code to install a program using a process which runs the msiexec, giving it the path to the MSI file.
This is the code I use:
string pathtoMsiFile = "\"" + msiPath + msiName + "\"";
Process p = new Process();
p.StartInfo.FileName = "msiexec.exe";
p.StartInfo.Arguments = "/i " + pathtoMsiFile + " /quiet";
p.Start();
p.WaitForExit();
The strange thing is that when I try to install the program, for a certain version it installs it to the correct location I would expect to on C:\path but a different version it installs to D:\path for some reason. If I open the MSI itself manually, the default location there is C:\path. Any idea why?
Eventually it appears the problem is with the program the msiexec tried to install.
I am not that program's developer so I couldn't know the problem in advanced on my own.
The program had a custom action in its installation that set a variable representing the drive to install on as the one where the OS is installed. The problem is, that this action was invoked only through the installation's UI (when double clicking the MSI), but not when using a quiet CLI command to install it.

Accepting EULA for a quiet install of EXE file

I am working on packaging up some installers for internal use. I have the uninstall working fine with a passive switch.
As for installation, the MSI's that do not have an EULA work perfectly with the passive switch showing progress.
The EXE's that contain an EULA are the problem.
I am trying to find a way to accept the EULA without user input - note I do not have access to changing the public properties of the EXE's to set the ACCEPTEULA=1
the base I am working with right now is...
start = new ProcessStartInfo();
start.WindowStyle = ProcessWindowStyle.Hidden;
start.CreateNoWindow = true;
start.Arguments = s.args; //curent argument /qn
start.FileName = tempDir + "/" + s.executable;
start.CreateNoWindow = true;
While this code works perfectly fine with the msi's it does not work with the exe's as they all contain EULAs.
When using an exe you need to preface /qn with /v making it:
setup.exe /v/qn

LPR command to print pcl-file from windows service not working(Now a tray application)

I've been looking around for a while for a possible solution and explanation, but I can't find anything really.
The following command is being run from a windows service. The same command does function if used directly in cmd.
It does not return any errors or anything else for that matter.
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/C lpr.exe –S " + printerIP + " –P " + deviceName + " –o l " + fInfo.DirectoryName + #"\" + fInfo.Name;
process.StartInfo = startInfo;
process.Start();
It might just be some minor thing I'm missing, but I just can't see it. If it's possible to go around using the lpr-command with an easy alternative I'd love that, but I havent seen anything yet.
Edit:
Forgot to add that the file I'm trying to send to the printer is a pcl file.
Edit2:
When I run the command without the Hidden windowstyle and WaitForExit(5000) applied to the process then I can't seem to see any commandline written - all that appears is the empty command prompt.
Edit 3:
Been toying a bit around with this now and I've come up with the following:
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "lpr";
startInfo.Arguments = " –S " + printerIP + " –P " + deviceName + " –o l " + fInfo.DirectoryName + #"\" + fInfo.Name;
process.StartInfo = startInfo;
process.Start();
The above code works if it is executed by a user clicking a button in a form. So I decided to change my code into running as a tray application, seeing as I thought this might solve the issues - yet it still seems to refuse being run. Could it be some sort of issue with it being run by a triggered timer or another thread? Or perhaps something to do with the rights of those methods?
Change your code to this:
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/C C:\windows\Sysnative\lpr.exe –S " + printerIP + " –P " + deviceName + " –o l " + fInfo.DirectoryName + #"\" + fInfo.Name;
process.StartInfo = startInfo;
process.Start();
The issue is that you are trying to access a 64 bit application (lpr) from a 32 bit cmd.exe application. The simple solution is to use the sysnative directory.
http://www.samlogic.net/articles/sysnative-folder-64-bit-windows.htm
The 'Sysnative' folder is invisible in Windows Explorer If you
start Windows Explorer and open the Windows folder on your hard disk,
you may notice that the Sysnative folder is not shown. The main reason
to this is that Windows Explorer is a 64-bit program (when run in a
64-bit Windows), and the Sysnative folder is only visible and
accessible from 32-bit software. If 64-bit software need access to the
64-bit system folder in Windows, the only option is to use the
System32 folder name (for example: C:\Windows\System32).
Using the 'Sysnative' folder will help you access 64-bit tools from
32-bit code Some tools in a 64-bit Windows only exist in a 64-bit
version; there is no 32-bit version available. And some of these tools
are located in the 64-bit System32 folder. One example is the nbtstat
tool that is used to help troubleshoot NetBIOS name resolution
problems. If you try to run the nbtstat tool from 32-bit code (for
example from an application or from script) and use a path like
C:\Windows\System32, you will get a "File not found" error. The file
can not be found; although Windows Explorer shows that the nbtstat
program file actually is located in the C:\Windows\System32 folder.
The solution to this (somewhat confusing) problem is to include the
virtual Sysnative folder in the folder path when you want to run the
tool. For example like this: C:\Windows\Sysnative\nbtstat.exe The
file path above will give you access to the 64-bit nbtstat tool from a
32-bit application or from a 32-bit script. We recommend you to read
this article / blog post (at Scottie’s Tech.Info) to get more details
about this.

what's the tricky to delete temp folder in the installer?

I am creating MSI installer via VS 2008. I try to delete the temp folder at the end of the installation. That temp folder is created by my installer to hold some batch files for database creation. It always show other process is access it and doesn't allow my code to delete it. I have called the Close() of that access process. I have put sleep before the code to delete it. Nothing helpful.
Do you have any idea how I can delete it at the end of the installation?
thanks,
Did you try Filemon to see who is accessing the temp folder when delete is called on the folder?
Its better you use the system temp folder path
System.Environment.GetEnvironmentVariable("TEMP")
you need not worry about cleaning it up.
I can think of creating a batch file in the temp folder to run which runs as the last step. You put a pause in it by using ping (http://www.robvanderwoude.com/wait.php) and then after a few seconds (that installer has exited) delete the folder by using parameter passed:
PING 1.1.1.1 -n 1 -w 60000 >NUL
rd "%1"
This is really a hack. It is better to root out what locks your folder.
I'll address the conceptual problems in your setup first:
First off, as "Vinay B R" said, be sure your "temp" folder is beneath the Windows %TEMP% folder. That way, you can leave the files there if you fail to delete them.
Why exactly do you want to delete the batch files when you're done? There is no expectation that you clean up after yourself inside of the %TEMP% folder.
If you want to ensure the user doesn't run them again, then you could name them with a different file extension (e.g. ".tmp" instead of .bat), execute them using this method described here, then leave them behind:
cmd < "%TEMP%foo.tmp"
If you are trying to delete files because you don't want the user to have access to them, then by deleting them you will only protect yourself against casual users.
If you still want to delete the files, then:
In all likelihood your own process is locking your folder. Using Process Explorer will likely point to msiexec.exe or cmd.exe. No doubt you are able to manually delete the folder once MSI and SQL have exited, right? If so, then your own process isn't terminating right away. Find out why. Is SQL taking longer than you think, perhaps?
As an alternative to Aliostad's method, here is the "other flavor" listed in this article. As he wrote, however, it would be best for you to determine why it's locked.
Process.Start("cmd.exe", "/C choice /C Y /N /D Y /T 3 & Del " +
Application.ExecutablePath);
Application.Exit();
Here is a working sample in C#. If your users will have .NET installed, then you can invoke this as a custom action using the WiX DTF (install WiX, then in Visual Studio select New Project -> Windows Installer XML -> C# Custom Action Project).:
// Note: This can also be used to delete this .exe (i.e.
// System.Windows.Forms.Application.ExecutablePath).
//
public static void AsynchDeleteFolder(string myTempFolderPath)
{
ProcessStartInfo info = new ProcessStartInfo();
// Don't create a visible DOS box.
info.WindowStyle = ProcessWindowStyle.Hidden;
info.CreateNoWindow = true;
// Wait 3 seconds ("/T 3").
info.Arguments = #"/C choice /C Y /N /D Y /T 3 & rmdir /S /Q """ +
myTempFolderPath + #"""";
info.FileName = "cmd.exe";
Process.Start(info);
}
If you would rather execute just the applicable portion as a batch file, then you can avoid the DOS window by following this method.:
' Filename: Run_a_batch_file_with_no_popup_dos_box.vbs
'
' Invoke like this from the command line:
' wscript.exe Run_a_batch_file_with_no_popup_dos_box.vbs "c:\path with spaces to my file name.bat"
'
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run chr(34) & WScript.Arguments.Item(0) & Chr(34), 0
Set WshShell = Nothing

Categories