Create a new silent installer
From WPKG | Open Source Software Deployment and Distribution
Packages come in many types.
MSI
MSI files are fairly common and usually easy to install and remove silently; a simple installer might look like this:
<package id="nicurl" name="NI Curl" revision="%version%.1" reboot="false">
<variable name="version" value="15.0.358" />
<check type="uninstall" condition="versiongreaterorequal" path="NI Curl 15.0.0 (64-bit)" value="15.0.358" />
<install cmd="msiexec /qn /l* c:\netinst\logs\nicurl15.0.0(64-bit) /i "%SOFTWARE%\ni.com\15.0.0\Products\NI_Curl\nicurl64.msi"">
<exit code="3010" reboot="false" />
</install>
<upgrade include="install" />
<!-- Remove - rip out the MSI -->
<remove cmd="msiexec /qn /x {7F805F1F-7E86-4D39-9BB5-1F7C6B06F316}">
<!-- 1605 - already removed -->
<exit code="1605" />
</remove>
</package>
Such simple installers can be automatically generated using [msitools] and the perl script below, which is offered without warranty.
#!/usr/bin/perl -w
# To try to automatically build some WPKG XML from an MSI (or two, if they're different bit-ness)
# Code released under the GPL; feel free to improve and share.
# Use: wpkg-msi path.to.msi
# Use: wpkg-msi -msi32 path.to.32bit.msi -msi64 path.to.64bit.msi
use strict;
use Data::Dumper;
use Getopt::Long;
use Sys::Hostname;
use XML::Writer;
# Figure out which MSI files we're being called on
my @msis=@ARGV;
my $settings={};
# Read settings from MSI
my $msi64='';
my $msi32='';
GetOptions ("msi32=s" => \$msi32, # 32bit MSI
"msi64=s" => \$msi64); # 64bit MSI
if ($msi64 eq '' and $msi32 eq '' and defined($ARGV[0])) {
$msi64=$ARGV[0];
$msi32=$ARGV[0];
}
$settings->{'64'}=&readmsi($msi64);
$settings->{'32'}=&readmsi($msi32);
# Build the WPKG XML
my $name=$settings->{'64'}->{'ProductName'}.'|'.$settings->{'32'}->{'ProductName'};
my $id=lc($name);
$id=~ s/\s+//g;
my $version='';
if ($settings->{'64'}->{'ProductVersion'} eq $settings->{'32'}->{'ProductVersion'}) {
$version=$settings->{'64'}->{'ProductVersion'};
} else {
$version=$settings->{'64'}->{'ProductVersion'}.'|'.$settings->{'32'}->{'ProductVersion'};
}
my $writer=XML::Writer->new(ENCODING=>'utf-8');
$writer->comment('vim: set softtabstop=3:');
$writer->comment('Autogenerated by '.$0." running on ".hostname." as user ".getpwuid( $< ));
$writer->startTag('package',id=>$id,name=>$name,revision=>'%version%.1',reboot=>'false');
print "\n\t";
$writer->emptyTag('variable',name=>'version',value=>$version);
print "\n\t";
if ( ($settings->{'64'}->{'ProductName'} eq $settings->{'32'}->{'ProductName'})
&& ($settings->{'64'}->{'ProductVersion'} eq $settings->{'32'}->{'ProductVersion'}) ) {
# Same product version
print "\n\t";
$writer->emptyTag('check',type=>'uninstall',
condition=>'versiongreaterorequal',
path=>$settings->{'32'}->{'ProductName'},
value=>$version);
} else {
# 64bit check
print "\n\t";
$writer->emptyTag('check',type=>'uninstall',
condition=>'versiongreaterorequal',
path=>$name,
architecture=>'x64',
value=>$settings->{'64'}->{'ProductVersion'});
# 32bit check
print "\n\t";
$writer->emptyTag('check',type=>'uninstall',
condition=>'versiongreaterorequal',
path=>$name,
architecture=>'x86',
value=>$settings->{'32'}->{'ProductVersion'});
}
if ($msi32 eq $msi64) {
my $msi=$msi32;
$msi =~ s/.*deploy\$/%SOFTWARE%/;
$msi =~ s/\//\\/g;
print "\n\n\t";
$writer->startTag('install',cmd=>'msiexec /qn /l* c:\\netinst\\logs\\'.$id.'.log /i "'.$msi.'"');
print "\n\t\t";
$writer->emptyTag('exit',code=>'3010',reboot=>'false');
print "\n\t";
$writer->endTag('install');
} else {
print "\n\n\t";
my $msi=$msi32;
$msi =~ s/.*deploy\$/%SOFTWARE%/;
$msi =~ s/\//\\/g;
$writer->startTag('install',architecture=>'x86',cmd=>'msiexec /qn /l* c:\\netinst\\logs\\'.$id.'.log /i "'.$msi32.'"');
print "\n\t\t";
$writer->comment('Handle installer exit codes here');
print "\n\t\t";
$writer->emptyTag('exit',code=>'3010',reboot=>'false');
print "\n\t";
$writer->endTag('install');
print "\n\n\t";
$msi=$msi64;
$msi =~ s/.*deploy\$/%SOFTWARE%/;
$msi =~ s/\//\\/g;
$writer->startTag('install',architecture=>'x64',cmd=>'msiexec /qn /l* c:\\netinst\\logs\\'.$id.'.log /i "'.$msi64.'"');
print "\n\t\t";
$writer->comment('Handle installer exit codes here');
print "\n\t\t";
$writer->emptyTag('exit',code=>'3010',reboot=>'false');
print "\n\t";
$writer->endTag('install');
}
print "\n\n\t";
$writer->emptyTag('upgrade',include=>'install');
if ( ($settings->{'64'}->{'ProductCode'} eq $settings->{'32'}->{'ProductCode'}) ) {
print "\n\n\t";
$writer->comment('Remove - rip out the MSI');
print "\n\t";
$writer->startTag('remove',cmd=>'msiexec /qn /x '.$settings->{'32'}->{'ProductCode'});
print "\n\t\t";
$writer->comment('1605 - already removed');
print "\n\t\t";
$writer->emptyTag('exit',code=>'1605');
print "\n\t";
$writer->endTag('remove');
} else {
print "\n\n\t";
$writer->comment('Remove - rip out the MSI');
print "\n\t";
$writer->startTag('remove',architecture=>'x64',cmd=>'msiexec /qn /x '.$settings->{'64'}->{'ProductCode'});
print "\n\t\t";
$writer->comment('1605 - already removed');
print "\n\t\t";
$writer->emptyTag('exit',code=>'1605');
print "\n\t";
$writer->endTag('remove');
print "\n\t";
$writer->startTag('remove',architecture=>'x86',cmd=>'msiexec /qn /x '.$settings->{'32'}->{'ProductCode'});
print "\n\t\t";
$writer->comment('1605 - already removed');
print "\n\t\t";
$writer->emptyTag('exit',code=>'1605');
print "\n\t";
$writer->endTag('remove');
}
print "\n";
$writer->endTag('package');
$writer->end();
print "\n";
exit;
sub readmsi($) {
my $msi=shift;
my $fh;
open ($fh, "msiinfo export \"$msi\" Property |");
my $settings={};
while (my $line=<$fh>){
$line =~ s/\r//;
chomp($line);
$line =~ /^([^\s]+)\s+(.*)$/;
chomp($2);
$settings->{$1}=$2;
}
close ($fh);
return $settings;
}