The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

如何將自訂參數傳入 Installer 類別的 Install 方法 ( Part 2 )

若希望可以在透過 msiexec 進行靜默安裝時能夠傳入自訂的屬性(PROPERTY)到自訂動作(Custom Action)中,然後再透過自訂動作的 CustomActionData 屬性傳入實做自訂動作的 Installer 類別中,之前試過一次但不成功,還以為是 Msi 格式的限制,直到最近我終於找出方法與真正的限制所在了。

使用 VS Setup Project 設定使用者介面時,你可以自訂屬性:

VS Setup Project 設定使用者介面

如上圖示,我自訂了一個 SQLIP 屬性,因此你可以在自訂動作中設定傳入 CustomActionData 屬性:

VS Setup Project 設定自訂動作

你從上圖可以發現 [SQLIP] 是「屬性值」的變數,而 /sqlipsqlip 就是傳入 Installer 類別的參數名稱,所以你就可以在你的 Installer 類別中使用 Context.Parameters["sqlip"] 取得該參數的值,如下範例:

SqlConnection conn = new SqlConnection();

SqlConnectionStringBuilder scsb = new SqlConnectionStringBuilder();

void ProjectInstaller_BeforeInstall(object sender, InstallEventArgs e)
{
	// 除錯用
	//System.Diagnostics.Debugger.Launch();

	scsb.DataSource = this.Context.Parameters["sqlip"];
	scsb.UserID = this.Context.Parameters["sqlid"];
	scsb.Password = this.Context.Parameters["sqlpw"];
	scsb.PersistSecurityInfo = true;
	scsb.InitialCatalog = this.Context.Parameters["dbname"];

	// 指派 conn.ConnectionString
	conn.ConnectionString = scsb.ConnectionString;

	// 將 conn.ConnectionString 儲存到 savedState 中
	e.SavedState["connectionString"] = scsb.ConnectionString;
}

以上就是將自訂屬性傳入 Installer 類別執行的方法,也算是標準作法。

不過,通常專業人士都不屑利用 使用者介面(User Interface) 進行安裝 系統管理員通常要透過 AD 搭配 msiexec 的靜默安裝進行全公司的軟體部署。我一直都認為 msiexec 應該可以透過指令列參數傳入屬性值,只是之前在實驗時卻發現傳入的屬性都會被蓋掉,一直都試不出來。一般來說,透過 Command Line 進行靜默安裝並傳入自訂屬性(PROPERTY)的方式如下:

msiexec /i Service1Setup.msi /quiet /passive /l*v Install.log SQLIP="(local)\SQLEXPRESS"

以上指令的重點在最後面那個 SQLIP="(local)\SQLEXPRESS" 參數,雖然我們可以透過這種方式傳入 PROPERTY 進去,不過我經過長時間的測試與研究 Install.log (安裝紀錄) 發現,原來 msiexec 在載入 PROPERTY 時會先讀入從 Command Line 進來的屬性,並且正確合併到 MSI 安裝程序中。但接著卻會讀取在使用者介面中定義的 PROPERTY 預設值,並再一次合併到 MSI 安裝程序中,所以這才會造成原本從 msiexec 指令傳入的屬性不見了,也因此造成無法透過 Command Line 傳入屬性到 msi 安裝過程中的錯誤假象!

瞭解了這個特性後這才知道,只要透過 Command Line 傳入的 PROPERTY 名稱 User Interface 中定義的 PROPERTY 名稱不要重複,就可以全部放入 Custom ActionsCustomActionData 裡面,並全部傳入 Installer 類別的各個事件中,而要讀取哪些屬性參數你就可以在程式裡面自行判斷了!

如果你在 User Interface 中定義的屬性值預設是空值的話,你還也可以運用以下技巧進行設計,可以不用定義兩個不同名但相同用途的屬性:

VS Setup Project 設定使用者介面

如上圖例,你原本在 User Interface 中定義的屬性名為 SQLPW,但預設值設定為 [SQLPW_S],因為在 Setup Project 裡的所有設定值只要出現中刮號 [ ] 框起來的都稱之為 屬性(PROPERTY) 且都是以英文大寫表示,當屬性找不到時會自動以空字串替代。

這也代表著你就可以從 Command Line 將 SQLPW_S 屬性傳入,如下範例:

msiexec /i Service1Setup.msi /quiet /passive /l*v Install.log SQLPW_S="ThisIsPassword"

最後你原本定義在 自訂動作 視窗中設定的 CustomActionData 完全不需要特別修改,因為當靜默安裝執行時,[SQLPW_S] 屬性值會被傳入 User Interface 中定義 [SQLPW] 屬性中。
備註:如上段文章所述,MsiExec 是先讀取 Command Line 傳入的 Property 然後才解析 User Interface 中定義的 Property 喔!

參考連結