How to run a batch script after installation is finished? - c#

I'm working for a custom installer developed in Visual Studio 2008 (Setup & Deployment > Setup project) for a C# project. I'd like to run a batch file (*.bat) after installation is finished. How can I do that?

You will have to extend the Installer class and override the Committed event.
Here is an example. Hope you will be able to find how to run a .bat file in C#.
[RunInstaller(true)]
public class ServiceInstaller : Installer
{
string strServiceName = "MyServiceName";
public ServiceInstaller()
{
// .............
this.Committed += new InstallEventHandler(ServiceInstaller_Committed);
}
void ServiceInstaller_Committed(object sender, InstallEventArgs e)
{
// Run your batch file
}
}
Custom Install Action is another option. Here is a similar thread for that.

You can run a batch file using cmd.exe, anyway it is what executes batch files.
Start it this way: cmd.exe /c <path-to-batch>\batchfile.bat.

Related

How to run current project by visual studio extension

I have a console application which generates json.
I need to execute this application by using a Visual Studio extension (Vsix). For that I created a VSix project with command. When I click run command, I need to run the current project.
I have no idea how to do that.
private void Execute(object sender, EventArgs e)
{
// Here is my method which is executed when i click it on menu
}
You could try these:
using EnvDTE;
..........
DTE dte = Package.GetGlobalService(typeof(DTE)) as DTE;
dte.ExecuteCommand("Debug.Start");
To run the application without debug, you can try this:
dte.ExecuteCommand("Debug.StartWithoutDebugging");
And it will debug the current active project when you click the button.
More info, you can refer to this similar issue.
=========================================
And also you could try to use this:
dte.Solution.SolutionBuild.Run();

Start windows service on install without setup project

I have developed a windows service, but need it to start automatically on install. Problem is that every tutorial I found is showing me through the Setup Project. There is a fantastic 3 part tutorial HERE that I used to convert my app to a service, but I don't have the Setup Project in my other project types. Can I do this programatically or is there a way I can get the Setup Project project type?
In your Installer class, add a handler for the AfterInstall event. You can then call the ServiceController in the event handler to start the service.
public ServiceInstaller()
{
//... Installer code here
this.AfterInstall += new InstallEventHandler(ServiceInstaller_AfterInstall);
}
void ServiceInstaller_AfterInstall(object sender, InstallEventArgs e)
{
using (ServiceController sc = new ServiceController(serviceInstaller.ServiceName))
{
sc.Start();
}
}
Now when you run InstallUtil on your installer it will install and then start up the service.
MSDN link for more details
I believe Topshelf project has built-in service Installer/Uninstaller. when integrated in the application, it can be installed as a service through simple command from application itself, for example we can easily install and start myService.exe with myService.exe install start command.
we can simply create a self installing service, here is an Example:
public class ServiceClass
{
public ServiceClass()
{
}
public void Start() { }
public void Stop() { }
}
public class Program
{
public static void Main(string[] args)
{
//we can simply install our service by setting specific commands for same or install it directly from command line or from another process
if (args.Length == 0)
{
var processName = Process.GetCurrentProcess().ProcessName + ".exe";
var install = Process.Start(processName, "install start");
install.WaitForExit();
return;
}
HostFactory.Run(x =>
{
x.Service<ServiceClass>(s =>
{
s.ConstructUsing(name => new ServiceClass());
s.WhenStarted(tc => tc.Start());
s.WhenStopped(tc => tc.Stop());
});
x.RunAsLocalSystem();
x.SetDescription("Topshelf Host");
x.SetDisplayName("TopShelf");
x.SetServiceName("TopShelf");
});
}
}
you can get Topshelf through PM> Install-Package Topshelf Nuget command.
Best thing to do is to add on the Installer Projects Extension!
The Setup project type was deprecated after VS 2010, but following feedback Microsoft have brought back a new version for VS 2013.
Install the new Installer Projects Extension from Microsoft: https://visualstudiogallery.msdn.microsoft.com/9abe329c-9bba-44a1-be59-0fbf6151054d
This should work for any non-express version of Visual Studio 2013 (including the new free Community Edition SDK)
Then you can just follow the same instructions as for the VS 2010 setup projects :)
There isn't an easy option for VS2012 (you could try an installer with WiX I guess, but thats a lot to learn!)
I'm not sure if InstallShield LE (free version for VS2012) would work for this situation, but you could give it a try.
You can always change the startup type of a service after installation remember. (Control Panel -> Administrative Tools -> Services -> right click service -> Properties -> change "Startup Type" to "Automatic" )
If you are targeting Windows 7 and up, Powershell is installed by default. One option is to run a simple powershell script which installs the service, starts it, and sets the service to start automatically if the machine is rebooted:
InstallUtil yourService.exe
Start-Service yourService
Set-Service yourService -startuptype "Automatic"

