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

若希望可以在透過 [msiexec](http://technet.microsoft.com/zh-tw/library/cc759262.aspx) 進行靜默安裝時能夠傳入自訂的屬性(PROPERTY)到自訂動作(Custom Action)中，然後再透過自訂動作的 CustomActionData 屬性傳入實做自訂動作的 Installer 類別中，[之前](/post/2009/02/28/How-to-pass-custom-parameters-into-Installer-Install-method)試過一次但不成功，還以為是 Msi 格式的限制，直到最近我終於找出方法與真正的限制所在了。

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

![VS Setup Project 設定使用者介面](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/4fd2e043dddb45d31e7c-image_3.png "VS Setup Project 設定使用者介面")

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

![VS Setup Project 設定自訂動作](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/bb8c5c88fc861d86ca8f-image_6.png "VS Setup Project 設定自訂動作")

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

```csharp
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](http://technet.microsoft.com/zh-tw/library/cc759262.aspx) 的靜默安裝進行全公司的軟體部署。我一直都認為 [msiexec](http://technet.microsoft.com/zh-tw/library/cc759262.aspx) 應該可以透過指令列參數傳入屬性值，只是之前在實驗時卻發現傳入的屬性都會被蓋掉，一直都試不出來。一般來說，透過 Command Line 進行**靜默安裝**並傳入**自訂屬性**(PROPERTY)的方式如下：

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

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

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

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

![VS Setup Project 設定使用者介面](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/79119ab6378e8af0b6d1-image_7.png "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 喔!*

**參考連結**

-   [MsiExec.exe Command-Line Options](http://msdn.microsoft.com/en-us/library/aa367988\(VS.85\).aspx)
-   [MsiExec.exe Command-Line Parameters](https://learn.microsoft.com/en-us/windows/win32/msi/command-line-options)
-   [How to Use Property Reference Command-Line Parameters with Msiexec.exe](https://web.archive.org/web/20130619235938/http://support.microsoft.com/kb/230781/en-us)
-   [How to Add Command Line Support with Your .MSI](http://blogs.msdn.com/helloworld/archive/2009/02/06/how-to-add-command-line-support-with-your-msi.aspx) ( 這是另一種 Solution 但我看不懂 )
-   [An Installation Example](http://msdn.microsoft.com/en-us/library/aa367563\(VS.85\).aspx)
-   Installer Custom Actions and Command Line Arguments
