﻿# 移動服務所需的檔案時應連帶複製完整的 NTFS ACLs 資訊

在幾年前曾經有一次因為擅自移動了 Hyper-V 裡所有的 VM 設定檔與 VHD 虛擬硬碟到另一顆硬碟，結果導致 Hyper-V 無法正常開啟該虛擬機，後來發現原來是檔案的 NTFS 相關資訊沒有複製過去的關係而導致 Hyper-V 的權限不足以致於無法正確開啟 VM 執行。前幾天又遇到了類似的情況，我為了將 SQL Server 完整的系統檔案、紀錄、系統資料庫與使用者資料庫都完整的移至另一台硬碟，這次就知道要小心複製這些檔案，以免又因為權限不足而導致 SQL Server 無法開啟。

重要觀念參考：[注意 Windows 對於檔案複製與搬移的 NTFS 權限變化 \[重要\]](/post/2010/02/25/NTFS-file-permission-changes-during-copy-and-move.aspx)

這次我選擇用 Windows Server 2008 內建的 **robocopy** 工具來複製該硬碟內所有的檔案到另一台，由於 **robocopy** 在複製目錄的時候可以設定「複製選項」，如下圖示，你可以設定除了複製 **資料** (D) 、**屬性** (A) 與 **時間戳記** (T) 之外，還能額外的複製 **NTFS ACL 安全性** (S)、**擁有者資訊** (O) 與 **稽核資訊** (U)，透過完整的選項設定，你將能夠複製最完整的檔案到另一台硬碟。

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/cf0951a2e64b8a800c3d-image_1016.png)

預設的情況下，複製目錄時並不會保留「目錄時間戳記」，所以複製完後所有目錄的時間都會被改成複製當時的時間，如果你連目錄的更新時間都要保留的話，建議也加上 **/DCOPY:T**  選項。

假設我們想從 D:\\ 複製到 E:\\ 的話，那麼你可以使用以下指令進行複製：

```
robocopy D:\ E:\ /E /COPY:DATSOU /DCOPY:T /XD "System Volume Information"
```

以上語法也可以將 /COPY:DATSOU 簡寫成 /COPYALL

```
robocopy D:\ E:\ /E /COPYALL /DCOPY:T /XD "System Volume Information"
```

從上述指令你可以發現，為了複製完整的磁碟檔案與目錄，我加上了 **/E** 參數，如此一來便能複製所有的子目錄，而且還包括空的子目錄。

另一個選項則是排除一個無法複製的 **System Volume Information** 系統目錄，這個目錄為系統隱藏目錄，但是 robocopy 看的見，因此最好設定為排除目錄，以免複製檔案目錄的過程中發生錯誤。

不過，這樣複製檔案與目錄會遇到一個問題，那就是第一層的目錄並不會複製其 NTFS 安全性過去，因此必須要想辦法同步兩個磁碟根目錄的安全性設定，這樣才能做到完全一樣的磁碟，這時我透過 **icals** 指令的幫助，省去手動設定時可能會發生手誤的機會。

利用 **icals** 指令來複製安全性，主要有 2 個步驟，分別為：

1.  先儲存來源目錄的 ACL 資訊
2.  再還原 ACL 資訊到目的目錄

我先以複製特定目錄的例子來說明，假設我有一個目錄為 c:\\tmp\\111，這時我可以輸入以下指令儲存該目錄的 ACL 資訊，並儲存成 AclFile.txt 檔：

```
icacls c:\tmp\111 /save AclFile.txt
```

這時的 **AclFile.txt** 檔案為如下的格式，第一行為「目錄名稱」

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/688e6c60b6c300a04e62-SNAGHTML215f20d7.png)

這時我們直接還原這個目錄的 ACL 資訊到目的目錄，假設為 **D:\\tmp\\111** 這個目錄，其指令如下：

```
icacls d:\tmp /restore AclFile.txt
```

請注意：我們這裡輸入的路徑為 d:\\tmp 而已，因為 111 這個目錄名稱已經記錄在檔案中，套用時會串接套用指定的目錄與 AclFile.txt 中的目錄名稱：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/9f1d9872d588ee275a9f-SNAGHTML2163362b.png)

這樣即可將目錄的 ACL 安全性資訊給設定完成！

不過，這樣的套用技巧並不適用於磁碟機根目錄 ( 例如: D:\\ ) 的權限套用！

如果要透過 **icacls** 指令來套用，會由兩個步驟增加到三個步驟，以下為詳細圖文解說：

**1\. 儲存來源目錄的 ACL 資訊 ( 假設我們儲存 C:\\ 根目錄的 ACL 安全性資訊 )**

```
icacls c:\ /save AclFile.txt
```

**2\. 開啟 AclFile.txt 修正第一行的結果**

由於透過 **icacls** 指令儲存「磁碟機根目錄」的時候，第一行並不會有路徑名稱，這個問題會導致在第三步還原時發生處理失敗的情況。

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/8280cd5d481f621c05bc-SNAGHTML2476d44e.png)

以下是直接執行還原時發生錯誤的情況：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/0b247770fbfff6e781f9-SNAGHTML24791295.png)

因此，我們必須手動修改該檔案，在第一行的地方加上路徑，也就是一個反斜線 ( \\ ) 符號：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/e8aae4cd033f4693c72d-SNAGHTML247c46a0.png)

**3\. 還原 ACL 資訊到目的磁碟**

有了第二個步驟的修正，就可以正常還原 ACL 權限到磁碟根目錄了：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/47baa0544f76336816cc-SNAGHTML247d926e.png)

**相關連結**

-   [注意 Windows 對於檔案複製與搬移的 NTFS 權限變化 \[重要\]](/post/2010/02/25/NTFS-file-permission-changes-during-copy-and-move.aspx)
-   [Robocopy - Wikipedia, the free encyclopedia](http://en.wikipedia.org/wiki/Robocopy)
-   [Robocopy – TechNet](http://technet.microsoft.com/en-us/library/cc733145\(WS.10\).aspx)
-   Better Robocopy GUI ( CodePlex )