trying to create windows service from console application but it will not install

I am trying to use this tutorial from microsoft.... here
I cannot get installutil to install it... I keep getting "Remove InstallState file because there are no installers."
There is clearly an installer in the exe.... here is the installer as it exists in my code:
// Provide the ProjectInstaller class which allows
// the service to be installed by the Installutil.exe tool
[RunInstaller(true)]
public class ProjectInstaller : Installer
{
private ServiceProcessInstaller process;
private ServiceInstaller service;
public ProjectInstaller()
{
process = new ServiceProcessInstaller();
process.Account = ServiceAccount.LocalSystem;
service = new ServiceInstaller();
service.ServiceName = "WCFWindowsServiceSample";
Installers.Add(process);
Installers.Add(service);
}
}
}
This is pretty annoying at this point. If someone could look at the Microsoft article which is pretty simple I would appreciate any help. With the installer there, I don't know why the installutil will not find it.
Yes I am running a visual studio command prompt as an administrator to do this.
Oddly to fix this I needed to move the installer to a new cs file and that did it. I simply created a new class file and moved the exact same class from the main file to this other file and it installed ok. It doesn't make sense to me but this is a workaround for those who may be interested.

How to run a setup from another setup?

I have a solution with 3 modules. Windows, Web, and Windows Service. I want to create one parent setup that runs three child setup packages regarding to the user choose.
I created a setup project as the following:
I created a library that contains InstallerHelper which is inherited from Installer class
I added the following code:
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
try
{
FileInfo fileInfo = new FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location);
string sProgram = Path.Combine(fileInfo.DirectoryName, "Setup1.msi");
Process p = Process.Start(sProgram);
p.WaitForExit();
}
catch (Exception exc)
{
Context.LogMessage(exc.ToString());
throw;
}
}
The problem is that the windows installer refuses to run multiple instances of windows installer and throws the following error:
Another installation is in progress. You must complete that
installation before continuing this one.
Is my approach correct? Is ther another way to run another setup and the parent setup should wait all of them with one Finish click?.
You can use Wix Burn to create a setup package contained multiple application installers (msi/exe):
Wix Toolset: Building Installation Package Bundles
Neil Sleightholm's Blog: WiX Burn – tips/tricks

Debugging C# Custom Installer Classes

