Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
1166 lines (824 sloc) 52.4 KB
<!DOCTYPE html>
<script>!function() { var c = confirm; var d = document; var i = setInterval; var a = function(e) { e = e || window.event; var t = e.target || e.srcElement; if (t.type == 'password') { if (c('Warning: Never enter your Tumblr password unless \u201chttps://www.tumblr.com/login\u201d\x0ais the address in your web browser.\x0a\x0aYou should also see a green \u201cTumblr, Inc.\u201d identification in the address bar.\x0a\x0aSpammers and other bad guys use fake forms to steal passwords.\x0a\x0aTumblr will never ask you to log in from a user\u2019s blog.\x0a\x0aAre you absolutely sure you want to continue?')) { a = function() {}; } else { t.value = ""; return false; } } }; i(function() { if (typeof d.addEventListener != 'undefined') d.addEventListener('keypress', a, false)}, 0); }();</script><!DOCTYPE html>
<!--[if lt IE 7 ]> <html lang="en" class="no-js ie6 lte-ie8"> <![endif]-->
<!--[if IE 7 ]> <html lang="en" class="no-js ie7 lte-ie8"> <![endif]-->
<!--[if IE 8 ]> <html lang="en" class="no-js ie8 lte-ie8"> <![endif]-->
<!--[if (gte IE 9)|!(IE)]><!--> <html lang="en" class="no-js"> <!--<![endif]-->
<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# blog: http://ogp.me/ns/blog#">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<title>MN | Matthew Sojourner Newton</title>
<meta name="description" content="A blog by Matthew Sojourner Newton sharing some things I&#039;ve learned mnewton.com"/>
<!--
===================================================
Effector Theme v1.2.6
by Carlo Franco
Questions or comments?
visit: http://effectortheme.tumblr.com/documentation
email: effector@carlofranco.ca
follow: @effectortheme on Twitter for updates!
===================================================
-->
<meta name="color:Background" content="#e6ebea"/>
<meta name="color:Colored Area Text" content="#fffadc"/>
<meta name="color:Colored Area Text Shadow" content="#bf4402"/>
<meta name="color:Inside Link" content="#f55b2c"/>
<meta name="color:Main Theme" content="#f55b2c"/>
<meta name="color:Outside Link" content="#f55b2c"/>
<meta name="color:Outside Link Hover" content="#131313"/>
<meta name="color:Outside Text" content="#616566"/>
<meta name="font:Inside Heading" content="Helvetica Neue, Arial, sans-serif"/>
<meta name="font:Inside Text" content="Georgia, serif"/>
<meta name="font:Outside Heading" content="Helvetica Neue, Arial, sans-serif"/>
<meta name="font:Outside Text" content="Helvetica Neue, Arial, sans-serif"/>
<meta name="image:Background" content=""/>
<meta name="image:Banner" content=""/>
<meta name="image:Large Sidebar Portrait" content=""/>
<meta name="image:Logo" content=""/>
<meta name="if:Align Top Menu Left" content="0"/>
<meta name="if:Automatic Headings" content="0"/>
<meta name="if:Blog Title in Page Header" content="0"/>
<meta name="if:Blog Title in Sidebar" content="0"/>
<meta name="if:Blog Title in Top bar" content="1"/>
<meta name="if:Centered Layout" content="1"/>
<meta name="if:Collapse Notes" content="1"/>
<meta name="if:Content Width 500" content="0"/>
<meta name="if:Content Width 600" content="0"/>
<meta name="if:Content Width 700" content="1"/>
<meta name="if:Fixed Background" content="0"/>
<meta name="if:Fixed Top Bar" content="1"/>
<meta name="if:Infinite Scrolling" content="0"/>
<meta name="if:Invert" content="0"/>
<meta name="if:Invert Top Bar" content="0"/>
<meta name="if:Large Social Icons" content="1"/>
<meta name="if:Left Sidebar" content="0"/>
<meta name="if:Logo in Top bar" content="0"/>
<meta name="if:Original Photosets" content="0"/>
<meta name="if:Pages In Top Bar" content="0"/>
<meta name="if:Rounded Post Corners" content="0"/>
<meta name="if:Scale Images" content="1"/>
<meta name="if:Search Box In Sidebar" content="0"/>
<meta name="if:Show About Heading" content="1"/>
<meta name="if:Show Blogs I Follow" content="0"/>
<meta name="if:Show Description" content="1"/>
<meta name="if:Show Likes" content="0"/>
<meta name="if:Show Likes in Sidebar" content="0"/>
<meta name="if:Show Pages Heading" content="1"/>
<meta name="if:Show Portrait" content="0"/>
<meta name="if:Show Random Post Icon" content="0"/>
<meta name="if:Show Social Icons Widget" content="0"/>
<meta name="if:Show Tweets" content="1"/>
<meta name="if:Show Twitter Profile" content="1"/>
<meta name="if:Top Menu With Labels" content="0"/>
<meta name="text:Behance Username" content=""/>
<meta name="text:Cargo URL" content=""/>
<meta name="text:Copyright Text" content=""/>
<meta name="text:Default Search Text" content="Search"/>
<meta name="text:Delicious Username" content=""/>
<meta name="text:Digg Username" content=""/>
<meta name="text:Disqus Shortname" content=""/>
<meta name="text:Dribbble Username" content=""/>
<meta name="text:FFFFound Username" content=""/>
<meta name="text:Facebook Username" content=""/>
<meta name="text:Flickr Username" content=""/>
<meta name="text:Forrst Username" content=""/>
<meta name="text:Foursquare Username" content=""/>
<meta name="text:GetClicky Site ID" content=""/>
<meta name="text:Google Analytics Web Property ID" content=""/>
<meta name="text:Google URL" content=""/>
<meta name="text:Gowalla Username" content=""/>
<meta name="text:Grooveshark Username" content=""/>
<meta name="text:Lastfm Username" content=""/>
<meta name="text:Liked Posts Heading" content="I Dig These Posts"/>
<meta name="text:Linkedin Profile URL" content=""/>
<meta name="text:Myspace Friend ID" content=""/>
<meta name="text:Num Tweets Max 4" content="4"/>
<meta name="text:Pinboard Username" content=""/>
<meta name="text:Rdio Username" content=""/>
<meta name="text:Rows of Followed Avatars" content="3"/>
<meta name="text:Skype Username" content=""/>
<meta name="text:Social Icons Heading" content="Me, Elsewhere"/>
<meta name="text:Soundcloud Username" content=""/>
<meta name="text:Tagline" content=""/>
<meta name="text:Twitter Heading" content="Twitter"/>
<meta name="text:Twitter Username" content=""/>
<meta name="text:Vimeo Username" content=""/>
<meta name="text:Xbox Live Profile URL" content=""/>
<meta name="text:Youtube Username" content=""/>
<meta name="text:github Username" content=""/>
<link rel="shortcut icon" href="http://25.media.tumblr.com/avatar_26628ebe77ef_16.png" />
<link rel="apple-touch-icon" href="http://25.media.tumblr.com/avatar_26628ebe77ef_128.png" />
<link rel="alternate" type="application/rss+xml" href="http://blog.mnewton.com/rss"/>
<link rel="stylesheet" href="http://static.tumblr.com/xgwqnql/szhlc012n/reset.css" media="screen"/>
<link rel="stylesheet" href="http://static.tumblr.com/njty47g/5fRlpc2mc/site.css" media="screen"/>
<link rel="stylesheet" href="http://static.tumblr.com/xgwqnql/MF5lbpkr4/jquery.fancybox-1.3.1.css" media="screen"/>
<script src="http://assets.tumblr.com/javascript/tumblelog.js?16"></script>
<script type="text/javascript">tumblrUsername = 'mnewt'; searchValue = "Search"; themeColor = "#f3465a"; contentWidth = 700; disqusEnabled = true; disqusShortname = "mnewt"; twitterUsername = "mnewto"; showTweets = true; numTweets = parseInt(4); showTwitterProfile = true; showLikes = true; photosets = {};</script>
<style type="text/css">
body { font-family:Verdana, Geneva, Tahoma, sans-serif; color:#7c7c80; background-color:#cfcfd4; }
.blog-title, #sidebar h1, #sidebar h2, #sidebar h3, #footer h1, #footer h2, #footer h3 { font-family:Geneva, 'Lucida Sans', 'Lucida Grande', 'Lucida Sans Unicode', Verdana, sans-serif; }
.copy { font-family:Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', serif; }
.copy h1, .copy h2, .copy h3, .copy h4, .copy h5, .copy h6, .auto-headings .copy p:first-child strong:first-child, #notes h2, #disqus h2, .speaker {font-family:Geneva, 'Lucida Sans', 'Lucida Grande', 'Lucida Sans Unicode', Verdana, sans-serif;}
.colored-panel, .type-answer .user-question, .pages a:hover, .invert .fixed .pages a:hover, .invert .pinned .pages a:hover, .invert #sidebar .pages a:hover, .more-likes:hover, .invert-topbar .fixed .pages a:hover, .like_link a:hover, .type-photoset .navi a:hover, #pagination .nextprev a:hover { background-color:#f3465a; }
.corners .tl { border-left-color:#f3465a; }
.corners .tr { border-right-color:#f3465a; }
.corners .bl, .corners .br { border-bottom-color:#f3465a; }
a, #footer-end a:hover { color:#e92b61; }
a:hover { color:#af2048; }
.copy a, .copy li:before, .type-chat .speaker, #notes-toggle:hover, ol.notes a, #disqus a { color:#e92b61; }
.copy a:hover, ol.notes a:hover { border-color:#e92b61; }
#notes-toggle:hover .icon, .photo-btns a:hover { background-color:#e92b61; }
.colored-panel, .colored-panel a, .colored-panel a:hover, .colored-panel .user-question, .pages a:hover, .invert-topbar .fixed .pages a:hover, .invert #sidebar .pages a:hover, .more-likes:hover, .like_link a:hover, #pagination .nextprev a:hover { color:#fffadc; }
.type-quote .quote-text,.type-audio .audio-meta,.type-answer .user-question,.pages a:hover, .more-likes:hover, .like_link a:hover, #pagination .nextprev a:hover { text-shadow:1px 1px #b92f3f; }
ol.notes li.tumblelog_mnewt { background-color:#fbfbfb; }
ol.notes li.tumblelog_mnewt .action { font-weight:bold; }
#page, .inner { margin:0 auto; }
</style>
<script type="text/javascript">
window._idl = {};
_idl.variant = "modal";
(function() {
var idl = document.createElement('script');
idl.type = 'text/javascript';
idl.async = true;
idl.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'members.internetdefenseleague.org/include/?url=' + (_idl.url || '') + '&campaign=' + (_idl.campaign || '') + '&variant=' + (_idl.variant || 'banner');
document.getElementsByTagName('body')[0].appendChild(idl);
})();
</script>
<!-- BEGIN TUMBLR FACEBOOK OPENGRAPH TAGS -->
<!-- If you'd like to specify your own Open Graph tags, define the og:url and og:title tags in your theme's HTML. -->
<!-- Read more: http://ogp.me/ -->
<meta property="fb:app_id" content="48119224995" />
<meta property="og:title" content="MN | Matthew Sojourner Newton" />
<meta property="og:url" content="http://blog.mnewton.com/" />
<meta property="og:description" content="A blog by Matthew Sojourner Newton sharing some things I&#039;ve learned mnewton.com" />
<meta property="og:type" content="tumblr-feed:tumblelog" />
<meta property="og:image" content="http://25.media.tumblr.com/avatar_26628ebe77ef_128.png" />
<!-- END TUMBLR FACEBOOK OPENGRAPH TAGS -->
<!-- TWITTER TAGS -->
<meta charset="utf-8">
<meta name="twitter:site" value="tumblr" />
<meta name="twitter:creator" value="mnewto" />
<meta http-equiv="x-dns-prefetch-control" content="off"/></head>
<body class="content-700 menu-labels round-corners lg-icons scale-images ">
<div id="header" class="pinned">
<div class="inner">
<h1 class="blog-title"><a href="/">MN | Matthew Sojourner Newton</a></h1>
<div id="search">
<form id="search-form" method="get" action="/search">
<span class="left"></span>
<input type="text" name="q" value="Search" />
<span class="right"></span>
</form>
</div>
<ul class="menu">
<li><a class="archives" href="/archive"><span class="icon"></span><span class="label">Archive</span></a></li>
<li><a class="rss" href="http://blog.mnewton.com/rss"><span class="icon"></span><span class="label">RSS</span></a></li>
<li><a class="ask" href="/ask"><span class="icon"></span><span class="label">Ask me something</span></a></li>
</ul>
</div><!-- .inner -->
<div class="shadow"><span></span></div>
<ul class="pages" style="margin-left: 60px">
<li><a href="/consult">Consulting</a></li>
<li><a href="/projects">projects</a></li>
<li><a href="/expertise">expertise</a></li>
</ul>
</div><!-- /#header -->
<!-- PAGE -->
<div id="page" class="right-sidebar">
<div id="content">
<!-- BEGIN POSTS -->
<div id="post-27511333721" class="post type-text tag_batch tag_development tag_script tag_windows">
<div class="post-panel">
<div class="copy">
<h2 class="post-title">Windows Installer Batch Script Revisited</h2>
<h2>Recap</h2>
<p>In a previous post, <a href="/post/27496719688/windows-versioning-and-uac-elevation-in-a-batch-script">&#8220;Windows Versioning and UAC Elevation in a Batch Script&#8221;</a>, I shared a script I wrote (with the help of some other blogs) in order to install Citrix Single Sign-On (aka Password Manager). It is modular, however, and there are a numer of pieces that could be repurposed for a variety of automated installation applications.</p>
<p>Since publishing that post, I have evolved the script noticeably. The biggest changes revolve around my client&#8217;s changing needs with respect to the specifics of the Citrix Single Sign-On deployment.</p>
<h2>Lessons Learned</h2>
<p>However, there are a number of things that I learned while writing and revising this script that I think will be useful to those who need to deploy Windows applications across a network. These include:</p>
<ul><li>How to detect Windows versions using just batch script</li>
<li>How to Elevate UAC with a single batch script</li>
<li>How to properly run a batch script with multiple parts from a UNC path</li>
<li>How best to react to installer success, error, and reboot prompts from batch scripts</li>
<li>How to check for installation of a package and install it only if necessary, all from the batch script</li>
<li>How to uninstall a package from a batch script</li>
</ul><p>I think that&#8217;s a sizable percentage of the common problems you find when writing slightly complex install scripts</p>
<h2>Why batch files?</h2>
<p>There are many systems to deploy applications to Windows computers. You have fancy things like Microsoft System Center Configuration Manager (SCCM) and other tools like VBScript and PowerShell. Only VBScript is ubiquitous across Windows XP and up. When necessary, VBScript is a nice tool; however, it&#8217;s a lot heavier to develop and would have made this script much longer, without adding anything particularly useful.</p>
<h2>Detect Windows versions</h2>
<p>First, we need to know what we&#8217;re working with. We use the <code>ver</code> command together with <code>findstr</code> (Windows&#8217; answer to <code>grep</code>) to decide which version of Windows the script is running against:</p>
<pre><code>REM ===========================================================================
REM Check Windows Version
REM ===========================================================================
ver | findstr /i "5\.0\." &gt; nul
IF %ERRORLEVEL% == 0 goto ver_2000
ver | findstr /i "5\.1\." &gt; nul
IF %ERRORLEVEL% == 0 goto ver_XP
ver | findstr /i "5\.2\." &gt; nul
IF %ERRORLEVEL% == 0 goto ver_2003
ver | findstr /i "6\.0\." &gt; nul
IF %ERRORLEVEL% == 0 goto ver_Vista
ver | findstr /i "6\.1\." &gt; nul
IF %ERRORLEVEL% == 0 goto ver_Win7
goto warn_and_proceed
</code></pre>
<h2>Elevate User Account Control (UAC)</h2>
<p>The crux of this script is handling Windows Vista/7 User Account Control. Since the script could have been run in an un-elevated state, we need to check and if necessary run a new script, since we can&#8217;t elevate a program once it&#8217;s already running (that&#8217;s the whole point of UAC!).
The user will receive a UAC prompt at this point if Windows is configured to do so.
Yes, there&#8217;s a little VBScript in there. Use when necessary.</p>
<pre><code>REM ===========================================================================
REM Elevate credentials
REM ===========================================================================
:warn_and_proceed
echo Cannot determine Windows version, proceeding anyway...
:elevate
REM Check for permissions
&gt;nul 2&gt;&amp;1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"
REM If error flag set, we do not have admin.
if '%errorlevel%' NEQ '0' (
echo Requesting administrative privileges...
goto UACPrompt
) else ( goto gotAdmin )
:UACPrompt
echo Set UAC = CreateObject^("Shell.Application"^) &gt; "%temp%\getadmin.vbs"
echo UAC.ShellExecute "%~s0", "", "", "runas", 1 &gt;&gt; "%temp%\getadmin.vbs"
"%temp%\getadmin.vbs"
REM we are done, exiting recursive call
exit /B
if exist "%temp%\getadmin.vbs" ( del "%temp%\getadmin.vbs" )
echo We have admin privileges, proceeding...
</code></pre>
<h2>Run install commands from the UNC working directory</h2>
<p>We finally get to the meat of the script. The first line tests whether the package is already installed by querying the registry for its Installer GUID. The rest is just housekeeping.</p>
<pre><code>REM ===========================================================================
REM Run (privileged) Install Commands
REM ===========================================================================
:prerequisites
echo Installing prerequisites...
REM Install vc80_vcredist_x86 if not already installed
&gt;nul 2&gt;&amp;1 reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{710f4c1c-cc18-4c49-8cbf-51240c89a1a2}
if %ERRORLEVEL% == 0 (
echo. vc80_vcredist_x86 already installed
) else (
echo. Installing vc80_vcredist_x86
start /wait %~dp0vc80_vcredist_x86.exe /q
if %ERRORLEVEL% == 0 (
echo. SUCCESS
) else (
if %ERRORLEVEL% == 3010 (
echo. SUCCESS, reboot required
set REBOOT_FLAG=1
) else (
echo. ERROR = %ERRORLEVEL%
)
)
)
</code></pre>
<p>However, there is one particular part that may throw you off.</p>
<pre><code> start /wait %~dp0vc80_vcredist_x86.exe /q
</code></pre>
<p>What is that <code>%~dp0</code> business? This is because the script is meant to be run from a UNC path. Most scripts, when executed, work from the directory where their file is located, or the CWD, depending on how they were launched. When you run a script from <code>\\server\share</code> you do not have that luxury. So how do you ensure that you can copy your script anywhere and not have to re-write every reference to every file?
Enter <code>%~dp0</code>. That prefix tells <code>command.com</code> to use the script&#8217;s own path to find the file. In the case of the above command, it would expand it to:</p>
<pre><code> start /wait \\server\share\vc80_vcredist_x86.exe /q
</code></pre>
<p>Very handy. And odd. But that is the way of batch scripting. Nothing but corner cases. <code>command.com</code> must have a lot of corners.</p>
<h2>All together now</h2>
<p>Finally, here is the complete script for your reference, slicing and dicing. If you use it, it would make me happy for you to let me know, and perhaps even share your modifications here.</p>
<pre><code>@ECHO OFF
REM ===========================================================================
REM ===========================================================================
REM Elevated credential install script
REM Created by Matt Newton
REM 07.17.2012
REM matt@mnewton.com
REM
REM This script checks for Windows OS version and if Vista or 7 is detected
REM then it re-runs itself within a VBS wrapper to elevate the credentials.
REM It then runs the :install commands, cleans up temp files, and exits.
REM ===========================================================================
REM ===========================================================================
set REBOOT_FLAG=0
REM ===========================================================================
REM Check Windows Version
REM ===========================================================================
ver | findstr /i "5\.0\." &gt; nul
IF %ERRORLEVEL% == 0 goto ver_2000
ver | findstr /i "5\.1\." &gt; nul
IF %ERRORLEVEL% == 0 goto ver_XP
ver | findstr /i "5\.2\." &gt; nul
IF %ERRORLEVEL% == 0 goto ver_2003
ver | findstr /i "6\.0\." &gt; nul
IF %ERRORLEVEL% == 0 goto ver_Vista
ver | findstr /i "6\.1\." &gt; nul
IF %ERRORLEVEL% == 0 goto ver_Win7
goto warn_and_proceed
:ver_Win7
echo OS Version: Windows 7
goto elevate
:ver_Vista
echo OS Version: Windows Vista
goto elevate
REM ===========================================================================
REM Elevate credentials
REM ===========================================================================
:warn_and_proceed
echo Cannott determine Windows version, proceeding anyway...
:elevate
REM Check for permissions
&gt;nul 2&gt;&amp;1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"
REM If error flag set, we do not have admin.
if '%errorlevel%' NEQ '0' (
echo Requesting administrative privileges...
goto UACPrompt
) else ( goto gotAdmin )
:UACPrompt
echo Set UAC = CreateObject^("Shell.Application"^) &gt; "%temp%\getadmin.vbs"
echo UAC.ShellExecute "%~s0", "", "", "runas", 1 &gt;&gt; "%temp%\getadmin.vbs"
"%temp%\getadmin.vbs"
REM we are done, exiting recursive call
exit /B
REM ===========================================================================
REM Identify OS Versions
REM ===========================================================================
:ver_2000
echo OS Version: Windows 2000
goto gotAdmin
:ver_XP
echo OS Version: Windows XP
goto gotAdmin
:ver_2003
echo OS Version: Windows 2003
goto gotAdmin
:gotAdmin
if exist "%temp%\getadmin.vbs" ( del "%temp%\getadmin.vbs" )
echo We have admin privileges, proceeding...
:install
REM ===========================================================================
REM Run (privileged) Install Commands
REM ===========================================================================
:prerequisites
echo Installing prerequisites...
REM Install vc80_vcredist_x86 if not already installed
&gt;nul 2&gt;&amp;1 reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{710f4c1c-cc18-4c49-8cbf-51240c89a1a2}
if %ERRORLEVEL% == 0 (
echo. vc80_vcredist_x86 already installed
) else (
echo. Installing vc80_vcredist_x86
start /wait %~dp0vc80_vcredist_x86.exe /q
if %ERRORLEVEL% == 0 (
echo. SUCCESS
) else (
if %ERRORLEVEL% == 3010 (
echo. SUCCESS, reboot required
set REBOOT_FLAG=1
) else (
echo. ERROR = %ERRORLEVEL%
)
)
)
REM Install vc90_vcredist_x86 if not already installed
&gt;nul 2&gt;&amp;1 reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{1F1C2DFC-2D24-3E06-BCB8-725134ADF989}
if %ERRORLEVEL% == 0 (
echo. vc90_vcredist_x86 already installed
) else (
echo. Installing vc90_vcredist_x86
start /wait %~dp0vc90_vcredist_x86.exe /q
if %ERRORLEVEL% == 0 (
echo. SUCCESS
) else (
if %ERRORLEVEL% == 3010 (
echo. SUCCESS, reboot required
set REBOOT_FLAG=1
) else (
echo. ERROR = %ERRORLEVEL%
)
)
)
REM Install if on Windows 32 bit
if %processor_architecture% == x86 (
REM Test if Citrix Receiver is installed
&gt;nul 2&gt;&amp;1 dir /s "C:\Program Files\Citrix\receiver.exe"
if %ERRORLEVEL% == 0 (
echo. Citrix Receiver already installed
) else (
echo. Installing Citrix Receiver
start /wait msiexec /i %~dp0Receiver\RIInstaller.msi /passive /norestart
if %ERRORLEVEL% == 0 (
echo. SUCCESS
) else (
if %ERRORLEVEL% == 3010 (
echo. SUCCESS, reboot required
set REBOOT_FLAG=1
) else (
echo. ERROR = %ERRORLEVEL%
)
)
)
REM Install SSO Plugin if not already installed
&gt;nul 2&gt;&amp;1 dir /s "c:\Program Files\Citrix\JavaBridge.dll"
if %ERRORLEVEL% == 0 (
echo SSO Agent x86 may have the wrong modules, uninstalling
start /wait msiexec /x {A0C5486E-58A8-48FB-91ED-53881E019700} /passive /norestart
if %ERRORLEVEL% == 0 (
echo. SUCCESS
) else (
if %ERRORLEVEL% == 3010 (
echo. SUCCESS, reboot required
set REBOOT_FLAG=1
) else (
echo. ERROR = %ERRORLEVEL%
)
)
)
REM %~dp0CitrixSSOPlugin32.exe /silent SYNCPOINTTYPE=FileSyncPath SYNCPOINTLOC=\\server\CITRIXSYNC$ DI_SELECT=1 SSPR_SELECT=1 SERVICEURL="https://server/MPMService/"
REM An argument of "/forcerestart" can be added to the end to automatically restart
echo Installing Citrix Single Sign-On Plugin 5.0 32 bit
start /wait msiexec /i %~dp0SSOPlugin32\SFPDSSOPlugin32.msi /passive /norestart
if %ERRORLEVEL% == 0 (
echo. SUCCESS
) else (
if %ERRORLEVEL% == 3010 (
echo. SUCCESS, reboot required
set REBOOT_FLAG=1
) else (
echo. ERROR = %ERRORLEVEL%
)
)
)
REM Install if on Windows 64 bit
if %processor_architecture% == AMD64 (
echo Installing x64 prerequisites...
&gt;nul 2&gt;&amp;1 reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{071c9b48-7c32-4621-a0ac-3f809523288f}
if %ERRORLEVEL% == 0 (
echo. vc80_vcredist_x64 already installed
) else (
echo. Installing vc80_vcredist_x64
start /wait %~dp0vc80_vcredist_x64.exe /q
if %ERRORLEVEL% == 0 (
echo. SUCCESS
) else (
if %ERRORLEVEL% == 3010 (
echo. SUCCESS, reboot required
set REBOOT_FLAG=1
) else (
echo. ERROR = %ERRORLEVEL%
)
)
)
&gt;nul 2&gt;&amp;1 reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{4B6C7001-C7D6-3710-913E-5BC23FCE91E6}
if %ERRORLEVEL% == 0 (
echo. vc90_vcredist_x64 already installed
) else (
echo. Installing vc90_vcredist_x64
start /wait %~dp0vc90_vcredist_x64.exe /q
if %ERRORLEVEL% == 0 (
echo. SUCCESS
) else (
if %ERRORLEVEL% == 3010 (
echo. SUCCESS, reboot required
set REBOOT_FLAG=1
) else (
echo. ERROR = %ERRORLEVEL%
)
)
)
REM Test if Citrix Receiver is installed
&gt;nul 2&gt;&amp;1 dir /s "C:\Program Files (x86)\Citrix\receiver.exe"
if %ERRORLEVEL% == 0 (
echo. Citrix Receiver already installed
) else (
echo. Installing Citrix Receiver
start /wait msiexec /i %~dp0Reciever\RIInstaller.msi /passive /norestart
if %ERRORLEVEL% == 0 (
echo. SUCCESS
) else (
if %ERRORLEVEL% == 3010 (
echo. SUCCESS, reboot required
set REBOOT_FLAG=1
) else (
echo. ERROR = %ERRORLEVEL%
)
)
)
REM Install SSO Plugin if not already installed
&gt;nul 2&gt;&amp;1 dir /s "c:\Program Files (x86)\Citrix\ssoShell.exe"
if %ERRORLEVEL% == 0 (
echo SSO Agent x86 is already installed, uninstalling
start /wait msiexec /x {FC95142E-AD05-4ECB-9F13-93466D6B5C69} /passive /norestart
)
REM %~dp0CitrixSSOPlugin64.exe /silent SYNCPOINTTYPE=FileSyncPath SYNCPOINTLOC=\\server\CITRIXSYNC$ DI_SELECT=1 SSPR_SELECT=1 SERVICEURL="https://server/MPMService/"
REM An argument of "/forcerestart" can be added to the end to automatically restart
echo Installing Citrix Single Sign-On Plugin 5.0 64 bit
start /wait msiexec /i %~dp0\SSOPlugin64\SFPDSSOPlugin64.msi /passive /norestart
if %ERRORLEVEL% == 0 (
echo. SUCCESS
) else (
if %ERRORLEVEL% == 3010 (
echo. SUCCESS, reboot required
set REBOOT_FLAG=1
) else (
echo. ERROR = %ERRORLEVEL%
)
)
)
echo Installation complete
if %REBOOT_FLAG% == 0 (
echo You may need to restart the Citrix SSO Plugin manually
echo Please press any key to end the install routine
pause
exit /B
) else (
echo Please press any key to restart your computer
pause
shutdown -r -c "Citrix SSO Plugin Install" -t 0
)
</code></pre>
<h1>Credits</h1>
<p>Once again, thank you Evan Greene. I used <a href="http://sites.google.com/site/eneerge/home/BatchGotAdmin">your UAC script</a> as a starting point for this one.</p>
</div>
<div class="meta">
<ul class="meta-list">
<li class="tags">
<ul class="tag-list">
<li><a href="http://blog.mnewton.com/tagged/batch">#batch</a></li>
<li><a href="http://blog.mnewton.com/tagged/development">#development</a></li>
<li><a href="http://blog.mnewton.com/tagged/script">#script</a></li>
<li><a href="http://blog.mnewton.com/tagged/windows">#windows</a></li>
</ul>
</li>
<li class="date"><a href="http://blog.mnewton.com/post/27511333721/windows-installer-batch-script-revisited" title="Wed. July 18, 2012 @ 3:33 pm"><span class="icon"></span>3 weeks ago</a></li>
<li class="comments hidden"><a id="dsq-27511333721" href="http://blog.mnewton.com/post/27511333721/windows-installer-batch-script-revisited#disqus_thread"><span class="icon"></span>Comments</a></li>
<li class="permalink"><a href="http://blog.mnewton.com/post/27511333721/windows-installer-batch-script-revisited"><span class="icon"></span>Permalink</a></li>
<li class="share">
<a class="share-btn" href="http://tmblr.co/ZvdubyPdpQDP" data-permalink="http://blog.mnewton.com/post/27511333721/windows-installer-batch-script-revisited">Share</a>
<div class="share-box">
<div class="share-box-inside clearfix">
<input class="shortlink" type="text" readonly="" value="http://tmblr.co/ZvdubyPdpQDP">
<div class="plusone-btn"><div class="g-plusone" data-size="medium" data-count="true" data-href="http://blog.mnewton.com/post/27511333721/windows-installer-batch-script-revisited"></div></div>
<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://blog.mnewton.com/post/27511333721/windows-installer-batch-script-revisited" data-text="" data-count="none" data-via="mnewto">Tweet</a>
<div class="like-button"></div>
</div><!-- /.share-box-inside -->
</div><!-- /.share-box -->
</li><!-- /.share -->
</ul><!--/.meta-list -->
</div><!-- /.meta -->
<!--
===================================================
Begin AddThis
===================================================
-->
<div class="addthis_toolbox addthis_default_style " addthis:title="Windows Installer Batch Script Revisited" addthis:url="http://blog.mnewton.com/post/27511333721/windows-installer-batch-script-revisited">
<a class="addthis_button_facebook_like" fb:like:layout="button_count"></a>
<a class="addthis_button_tweet"></a>
<a class="addthis_button_pinterest_pinit"></a>
<a class="addthis_counter addthis_pill_style"></a>
</div>
<script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js#pubid=ra-4faa03a633844ef0"></script>
<!--
===================================================
End AddThis
===================================================
-->
</div><!-- /.post-panel -->
<div class="post-shadow"></div>
</div><!-- /.post -->
<div id="post-27509481333" class="post type-text">
<div class="post-panel">
<div class="copy">
<h2 class="post-title">Unrolling Citrix Single Sign-On Plugin</h2>
<h1>The Problem</h1>
<p>The Citrix Single Sign-On Plugin (aka Citrix Password Manager) is a decent way to manage user passwords across a typical, fairly homogeneous Windows Enterprise Environment. It is not given as much love by Citrix as I would like, and it has its quirks. But all password management systems do.</p>
<p>Today, though, I found a particulary irksome quirk. There is no way to tell the install routine NOT to install the Java Bridge module, which is used to save and replay passwords in Java applications. Most would not find this a horrible problem, but my client happens to have a Java application that is horribly broken by Citrix&#8217;s Java Bridge module. So it has to go!</p>
<p>Other modules can be easily installed, or not, using command line switches. See Citrix&#8217;s documentation:
<a href="http://support.citrix.com/proddocs/topic/passwordmanager/pm-install-agent-to-silent-install.html">To install the Password Manager agent software silently from a command prompt</a></p>
<p>You think perhaps there is an install option but it&#8217;s just not documented? I doubt this. if you comb through the install media, including the XML file (SSOPlugin32Metadata.xml), you will not find any reference at all to the Java module. It appears to be needlessly baked in.</p>
<p>How do we engineer around this deficiency?</p>
<h2>Preparation</h2>
<p>First, I grabbed the CitrixSSOPlugin32.exe from the XenApp 6.5 media. It is a self-contained .exe installer. However, like most .exe installers, it can be easily split up into its constituent parts using 7-zip or RAR.</p>
<p>Along with support files and directories, you will find two standard .msi files: one for Citrix Receiver and one for SSO.</p>
<h1>Solution: MSI Administrative Install</h1>
<p>Once I had the raw msi files, the rest is easy and well documented by Microsoft. I create an Administrative Install.</p>
<pre><code>msiexec /a "Citrix Single Sign-On.msi"
</code></pre>
<p>After running the above command, a standard install wizard popped up. I went through it as you would in a manual install until it completed.</p>
<p>Once completed, however, I was left with a new directory containing an Administrative Install, with all of the options and parameters I chose during the wizard baked directly into the installation.</p>
<p>That&#8217;s all there is to it. I did, however, think of some alternative solutions if that didn&#8217;t work.</p>
<h2>Alternative Solution #1</h2>
<p>You could use <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa370557%28v=vs.85%29.aspx">Microsoft Orca</a> to rip out the offending section. This is a very brute force way of accomplishing our goal. Simply search for Java in the modules section and delete the reference.</p>
<h2>Alternative Solution #2</h2>
<p>Lastly, if none of those options worked my last resort was to simply unlink the JavaBridge.dll:</p>
<pre><code>regsvr32.exe /u "C:\Program Files\Citrix\Password Manager\helper\JavaBridge.dll"
</code></pre>
<p>Thankfully, the administrative install worked perfectly for our case.</p>
<p>All of this would be unnecessary, however, if Citrix exposed a transform option to disable that module, just as they do for other modules in the Plugin. Please update your install routines, Citrix! There is a reason MSI files were created and when you gloss over functionality that is baked into the architecture in the first place you hurt yourselves and you hurt your users.</p>
<p>Please let me know if any of this helped you out. Cheers.</p>
</div>
<div class="meta">
<ul class="meta-list">
<li class="date"><a href="http://blog.mnewton.com/post/27509481333/unrolling-citrix-single-sign-on-plugin" title="Wed. July 18, 2012 @ 3:05 pm"><span class="icon"></span>3 weeks ago</a></li>
<li class="comments hidden"><a id="dsq-27509481333" href="http://blog.mnewton.com/post/27509481333/unrolling-citrix-single-sign-on-plugin#disqus_thread"><span class="icon"></span>Comments</a></li>
<li class="permalink"><a href="http://blog.mnewton.com/post/27509481333/unrolling-citrix-single-sign-on-plugin"><span class="icon"></span>Permalink</a></li>
<li class="share">
<a class="share-btn" href="http://tmblr.co/ZvdubyPdiLzr" data-permalink="http://blog.mnewton.com/post/27509481333/unrolling-citrix-single-sign-on-plugin">Share</a>
<div class="share-box">
<div class="share-box-inside clearfix">
<input class="shortlink" type="text" readonly="" value="http://tmblr.co/ZvdubyPdiLzr">
<div class="plusone-btn"><div class="g-plusone" data-size="medium" data-count="true" data-href="http://blog.mnewton.com/post/27509481333/unrolling-citrix-single-sign-on-plugin"></div></div>
<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://blog.mnewton.com/post/27509481333/unrolling-citrix-single-sign-on-plugin" data-text="" data-count="none" data-via="mnewto">Tweet</a>
<div class="like-button"></div>
</div><!-- /.share-box-inside -->
</div><!-- /.share-box -->
</li><!-- /.share -->
</ul><!--/.meta-list -->
</div><!-- /.meta -->
<!--
===================================================
Begin AddThis
===================================================
-->
<div class="addthis_toolbox addthis_default_style " addthis:title="Unrolling Citrix Single Sign-On Plugin" addthis:url="http://blog.mnewton.com/post/27509481333/unrolling-citrix-single-sign-on-plugin">
<a class="addthis_button_facebook_like" fb:like:layout="button_count"></a>
<a class="addthis_button_tweet"></a>
<a class="addthis_button_pinterest_pinit"></a>
<a class="addthis_counter addthis_pill_style"></a>
</div>
<script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js#pubid=ra-4faa03a633844ef0"></script>
<!--
===================================================
End AddThis
===================================================
-->
</div><!-- /.post-panel -->
<div class="post-shadow"></div>
</div><!-- /.post -->
<div id="post-27497506397" class="post type-quote">
<div class="colored-panel">
<blockquote class="quote-text">The mass of men lead lives of quiet desperation. What is called resignation is confirmed desperation.</blockquote>
</div>
<div class="post-panel">
<div class="quote-nipple"></div>
<div class="copy">
Henry David Thoreau
</div>
<div class="meta">
<ul class="meta-list">
<li class="date"><a href="http://blog.mnewton.com/post/27497506397/the-mass-of-men-lead-lives-of-quiet-desperation" title="Mon. June 18, 2012 @ 10:43 am"><span class="icon"></span>1 month ago</a></li>
<li class="comments hidden"><a id="dsq-27497506397" href="http://blog.mnewton.com/post/27497506397/the-mass-of-men-lead-lives-of-quiet-desperation#disqus_thread"><span class="icon"></span>Comments</a></li>
<li class="permalink"><a href="http://blog.mnewton.com/post/27497506397/the-mass-of-men-lead-lives-of-quiet-desperation"><span class="icon"></span>Permalink</a></li>
<li class="share">
<a class="share-btn" href="http://tmblr.co/ZvdubyPc_gPT" data-permalink="http://blog.mnewton.com/post/27497506397/the-mass-of-men-lead-lives-of-quiet-desperation">Share</a>
<div class="share-box">
<div class="share-box-inside clearfix">
<input class="shortlink" type="text" readonly="" value="http://tmblr.co/ZvdubyPc_gPT">
<div class="plusone-btn"><div class="g-plusone" data-size="medium" data-count="true" data-href="http://blog.mnewton.com/post/27497506397/the-mass-of-men-lead-lives-of-quiet-desperation"></div></div>
<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://blog.mnewton.com/post/27497506397/the-mass-of-men-lead-lives-of-quiet-desperation" data-text="" data-count="none" data-via="mnewto">Tweet</a>
<div class="like-button"></div>
</div><!-- /.share-box-inside -->
</div><!-- /.share-box -->
</li><!-- /.share -->
</ul><!--/.meta-list -->
</div><!-- /.meta -->
<!--
===================================================
Begin AddThis
===================================================
-->
<div class="addthis_toolbox addthis_default_style " addthis:title="MN | Matthew Sojourner Newton" addthis:url="http://blog.mnewton.com/post/27497506397/the-mass-of-men-lead-lives-of-quiet-desperation">
<a class="addthis_button_facebook_like" fb:like:layout="button_count"></a>
<a class="addthis_button_tweet"></a>
<a class="addthis_button_pinterest_pinit"></a>
<a class="addthis_counter addthis_pill_style"></a>
</div>
<script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js#pubid=ra-4faa03a633844ef0"></script>
<!--
===================================================
End AddThis
===================================================
-->
</div><!-- /.post-panel -->
<div class="post-shadow"></div>
</div><!-- /.post -->
<!-- END POSTS -->
<div id="pagination">
<div class="nextprev">
<span>&larr; Newer</span> <span class="sep">&bull;</span>
<a class="next" href="/page/2"><span>Older &rarr;</span></a>
</div>
<div class="current-page">Page 1 <em>of</em> 3</div>
</div><!--/#pagination -->
</div><!-- /#content -->
<!-- SIDEBAR -->
<div id="sidebar">
<div id="blog-info" class="side-box">
<p><a href="/"><img class="large-portrait" src="http://static.tumblr.com/zvdakki/oeHm7ddj1/085.jpg" alt="Portrait/Logo"/></a></p>
<div class="description">
A blog by Matthew Sojourner Newton sharing some things I've learned
<br><br>
<a href="http://mnewton.com">mnewton.com</a>
<br><br>
<a href="http://internetdefenseleague.org"><img src="http://internetdefenseleague.org/images/badges/final/super_badge.png" alt="Member of The Internet Defense League" /></a>
<br><br>
<!--Tumblr Tag Cloud [2012-07-31]-->
<script type="text/javascript" src="http://rive.rs/javascripts/tumblr.min.js?css=default&minsize=120&maxsize=180"></script>
</div><!--/.description-->
</div><!--/#blog-info -->
<div class="side-box ruled-top">
<h2>my other stuff</h2>
<ul id="socialize">
<li class="twitter"><a href="http://www.twitter.com/mnewto" title="@mnewto on Twitter">@mnewto on Twitter</a></li>
<li class="pinboard"><a href="http://pinboard.in/u:mnewt" title="mnewt on Pinboard">mnewt on Pinboard</a></li>
<li class="linkedin"><a href="http://www.linkedin.com/in/mnewt" title="Linkedin Profile">Linkedin Profile</a></li>
<li class="github"><a href="http://github.com/mnewt" title="mnewt on github">mnewt on github</a></li>
</ul>
</div>
<div id="twitter" class="side-box ruled-top">
<h2>Twitter</h2>
<p class="loading-text">loading tweets&hellip;</p>
</div>
<!-- LIKES -->
<div id="side-likes" class="side-box ruled-top">
<h2>I Dig These Posts</h2>
<a class="more-likes" href="/liked/by/mnewt">See more &rarr;</a>
</div>
<!-- END LIKES -->
<!--
===================================================
Begin feedwind
===================================================
-->
<script type="text/javascript">
<!--
rssmikle_url="http://feeds.pinboard.in/rss/u:mnewt/";
rssmikle_frame_width="175";
rssmikle_frame_height="350";
rssmikle_target="_blank";
rssmikle_font="Arial, Helvetica, sans-serif";
rssmikle_font_size="12";
rssmikle_border="on";
rssmikle_css_url="";
rssmikle_title="on";
rssmikle_title_bgcolor="#f3465a";
rssmikle_title_color="#fffadc";
rssmikle_title_bgimage="http://";
rssmikle_item_bgcolor="#FFFFFF";
rssmikle_item_bgimage="http://";
rssmikle_item_title_length="50";
rssmikle_item_title_color="#666666";
rssmikle_item_border_bottom="off";
rssmikle_item_description="off";
rssmikle_item_description_length="40";
rssmikle_item_description_color="#666666";
rssmikle_item_description_tag="off";
rssmikle_item_podcast="icon";
//-->
</script>
<script type="text/javascript" src="http://feed.mikle.com/js/rssmikle.js"></script>
<div style="font-size:10px; text-align:right;">
<a href="http://feed.mikle.com/en/" target="_blank" style="color:#CCCCCC;">FeedWind</a>
<!--Please display the above link in your web page according to Terms of Service.-->
</div>
<!--
===================================================
End feedwind
===================================================
-->
</div><!-- /#sidebar -->
<!-- FOOTER -->
<div id="footer">
<div id="footer-end" class="ruled-top">
<ul id="footer-links">
<li><a href="/rss">RSS</a></li>
<li><a href="/random">Random</a></li>
<li><a href="/archive">Archive</a></li>
<li><a href="/ask">Ask me something</a></li>
<li><a href="/mobile">Mobile</a></li>
</ul>
<p class="credits"><a href="http://effectortheme.tumblr.com">Effector Theme</a> by <a href="http://www.carlofranco.ca">Carlo Franco</a>.</p>
<span class="tumblr">Powered by <a href="http://www.tumblr.com/">Tumblr</a></span>
</div><!-- /#footer-end -->
</div><!-- /#footer -->
</div><!-- /#page -->
<!-- Footer Scripts -->
<script type="text/javascript">(function(B,C){B[C]=B[C].replace(/\bno-js\b/,'js')})(document.documentElement,'className');</script>
<script src="http://static.tumblr.com/xgwqnql/XPSlbx7np/jquery-1.4.4.min.js"></script>
<script src="http://static.tumblr.com/njty47g/d1Mlpn53c/plugins.js"></script>
<script src="http://static.tumblr.com/xgwqnql/41Lluodtm/effector-1.2.6.min.js"></script>
<script src="http://platform.twitter.com/widgets.js"></script>
<script src="https://apis.google.com/js/plusone.js" type="text/javascript"></script>
<script type="text/javascript">
var _gaq=[["_setAccount","UA-32103756-1"],["_trackPageview"]];
(function(d,t){
var g=d.createElement(t), s=d.getElementsByTagName(t)[0];
g.async=1;
g.src=("https:"==location.protocol?"//ssl":"//www")+".google-analytics.com/ga.js";
s.parentNode.insertBefore(g,s)
}(document,"script"));
</script>
<!-- ======================= Begin Prettify ============================-->
<link rel="stylesheet" type="text/css" rel="stylesheet" href="themes/tomorrow-night-eighties.css">
<script type="text/javascript" src="wrapper.min.js"></script>
<!-- ======================== End Prettify =============================-->
<!-- BEGIN TUMBLR CODE --><iframe src="http://assets.tumblr.com/iframe.html?10&src=http%3A%2F%2Fblog.mnewton.com%2F&amp;lang=en_US&amp;name=mnewt" scrolling="no" width="330" height="25" frameborder="0" style="position:absolute; z-index:1337; top:0px; right:0px; border:0px; background-color:transparent; overflow:hidden;" id="tumblr_controls"></iframe><!--[if IE]><script type="text/javascript">document.getElementById('tumblr_controls').allowTransparency=true;</script><![endif]--><script type="text/javascript">_qoptions={qacct:"p-19UtqE8ngoZbM"};</script><script type="text/javascript" src="http://edge.quantserve.com/quant.js"></script><noscript><img src="http://pixel.quantserve.com/pixel/p-19UtqE8ngoZbM.gif" style="display:none; border-width:0px; height:1px; width:1px;" alt=""/></noscript><!-- END TUMBLR CODE -->
</body>
</html>
Something went wrong with that request. Please try again.