安国圣山刁景超 發表於 2014-7-16 10:57:52

VB.NET中调用MSI卸载软件的2个方法

<p>最近在折腾组里面的那个破Lab,要自己写程序每天安装最新版本的build。而今天手头上没有任何任务,所以把用到的一些东西记下来以供今后参考。这篇日志来记录如何在.NET中卸载别的软件。</p>
<p><strong>一、直接使用MSI安装包</strong></p>
<p>  如果你知道MSI安装程序的路径,那么显然可以直接使用即可:<br />
<div class="codetitle"><span><U>复制代码</U></span> 代码如下:</div><div class="codebody" id="code67586"><br />
msiexec /x "C:Table Manager Clients.msi" /quiet /qn<br />
</div></p>
<p>/quiet参数表示自动卸载,/qn表示 显示任何UI。</p>
<p>  这个方法很简单,推荐使用。但是如果软件的版本不对,或者安装程序做得有问题(比如我们这做的一个奇葩安装程序),那么就不行了。</p>
<p><div class="codetitle"><span><U>复制代码</U></span> 代码如下:</div><div class="codebody" id="code59300"><br />
msiexec /Option &lt;Required Parameter&gt; <br />
&nbsp;&nbsp;&nbsp; <br />
Install Options<br />
&nbsp;&nbsp;&nbsp; &lt;/package | /i&gt; &lt;Product.msi&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Installs or configures a product</p>
<p></div></p>
<p> 但是这个序列号是不定的,对于相同程序的不同版本,序列号也不一定相同(可能会生成一个新的序列号)。为了得到需要产品的序列号,就只能去查注册表了。</p>
<p><strong>二、使用产品序列号卸载程序</strong></p>
<p>  所有用MSI安装的程序都会记录在HKEY_LOCAL_MACHINE的SOFTWAREMicrosoftWindowsCurrentVersionInstallerUserDataS-1-5-18Products子健下。S-1-5-18是系统通用的用户,可能有其他的用户目录(比如我这有S-1-5-21-2109753547-707883502-1543859470-98763),应该是对应的在安装时不共享的那些程序。</p>
<p><img src="https://img.jbzj.com/file_images/article/201407/2014716105821677.jpg?2014616105836" alt="" /></p>
<p> 如上图,在Products键下有一大堆十六进制的数字。在数字下可能有InstallProperties子键(注意不是每一个都有),然后有DisplayName用于标识产品的名称,DisplayVersion用于显示版本号等等。我们只需要关注会用到的就行了,这里就只关注产品名称吧。</p>
<p>在左侧显示的数字并不是用于msi卸载的产品序列号。我们注意到有一个UninstallString属性,这个属性就是卸载这个程序的命令及参数:<br />
<div class="codetitle"><span><U>复制代码</U></span> 代码如下:</div><div class="codebody" id="code37274"><br />
MsiExec.exe /X{4B9E6EB0-0EED-4E74-9479-F982C3254F71}<br />
</div></p>
<p>那么,我们要做的很显然是搜索这些键,查找哪一个才是我们要卸载的产品,然后用UninstallString把它卸掉就行了。另外我们需要在参数上加上/quiet和/qn参数,这样就能实现自动卸载了。<br />
<div class="codetitle"><span><U>复制代码</U></span> 代码如下:</div><div class="codebody" id="code76795"><br />
Private Sub UninstallMsi(productName As String)<br />
&nbsp;&nbsp;&nbsp; Dim reg_path As String = "SOFTWAREMicrosoftWindowsCurrentVersionInstallerUserDataS-1-5-18Products"<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp; Dim key As RegistryKey = Registry.LocalMachine.OpenSubKey(reg_path)<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp; For Each temp_key_name As String In key.GetSubKeyNames()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dim temp_key As RegistryKey = key.OpenSubKey(temp_key_name &amp; "InstallProperties")<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If temp_key IsNot Nothing Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If temp_key.GetValue("DisplayName").ToString.Trim.ToLower = productName.Trim.ToLower Then<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dim uninstall_string As String = temp_key.GetValue("UninstallString").ToString<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uninstall_string = uninstall_string.ToLower.Replace("msiexec.exe", "").Replace("msiexec", "").ToUpper<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uninstall_string = uninstall_string.Replace("/I", "/x")<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uninstall_string = uninstall_string.Replace("/i", "/x")<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uninstall_string &amp;= " /quiet /qn"<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("Uninstalling product " &amp; uninstall_string)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LogDataAccess.InsertApplicationLog(TMConfigrationManager.GetConfig("ServerType"), _<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Uninstalling " &amp; productName &amp; """" &amp; uninstall_string &amp; """ ...")<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dim proc_start_info As New ProcessStartInfo("msiexec", uninstall_string)<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dim proc As Process = Process.Start(proc_start_info)<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If (proc IsNot Nothing) Then proc.WaitForExit()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If proc.ExitCode &lt;&gt; 0 Then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dim err_message As String = "Uninstall " &amp; productName &amp; " failed."<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LogDataAccess.InsertApplicationLog(TMConfigrationManager.GetConfig("ServerType"), err_message)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine(err_message)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; End If<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LogDataAccess.InsertApplicationLog(TMConfigrationManager.GetConfig("ServerType"), "Uninstall previous version of " &amp; productName &amp; " successful.")<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Exit Sub<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; End If<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; End If<br />
&nbsp;&nbsp;&nbsp; Next<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp; Dim message As String = "Cannot find " &amp; productName &amp; " registry entries. Do not need to uninstall."<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp; LogDataAccess.InsertApplicationLog(TMConfigrationManager.GetConfig("ServerType"), message)<br />
&nbsp;&nbsp;&nbsp; Console.WriteLine(message)<br />
End Sub<br />
</div></p>
<p>.NET中访问注册表的类封装在Microsoft.Win32命名空间下,直接使用即可(主要使用RegistryKey类,RegisitryKey类似树形结构)。</p>
<p>  这就是实现自动卸载的代码(里面有一些与输出日志相关的代码,可以不用管它)。</p>
<p>  程序首先在Products键下搜索所有的产品,如果有InstallProperties子键,就匹配DisplayName是否与要卸载的程序相同,如果相同,就生成一个卸载的命令并启动一个新的进程进行卸载。</p>
<p>  如果卸载失败,msiexec会返回一个不为0的数值,此时我们将错误信息输出。(注意:还有两个数值表示卸载成功但是需要重启,请自行查找相关手册。)</p>
                           
                            <div class="art_xg">
                              
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: VB.NET中调用MSI卸载软件的2个方法