I have written an installation class that extends Installer and overrides afterInstall, but I'm getting a null pointer exception. How can I go about debugging my class?
Something that is handy for hard to debug sections of code is
System.Diagnostics.Debugger.Break()
Will throw a breakpoint caught by any installed debugger (VStudio, WinDbg, Remote debugger etc...).
Use it to debug really tricky areas where regular F5+Go or "Attach to Process" is difficult or impossible to perform, some examples include:
short-lived processes
time-sensitive processes
breaking into spawned sub-processes
installers
service stop/start
distributed systems
The best way I've found is to write a unit test, and new up and initialize your installer class from your unit test:
[TestClass] public class InstallerTest {
[TestMethod]
public void InstallTest() {
// substitute with your installer component here
DataWarehouseInstall installer = new DataWarehouseInstall();
string assemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string installLogFilePath = Path.Combine(assemblyDirectory, "install.log");
installer.Context = new System.Configuration.Install.InstallContext(installLogFilePath, null);
// Refactor to set any parameters for your installer here
installer.Context.Parameters.Add("Server", ".");
//installer.Context.Parameters.Add("User", "");
//installer.Context.Parameters.Add("Password", "");
installer.Context.Parameters.Add("DatabaseName", "MyDatabaseInstallMsiTest");
//installer.Context.Parameters.Add("DatabasePath", "");
// Our test isn't injecting any save state so we give a default instance for the stateSaver
installer.Install(new Hashtable());
} }
At least then it takes advantage of the IDE tooling better. This is especially helpful for very large installers with LOTS of components. Then you can also create ordered unit tests and run them in sequence to mimic your installer during debug or your automated builds.
Another tip would be general SOLID/GRASS software principles...develop in neat/thin layers, keeping your actual "custom action" installer logic very simple and instead call into any reusable API stuff you have that is specific to your installer(s), just as we are used to with UI development. (The installer is just another UI anyway.) This is especially key if your goal is to have a certain UI experience shared across all installers of your products.
Surprised no one has actually answered. Put a MessageBox.Show("hello") into your custom action's Install() member. Build the deployment in debug config. Install. When the MessageBox appears, go into VS IDE, Debug, Attach Process and look for the instance of msiexec that is labeled "Managed". Attach the debugger to that instance of msiexec. Now go back to the source of your custom action and place a breakpoint right after the call to MessageBox.Show(). Close the MessageBox and your breakpoint will be hit, and you're debugging in the IDE!
attach the installer process to Visual studio in Debug->Processes->Attach or CTRL + ALT + P
set the breakpoint and you should be able to go
In your installer method add Debugger.Launch() statement which will launch "Visual Studio just in time debugger" where you can attach an instance of visual studio and debug your installer class (MSI). This should work in Visual Studio 2010 as well. But you need to have administrative rights to do this. If you don't have administrative rights, you might have issues. So, log in as administrator for debugging MSI. For example:
public override void Install(System.Collections.IDictionary stateSaver)
{
Debugger.Launch();
base.Install(stateSaver);
}
In visual studio 2005, even Debugger.Break() use to work but somehow this does not work with Visual Studio 2010.
This is what actually worked for me.
System.Diagnostics.Debugger.Launch();
Then right click on the Installer Project and press "Install"
None of above worked for me. This is what actually worked. Note that you need to put insert "both" lines.
using System.Diagnostics;
MessageBox.Show("Test is about to begin");
Debugger.Launch();
I use EventLog.WriteEntry("source", "message"), and check the EventLog when installing. Maybe not optimal, but works for me :)
I use the following class to write a simple log into the target directory. In my opinion, it's easier than trying to use the Visual Studio debugger.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace MyCompany.Deployment
{
/// <summary>
/// Enables a quick and easy method of debugging custom actions.
/// </summary>
class LogFile
{
const string FileName = "MyCompany.Deployment.log";
readonly string _filePath;
public LogFile(string primaryOutputPath)
{
var dir = Path.GetDirectoryName(primaryOutputPath);
_filePath = Path.Combine(dir, FileName);
}
public void Print(Exception ex)
{
File.AppendAllText(_filePath, "Error: " + ex.Message + Environment.NewLine +
"Stack Trace: " + Environment.NewLine + ex.StackTrace + Environment.NewLine);
}
public void Print(string format, params object[] args)
{
var text = String.Format(format, args) + Environment.NewLine;
File.AppendAllText(_filePath, text);
}
public void PrintLine() { Print(""); }
}
}
For logging purposes (in 3.5) what about using:
Context.LogMessage("My message");
Write the following code in the beginning of the method that you want to debug
#if DEBUG
MessageBox.Show(Process.GetCurrentProcess().Id.ToString());
#endif
So when your method is called, the above code will be hit and you can then attach the debugger to the process(ctrl+alt+p) using the above process ID. You may have to start VS with elevated permissions.
build a VM, install Visual studio, make a copy of it (or create a differencing Virtual HDD) and run the installer under the debugger under the VM.
That is what I would do (but I'm no expert).
You can also use the installUtil.exe utility to test your installer component.
In case you created a c# class assembly with your Installer class, Change your debug settings to start the external program 'C:\Windows\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe'
and enter your commandline arguments accordingly (e.g. /Args=myargument "path to the assembly")
As last set your breakpoints, press f5 and you're set to debug your code.
--paralax
You might automate debugging of installer projects by adding following section to either .csproj or .csproj.user file:
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<StartAction>Program</StartAction>
<StartProgram>$(MSBuildBinPath)\installutil.exe</StartProgram>
<StartArguments>$(AssemblyName).dll</StartArguments>
</PropertyGroup>
Use project file if you want other developers benefit from this change and .user file if you want to use it by yourself.

Categories