Jamyy's Weblog

Windows Batch + VBS: 自動安裝 / 移除軟體

by Jamyy on 四月.28, 2012, under Coding


執行 action.bat 自動移除 FortiClient Lite 防毒軟體, 重開機後自動安裝 Avira Free AntiVirus

action.bat

@echo off
echo Please wait...

REM 複製小紅傘安裝程式到 temp 資料夾
copy "%~dp0avira_free_antivirus_zhtw.exe" %temp% >nul

REM 匯入防止小紅傘出現廣告視窗的機碼; 這部分的機碼是在群組原則 (gpedit.msc) 設置路徑規則所得
reg import "%~dp0policies.reg" >nul

REM 開機後自動安裝小紅傘防毒軟體; 若不以 cmd /c start 方式執行則必須等安裝完成後才能進入桌面
reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce /f /v installer /t REG_SZ /d "cmd /c start %temp%\avira_free_antivirus_zhtw.exe" >nul

REM 匯出 Uninstall 清單 (控制台 → "新增或移除程式" 內容的機碼)
reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall /s > %temp%\uninstall.txt

REM 以 VBScript 接手處理剛剛匯出的檔案
wscript "%~dp0script.vbs"

參考資料: GPO--群組原則匯出與匯入~ @ averykao的部落格 :: 痞客邦 PIXNET ::

script.vbs

set objShell = CreateObject("WScript.Shell")
set objFSO = CreateObject("Scripting.FileSystemObject")
strTempPath = objShell.ExpandEnvironmentStrings("%temp%") '取得環境變數

'讀入 uninstall.txt
set objFile = objFSO.OpenTextFile(strTempPath & "\uninstall.txt", 1) '0=Append, 1=Read, 2=Write

'尋找 FortiClient Lite 的移除資訊 (UninstallString)
strLine = "" '存放逐行讀入的內容
strRegistry = "" '組合單一機碼底下的所有內容
boolFlag = False '是否已經找到 DisplayName = FortiClient Lite

Do Until objFile.AtEndOfStream
	'逐行讀入檔案內容
	strLine = objFile.ReadLine
	If InStr(strLine, "HKEY_LOCAL_MACHINE") = 1 Then
		'如果已經找到 FortiClient Lite 機碼就結束迴圈
		If boolFlag Then Exit Do
		'清空 strRegistry 以便開始組合該機碼底下的所有數值項目
		strRegistry = ""
	ElseIf InStr(strLine, "DisplayName") > 0 and InStr(strLine, "FortiClient Lite") > 0 Then
		'找到 FortiClient Lite, 將 boolFlag 設為 True
		boolFlag = True
	End If
	'以 Chr(13) 作為字串轉陣列的分隔字元
	strRegistry = strRegistry & strLine & Chr(13)
Loop

strUninst = "" '存放反安裝指令
If boolFlag Then
	'boolFlag = True 表示系統裝有 FortiClient Lite, 找出反安裝指令來進行移除作業
	aryRegistry = Split(strRegistry, Chr(13))
	For i = 0 To Ubound(aryRegistry) - 2
		If InStr(aryRegistry(i), "UninstallString") > 0 Then
			strUninst = Mid(aryRegistry(i), InStr(aryRegistry(i), "REG_EXPAND_SZ") + 14)
			'將原本 /I{機碼} 改成 /x{機碼} /quiet /forcerestart 默默的在背景進行移除作業並強制重開機
			strUninst = Replace(strUninst, "/I", "/x") & " /quiet /forcerestart"
			Exit For
		End If
	Next
	'執行反安裝指令
	objShell.Run "cmd /c " & strUninst, 0, True '0=背景執行, True=等候作業完成
Else
	'不需移除 FortiClient Lite 就直接安裝小紅傘防毒軟體
	objShell.Run "cmd /c reg delete HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce /v installer /f", 0 '0=背景執行
	objShell.Run strTempPath & "\avira_free_antivirus_zhtw.exe"
End If

參考資料: VBScript Commands

policies.reg

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers\0\Paths]

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers\0\Paths\{2cb84e55-d2e8-4dd7-b317-8ea6e897c630}]
"LastModified"=hex(b):00,b1,3d,da,8c,23,cd,01
"Description"=""
"SaferFlags"=dword:00000000
"ItemData"="C:\\Program Files\\Avira\\AntiVir Desktop\\avnotify.exe"

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers\0\Paths\{7caba076-33a4-4e0d-9e65-9fa7ce1fbe5c}]
"LastModified"=hex(b):b0,07,3d,e8,8c,23,cd,01
"Description"=""
"SaferFlags"=dword:00000000
"ItemData"="C:\\Program Files\\Avira\\AntiVir Desktop\\avnotify.dll"

policies.reg 額外說明:

  1. 匯入後雖然無法在 gpedit.msc 看到這兩個路徑規則, 但確實是有效的
  2. 可應用在 Windows XP Pro (32位元) & Windows 7 Ultimate (32位元), 其餘版本沒試過

---

附錄: 失敗的作品 - 原本想用一個批次檔搞定, 但效率實在太差, UninstallString 的取用也有問題, 所以作罷

@echo off
for /f "skip=2 tokens=*" %%i in ('2^>nul reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"') do (
	for /f "skip=4 delims=REG_SZ tokens=2*" %%j in ('2^>nul reg query "%%i" /v "DisplayName"') do (
		for /f "usebackq tokens=*" %%k in (`"echo %%j | find "FortiClient Lite""`) do (
			for /f "skip=4 delims=REG_EXPAND_SZ tokens=2*" %%l in ('reg query %%i /v "UninstallString"') do (
				echo %%l
			)
		)
	)
)

參考資料: How to capture the uninstall string



:,