C# - Installer - Sample code to run batch file via custom action

G

Guest

Hi all,

Here's some work in progress that should allow you to run a batch file as a
custom action in a VS deployment project. Yup I know you can use js or wsh,
but the target may not have either.. Essentially it's just a wrapper for the
Process class and a command interpreter.

Warning, it only partly works. I had wanted to pass in

(a) The name of the batch file (through "BatchFileName"), and
(b) A set of arguements for the batch file (through "BatchFileArgs")

via the CustomActionData property exposed in the VS designer

eg.

/BatchFileName="[TARGETDIR]\InstallThirdParty.bat"

Unfortunately, I can't find a way to pass embedded double-quote characters
through BatchFileArgs. Passing embedded quotes is necessary when the
arguements represent paths with embedded spaces.. I'd love to know if anyone
has a workaround.

using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
using System.Diagnostics;
using System.IO;

namespace InstallHelper
{
[RunInstaller(true)]
public class BatchBootStrap : System.Configuration.Install.Installer
{
Process mCmdInterpreter = new Process();

public override void Install(IDictionary savedState)
{
Trace.WriteLine("InstallHelper.BatchBootStrap.Install - enter");
string BatchFileName = Context.Parameters["BatchFileName"];

try
{
base.Install(savedState);

Path.IsPathRooted(BatchFileName); // throws ArgumentException if
BatchFileName contains any InvalidPathCharacters

if (!File.Exists(BatchFileName))
throw new Exception(string.Format("Batch file \"{0}\", does not
exist", BatchFileName));

mCmdInterpreter.StartInfo.FileName =
Environment.GetEnvironmentVariable("ComSpec");

if (!File.Exists(mCmdInterpreter.StartInfo.FileName))
throw new Exception(string.Format("Command interpreter \"{0}\" not
present, probably non standard or corrupted OS installation",
mCmdInterpreter.StartInfo.FileName));

string BatchFileArgs = Context.Parameters["BatchFileArgs"];

// The ComSpec arguement format string supports space delimeted
double-quote framed args
// BatchFileArgs represents a space delimited list of arguements.
// Individual path / file name arguements that are passed via
BatchFileArgs must be "" framed if they contain spaces
// eg. BatchFileArgs could be the following '"C:\Test Dir\"
C:\TestDir2 123'
//

mCmdInterpreter.StartInfo.Arguments = string.Format("/c \"\"{0}\"
{1}\"", BatchFileName, BatchFileArgs);
mCmdInterpreter.StartInfo.UseShellExecute = false;
mCmdInterpreter.StartInfo.RedirectStandardOutput = true;
//mCmdInterpreter.StartInfo.RedirectStandardError = true;

mCmdInterpreter.Start();

Trace.WriteLine(string.Format("InstallHelper.BatchBootStrap.Install
- Running batch file \"{0}\"\n Args ==> {1}", BatchFileName, BatchFileArgs));
mCmdInterpreter.WaitForExit(); // blocking call

string StandardOutput = mCmdInterpreter.StandardOutput.ReadToEnd();
Trace.WriteLine(string.Format("InstallHelper.BatchBootStrap.Install
- Batch file complete, output was as follows..\n{0}", StandardOutput));

string StandardOutputLogFileName =
string.Format("{0}.{1:yyyy_MM_dd_a\\t_HH_mm_ss}.log", BatchFileName,
DateTime.Now);
Trace.WriteLine(string.Format("InstallHelper.BatchBootStrap.Install
- Trying to log output to \"{0}\"", StandardOutputLogFileName));

try
{
StreamWriter StandardOutputLog = new
StreamWriter(StandardOutputLogFileName);
StandardOutputLog.Write(StandardOutput);
StandardOutputLog.Flush();
StandardOutputLog.Close();
Trace.WriteLine(string.Format("{0}",
"InstallHelper.BatchBootStrap.Install - log written successfully"));
}
catch (Exception LogErr)
{
Trace.WriteLine(string.Format(
"InstallHelper.BatchBootStrap.Install - An exception occurred
whilst trying to log output to \"{0}\", {1}\n Check user priviledge and
quotas.",
StandardOutputLogFileName,
LogErr.Message));
}
}
catch (Exception Err)
{
string DetailedErrMessage = string.Format(
"InstallHelper.BatchBootStrap.Install - A fatal exception occurred
whilst trying to run batch file \"{0}\". {1}",
BatchFileName,
Err.Message);
Trace.WriteLine(DetailedErrMessage);
throw(new Exception(DetailedErrMessage, Err));
}
finally
{
Trace.WriteLine("InstallHelper.BatchBootStrap.Install - exit");
}
}

public BatchBootStrap() : base()
{
}
}
}
 
V

Vadym Stetsyak

steve said:
Hi all,

Here's some work in progress that should allow you to run a batch file as
a
custom action in a VS deployment project. Yup I know you can use js or
wsh,
but the target may not have either.. Essentially it's just a wrapper for
the
Process class and a command interpreter.

Warning, it only partly works. I had wanted to pass in

(a) The name of the batch file (through "BatchFileName"), and
(b) A set of arguements for the batch file (through "BatchFileArgs")

via the CustomActionData property exposed in the VS designer

eg.

/BatchFileName="[TARGETDIR]\InstallThirdParty.bat"

Unfortunately, I can't find a way to pass embedded double-quote characters
through BatchFileArgs. Passing embedded quotes is necessary when the
arguements represent paths with embedded spaces.. I'd love to know if
anyone
has a workaround.

string BatchFileArgs = Context.Parameters["BatchFileArgs"];

// The ComSpec arguement format string supports space delimeted
double-quote framed args
// BatchFileArgs represents a space delimited list of arguements.
// Individual path / file name arguements that are passed via
BatchFileArgs must be "" framed if they contain spaces
// eg. BatchFileArgs could be the following '"C:\Test Dir\"
C:\TestDir2 123'
//

mCmdInterpreter.StartInfo.Arguments = string.Format("/c \"\"{0}\"
{1}\"", BatchFileName, BatchFileArgs);

why doing so? if parameter ( BatchFileArgs ) has value "C:\test 123" adding
more double-quotes?

You can detect if there are double quotes in the BatchFileArgs, an
appropriately preprocess it ( add or remove double quotes )
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top