powershell获取msi的productCode和UpgradeCode方法

一个完全由自己维护的打包项目再提交产品的时候因为自己的疏漏,忘记修改产品id了,导致两个有共存关系的产品呢,只能安装一个,不过所幸虽然已经交付,但是没有完全上线,而且这个问题是自己在测试其他功能的时候顺带发现的(PS:测试也没发现呢0_0),所以还算比较及时,把产品追回了,重新生成了一版提交上去了。

当然,这个事故也给我们整个研发测试团队敲了个警钟(PS:感谢老大,直接找产品部门把项目追回了,没有惊动技术总监,不然我怕是得挨训,闹不好KPI甚至职业生涯也要受影响,当然,测试那边估计也不好受,哈哈,吐槽有点多),言归正传,我专门写了正式邮件给我的经理(不是技术总监)以及测试的老大,有关这个事情以及给测试的建议。好了,测试一封回信我又给自己找了个新活(提供一种手段可以获得msi的productCode和UpgradeCode  \0_0/)。happy!快乐!

首先我想到的是右键msi文件查查属性,没准直接有我想要的(印象中好像在属性里有看到类似的),

上bing搜一搜看咯,没准有现成的。当然,百度也同时在看。倒也有点收获:

一个来自CSDN的方法分享,使用记事本打开对应的msi文件,可以看到一堆乱码,其中也夹杂着一些可见数据,使用ctrl+f打开搜素栏,搜索ProductCode,会索引到对应的productCode,ProductName,则是对应的UpgradeCode。

可惜这个并不能满足我的要求,因为我需要能够将他输出出来,而不是由别人自己去找(其实也行,主要测试不乐意,嫌麻烦),那没办法,怎么搞呢,想想有没有其他的方法。不过从上面的例子我已经知晓这个所谓的productCode是打包之后也可见的,并不如我初期预测的只能在打包前在VS里面看到。既然这样的话,那是不是有现成的接口可以供我使用。所以我来到了MSDN,开始搜ProductCode和getProductCode等字眼.还真让我找到了,一个名为msi.dll的动态库

UINT MsiGetProductCodeA(
  LPCSTR szComponent,
  LPSTR  lpBuf39
);

get_ProductCode(string Component)

 可以通过下面的函数获取ProductCode,但是,我并没有在这里找到UpgradeCode相关的函数,另一方面,因为没有这样玩过,所以搞了个小的用来测试的项目,打算写个小demo测试一把效果,但是我有点愁,貌似我没法直接断点去看(不讨论msi点击安装后附件到进程这种骚操作,即使这样,如果涉及创建子进程用完就杀那种也不好搞,之前调试另一个msi的时候就遇到这问题),那打log呗,写了点打log的函数,生成个日志文件,写点内容,生成安装包,当我真正把生成的安装包拿到我的测试虚机进行安装的时候,我发现事情貌似并不如我所料想的那么简单,开始时安装失败,调试了一会安装成功了,但是我想要的产品id并没有打印出来,不知道是调用函数有问题还是参数传入不正确,反正毫无反应。

没招啊,又开始了百度,突然发现一个帖子里提到使用powershell的方法去获取ProdutCode,仔细瞄了一眼发现和我需求完全一样,果断就抛弃了第二方案!

说到这,就不得不提接下来的主角——get-wmiobject,作为一个powershell命令他背负了太多太多,看看官方解释

翻译过来就是获取Windows Management Instrumentation(WMI)类的实例或有关可用类的信息。通俗的讲,这个搞了个对象出来,当然,搞对象得有类啊,那么,第二主角也将出场——Win32_Product,WMI类,代表由Windows Installer安装的产品。有了这两个东西,我们想要的东西基本就完全了,来看我们两个主角的第一次双剑合璧!

emmm,不小心暴露姓氏了,言归正传,上面的IdentifyingNumber就是我想要的ProductCode,林列出来的只是安装的msi的部分属性,还有好多没有显示出来,那么怎么搞到另一个我想要的UpgradeCode呢,没思路啊,我又开始孜孜不倦的看起了MSDN,一个用例吸引了我的注意力,原文链接在这咯-》点这里

Get-WmiObject -Query "select * from win32_service where name='WinRM'" -ComputerName Server01, Server02 | Format-List -Property PSComputerName, Name, ExitCode, Name, ProcessID, StartMode, State, Status

PSComputerName : SERVER01
Name           : WinRM
ExitCode       : 0
Name           : WinRM
ProcessID      : 844
StartMode      : Auto
State          : Running
Status         : OK

PSComputerName : SERVER02
Name           : WinRM
ExitCode       : 0
Name           : WinRM
ProcessID      : 932
StartMode      : Auto
State          : Running
Status         : OK

这不就是索引条件嘛,瞌睡有人送枕头,可是这玩意怎么写呢,我又开始了自己的上网淘宝,有货!

gwmi -Query "SELECT ProductCode,Value FROM Win32_Property WHERE Property='UpgradeCode'" | Format-Table ProductCode,Value

舒服啊,一个索引,后面我加了格式化输出,将我想要的数据都打了出来,看看截图

到了这一步,其实已经基本解决问题了,但是还差个临门一脚,怎么把我想要的那个产品输出出来呢。

首先,我有个已经输出的表格,一个ProductCode对应一个UpgradeCode,然后我通过产品名字分辨出了我的msi的具体的ProductCode。这种情况下,加上几个变量,加个过滤条件,我觉着,应该就差不多解决问题了。程序员嘛,复制大师和拼接组装大师!下面就是我的完全体的脚本了。

$tmpCKBNmae = $args[0]

if (!$tmpCKBNmae)
{ 
    Write-Host "error: No Parameter!"
    return 
}

$tmpList = get-wmiobject Win32_Product

foreach($tmp in $tmpList)
{
    $testtmp = $tmp 
     if (!$testtmp.Name.ToString().CompareTo($tmpCKBNmae))
     {
       $ProductCode = $testtmp.IdentifyingNumber
       break
     }
}

$UpgradeCodeList = gwmi -Query "SELECT ProductCode,Value FROM Win32_Property WHERE Property='UpgradeCode'" | Format-Table ProductCode,Value

$UpgradeCodeList | findstr $ProductCode

通过一些条件的过滤,只需要在调用或者脚本的时候传入对应的msi名称,就可以将机器上已经安装的指定名字的MSI文件的productCode和UpgradeCode输出至命令行,完结散花!

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值