<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Windows 11 on kenji.blog</title><link>http://kenji.blog/zh-tw/tags/windows-11/</link><description>Recent content in Windows 11 on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>zh-tw</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 22:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/zh-tw/tags/windows-11/index.xml" rel="self" type="application/rss+xml"/><item><title>Windows 11 專用 MSIX 套件製作方法與自簽章憑證的陷阱</title><link>http://kenji.blog/zh-tw/p/windows-11-msix-packaging-guide/</link><pubDate>Sat, 12 Sep 2026 22:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/p/windows-11-msix-packaging-guide/</guid><description>&lt;img src="http://kenji.blog/p/windows-11-msix-packaging-guide/img/eyecatch.jpg" alt="Featured image of post Windows 11 專用 MSIX 套件製作方法與自簽章憑證的陷阱" />&lt;p>在 Windows 11 的時代，做為應用程式的散佈格式，「MSIX」正逐漸成為標準的選擇。傳統的 MSI 或 EXE 等安裝程式存在許多問題，而 MSIX 則被寄予厚望，成為解決這些問題的次世代套件技術。然而，當開發者實際製作 MSIX 套件，並試圖在組織內部或測試環境中進行側載（Sideloading）時，經常會陷入「自簽章憑證的陷阱」。&lt;/p>
&lt;p>本文將從 MSIX 的技術細節、使用 Visual Studio 或命令列工具製作套件的方法，到許多開發者所面臨的自簽章憑證錯誤原因與解決方案，進行非常詳細的解說。我們希望能成為 Windows 應用程式開發者、基礎架構管理員以及套件負責人的必讀指南。&lt;/p>
&lt;h2 id="1-什麼是-msix與傳統-msiexe-的比較">1. 什麼是 MSIX？與傳統 MSI/EXE 的比較
&lt;/h2>&lt;p>MSIX 是由 Microsoft 所提供、專為 Windows 設計的最新應用程式套件格式。它整合了以往存在的 MSI (Microsoft Installer)、以 .exe 為基礎的自訂安裝程式、App-V (Application Virtualization)，以及自 Windows 8 起導入的 AppX (通用 Windows 平台應用程式的套件) 中所有優良的功能與概念，並針對現代的安全性和部署需求進一步進化。&lt;/p>
&lt;h3 id="傳統安裝程式-msiexe-的問題">傳統安裝程式 (MSI/EXE) 的問題
&lt;/h3>&lt;p>長年做為 Windows 標準安裝格式的 MSI 與 EXE，存在以下根本性的問題：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Win Rot (Windows 劣化) 現象&lt;/strong>：隨著應用程式的重複安裝與解除安裝，登錄檔中會殘留不必要的機碼，且系統資料夾 (如 &lt;code>C:\Windows\System32&lt;/code>) 中也會遺留 DLL 檔案。這將導致作業系統本身的運作逐漸變慢並產生不穩定的現象。&lt;/li>
&lt;li>&lt;strong>DLL 地獄 (DLL Hell)&lt;/strong>：當多個應用程式試圖將同名 (但版本不同) 的 DLL 安裝到共用系統目錄時，後安裝的應用程式會覆寫現有的 DLL，導致先安裝的應用程式無法正常運作。&lt;/li>
&lt;li>&lt;strong>自訂動作帶來的不穩定性&lt;/strong>：在 MSI 套件中，被稱為「自訂動作」的任意指令碼或程式碼可以在安裝與解除安裝期間以系統權限執行。這會帶來安裝程式中途當機或導致系統發生預期外設定變更的風險。&lt;/li>
&lt;/ol>
&lt;h3 id="msix-的容器化架構解決方案">MSIX 的容器化架構解決方案
&lt;/h3>&lt;p>MSIX 透過將應用程式放入輕量級的「容器」內執行，來解決這些問題。此容器化方法具有以下巨大的優勢：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>乾淨的解除安裝&lt;/strong>：透過 MSIX 安裝的應用程式，其對檔案系統與登錄檔的寫入都會被虛擬化 (VFS: 虛擬檔案系統, VReg: 虛擬登錄檔)。因此，解除安裝時會將此虛擬化的容器整個刪除，不會在系統上留下任何垃圾 (殘骸)。完全防止 Win Rot 現象。&lt;/li>
&lt;li>&lt;strong>隔離與安全性 (Isolation)&lt;/strong>：各個應用程式都在自己的環境內執行，不會直接破壞其他應用程式的 DLL 或資源。從此擺脫 DLL 地獄。&lt;/li>
&lt;li>&lt;strong>網路頻寬的最佳化&lt;/strong>：MSIX 的更新機制非常優秀，支援區塊層級的差異更新 (Differential Update)。由於僅下載二進位資料中被變更的少數區塊，即使是大型應用程式的更新，也能將對網路的負擔降至最低。&lt;/li>
&lt;li>&lt;strong>確實的安裝狀態&lt;/strong>：套件內含資訊清單檔案 (&lt;code>AppxManifest.xml&lt;/code>)，安裝的交易會由作業系統層級嚴密管理。若發生失敗，將完全復原至原始狀態。&lt;/li>
&lt;/ul>
&lt;h2 id="2-msix-套件製作的全貌與工具鏈">2. MSIX 套件製作的全貌與工具鏈
&lt;/h2>&lt;p>製作 MSIX 套件大致可分為兩種方法。一種是使用 Visual Studio 的整合開發環境 (IDE)，另一種則是善用 Windows SDK 隨附的命令列工具 (&lt;code>MakeAppx.exe&lt;/code> 與 &lt;code>SignTool.exe&lt;/code>)。&lt;/p>
&lt;p>以下的 Mermaid 區塊圖展示了從原始程式碼檔案到最終產生已簽章 MSIX 套件的程序。&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;原始程式碼檔案 (EXE, DLL, 資產等)&amp;#34;] --&amp;gt; B[&amp;#34;AppxManifest.xml (資訊清單定義)&amp;#34;]
B --&amp;gt; C[&amp;#34;MakeAppx.exe (MSIX 套件建立工具)&amp;#34;]
C --&amp;gt; D[&amp;#34;未簽章的 MSIX 套件 (.msix)&amp;#34;]
E[&amp;#34;數位憑證 (.pfx)&amp;#34;] --&amp;gt; F[&amp;#34;SignTool.exe (數位簽章工具)&amp;#34;]
D --&amp;gt; F
F --&amp;gt; G[&amp;#34;已簽章的 MSIX 套件 (準備好部署)&amp;#34;]
style A fill:#f9f9f9,stroke:#333
style B fill:#e6f7ff,stroke:#333
style D fill:#ffcccb,stroke:#333
style G fill:#d4edda,stroke:#333
&lt;/pre>
&lt;p>從這個程序可以看出，單純收集檔案並封裝（封裝化）是不夠的，必須要有「數位簽章」的步驟。基於安全考量，Windows 11 完全不允許安裝未簽章的 MSIX 套件。&lt;/p>
&lt;h2 id="3-方法-a使用-visual-studio-製作-msix">3. 方法 A：使用 Visual Studio 製作 MSIX
&lt;/h2>&lt;p>最簡單且最常見的方法是使用 Visual Studio 的「Windows 應用程式封裝專案 (Windows Application Packaging Project - WAP)」。只要使用此專案範本，不論是 WPF、Windows Forms、WinUI 3，甚至是 C++ 的舊版 Win32 應用程式，都能輕鬆轉換成 MSIX。&lt;/p>
&lt;h3 id="逐步指南">逐步指南
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>新增 WAP 專案&lt;/strong>：在現有的 Visual Studio 方案按右鍵，從「加入新的專案」中選擇「Windows 應用程式封裝專案」。&lt;/li>
&lt;li>&lt;strong>選擇目標平台&lt;/strong>：指定應用程式支援的 Windows 10/11 的最低版本與目標版本。&lt;/li>
&lt;li>&lt;strong>參考應用程式&lt;/strong>：以滑鼠右鍵按一下封裝專案的「應用程式」節點，從「加入參考」中選擇想要封裝的主要專案 (例如 WPF 專案)。&lt;/li>
&lt;li>&lt;strong>設定資訊清單&lt;/strong>：連按兩下 &lt;code>Package.appxmanifest&lt;/code> 檔案，開啟視覺化設計工具。在這裡設定應用程式的顯示名稱、說明、標誌圖片，以及最重要的「套件名稱 (Identity Name)」與「發行者 (Publisher)」。&lt;/li>
&lt;li>&lt;strong>建立套件&lt;/strong>：在專案上按一下滑鼠右鍵，選擇「發佈」-&amp;gt;「建立應用程式套件」。選擇「側載」，並選擇架構 (x64, ARM64 等)，Visual Studio 就會自動包辦編譯、透過 &lt;code>MakeAppx&lt;/code> 進行封裝，以及自簽章憑證的產生與簽章。&lt;/li>
&lt;/ol>
&lt;p>雖然過程非常順暢，但如果在此處使用了 Visual Studio 自動產生的自簽章憑證 (Test Certificate)，將會陷入後述的「陷阱」中。&lt;/p>
&lt;h2 id="4-方法-b使用命令列-makeappxexe-製作">4. 方法 B：使用命令列 (MakeAppx.exe) 製作
&lt;/h2>&lt;p>在 CI/CD 管線的自動化，或是手動將現有安裝程式的檔案群重新封裝時，就需要命令列工具。只要安裝了 Windows SDK 的環境，就能從開發人員命令提示字元存取以下工具。&lt;/p>
&lt;h3 id="1-準備資訊清單檔案">1. 準備資訊清單檔案
&lt;/h3>&lt;p>在套件的根目錄中，建立一個寫有最低限度資訊的 &lt;code>AppxManifest.xml&lt;/code>。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-xml" data-lang="xml">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;utf-8&amp;#34;?&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;Package&lt;/span> &lt;span class="na">xmlns=&lt;/span>&lt;span class="s">&amp;#34;http://schemas.microsoft.com/appx/manifest/foundation/windows10&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">xmlns:uap=&lt;/span>&lt;span class="s">&amp;#34;http://schemas.microsoft.com/appx/manifest/uap/windows10&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">xmlns:rescap=&lt;/span>&lt;span class="s">&amp;#34;http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities&amp;#34;&lt;/span>&lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Identity&lt;/span> &lt;span class="na">Name=&lt;/span>&lt;span class="s">&amp;#34;MyCompany.AwesomeApp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">Publisher=&lt;/span>&lt;span class="s">&amp;#34;CN=MyCompany Self-Signed, O=MyCompany&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">Version=&lt;/span>&lt;span class="s">&amp;#34;1.0.0.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">ProcessorArchitecture=&lt;/span>&lt;span class="s">&amp;#34;x64&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Properties&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;DisplayName&amp;gt;&lt;/span>Awesome App&lt;span class="nt">&amp;lt;/DisplayName&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;PublisherDisplayName&amp;gt;&lt;/span>My Company&lt;span class="nt">&amp;lt;/PublisherDisplayName&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Logo&amp;gt;&lt;/span>Assets\StoreLogo.png&lt;span class="nt">&amp;lt;/Logo&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/Properties&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Resources&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Resource&lt;/span> &lt;span class="na">Language=&lt;/span>&lt;span class="s">&amp;#34;en-us&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Resource&lt;/span> &lt;span class="na">Language=&lt;/span>&lt;span class="s">&amp;#34;ja-jp&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/Resources&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Dependencies&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;TargetDeviceFamily&lt;/span> &lt;span class="na">Name=&lt;/span>&lt;span class="s">&amp;#34;Windows.Desktop&amp;#34;&lt;/span> &lt;span class="na">MinVersion=&lt;/span>&lt;span class="s">&amp;#34;10.0.17763.0&amp;#34;&lt;/span> &lt;span class="na">MaxVersionTested=&lt;/span>&lt;span class="s">&amp;#34;10.0.22000.0&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/Dependencies&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Capabilities&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;rescap:Capability&lt;/span> &lt;span class="na">Name=&lt;/span>&lt;span class="s">&amp;#34;runFullTrust&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/Capabilities&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Applications&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Application&lt;/span> &lt;span class="na">Id=&lt;/span>&lt;span class="s">&amp;#34;AwesomeApp&amp;#34;&lt;/span> &lt;span class="na">Executable=&lt;/span>&lt;span class="s">&amp;#34;AwesomeApp.exe&amp;#34;&lt;/span> &lt;span class="na">EntryPoint=&lt;/span>&lt;span class="s">&amp;#34;Windows.FullTrustApplication&amp;#34;&lt;/span>&lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;uap:VisualElements&lt;/span> &lt;span class="na">DisplayName=&lt;/span>&lt;span class="s">&amp;#34;Awesome App&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">Description=&lt;/span>&lt;span class="s">&amp;#34;The best app ever.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">BackgroundColor=&lt;/span>&lt;span class="s">&amp;#34;transparent&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">Square150x150Logo=&lt;/span>&lt;span class="s">&amp;#34;Assets\Square150x150Logo.png&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">Square44x44Logo=&lt;/span>&lt;span class="s">&amp;#34;Assets\Square44x44Logo.png&amp;#34;&lt;/span>&lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/uap:VisualElements&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/Application&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/Applications&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/Package&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>這裡最重要的一點是，&lt;code>&amp;lt;Identity Publisher=&amp;quot;...&amp;quot; /&amp;gt;&lt;/code> 的值必須與稍後用於簽章的憑證的 Subject 完全一致。&lt;/p>
&lt;h3 id="2-透過-makeappx-進行封裝">2. 透過 MakeAppx 進行封裝
&lt;/h3>&lt;p>在命令提示字元中執行以下命令，將目錄封裝成 MSIX 檔案。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmd" data-lang="cmd">&lt;span class="line">&lt;span class="cl">MakeAppx.exe pack /d &lt;span class="s2">&amp;#34;C:\Path\To\AppFolder&amp;#34;&lt;/span> /p &lt;span class="s2">&amp;#34;C:\Path\To\Output\AwesomeApp_1.0.0.0_x64.msix&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>這樣未簽章的 MSIX 檔案就完成了，但在此狀態下無法安裝到 Windows 上。&lt;/p>
&lt;h2 id="5-數位簽章與密碼學的數學背景">5. 數位簽章與密碼學的數學背景
&lt;/h2>&lt;p>為了深入理解為何 MSIX 套件需要簽章，我們必須了解數位簽章背後的密碼學機制。數位簽章保證了套件「確實是由指定的發行者所建立 (認證)」以及「建立後到目前為止未被第三方竄改 (完整性)」。&lt;/p>
&lt;p>MSIX 的簽章通常結合了 RSA 加密與 SHA-256 (Secure Hash Algorithm 256-bit)。&lt;/p>
&lt;h3 id="套用雜湊函數">套用雜湊函數
&lt;/h3>&lt;p>首先，將整個 MSIX 套件的二進位檔 (內容物) 視為訊息 $M$。簽章工具 (SignTool.exe) 會對此訊息 $M$ 套用密碼編譯雜湊函數 SHA-256，計算出固定長度 (256 位元) 的雜湊值 $H(M)$。&lt;/p>
&lt;h3 id="產生簽章-發行者">產生簽章 (發行者)
&lt;/h3>&lt;p>接著，發行者會使用自身的「私鑰 (Private Key)」$d$ 將雜湊值加密，產生數位簽章 $\sigma$。在 RSA 演算法的脈絡下，這可表示為如下的模組指數運算：&lt;/p>
$$ \sigma \equiv (H(M))^d \pmod n $$&lt;p>這裡的 $n$ 是 RSA 模數 (兩個巨大質數的乘積)。包含此簽章 $\sigma$ 與發行者「公鑰 (Public Key)」$e$ 的憑證 (X.509 格式)，將做為 MSIX 套件的一部分 (&lt;code>AppxSignature.p7x&lt;/code>) 被嵌入其中。&lt;/p>
&lt;h3 id="驗證簽章-windows-os">驗證簽章 (Windows OS)
&lt;/h3>&lt;p>當使用者嘗試安裝 MSIX 時，Windows OS 會從套件內的憑證中取出公鑰 $e$，並執行以下計算以還原雜湊值 $H'(M)$：&lt;/p>
$$ H'(M) \equiv \sigma^e \pmod n $$&lt;p>同時，OS 會自行對下載的整個 MSIX 套件 $M$ 重新計算雜湊值 $H(M)$。
最後，驗證還原的雜湊值與重新計算的雜湊值是否相等 ($H(M) = H'(M)$)。若此等式成立，就等於在數學上證明了「檔案在簽章後連 1 位元都沒有被竄改」。&lt;/p>
&lt;h2 id="6-最大的障礙自簽章憑證的陷阱">6. 最大的障礙：「自簽章憑證的陷阱」
&lt;/h2>&lt;p>即使上述的數學證明完美無缺，Windows 11 也無法僅憑藉這一點就允許安裝。因為它必須驗證『信任的鏈結 (Chain of Trust)』，也就是「該公鑰 (憑證) 的擁有者，是否真的是其所宣稱的安全組織或人員？」。&lt;/p>
&lt;p>如果憑證是由 VeriSign 或 DigiCert 等已被 OS 預先信任的公開根憑證授權單位 (Root CA) 所發行，就能順利安裝 (透過 Microsoft Store 發佈的應用程式也同樣受到 Microsoft 根憑證的信任)。&lt;/p>
&lt;p>然而，在開發中或做為公司內部專用工具等情況下，若無法負擔購買公開憑證的成本，開發者就會自行核發憑證。這就是「自簽章憑證 (Self-Signed Certificate)」。&lt;/p>
&lt;p>以下的循序圖展示了嘗試安裝以自簽章憑證簽署的 MSIX 套件時，OS 的行為模式。&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
autonumber
participant U as &amp;#34;使用者 (Windows 11)&amp;#34;
participant P as &amp;#34;MSIX 應用程式安裝程式&amp;#34;
participant C as &amp;#34;Windows 憑證存放區&amp;#34;
U-&amp;gt;&amp;gt;P: &amp;#34;連按兩下 .msix 檔案&amp;#34;
P-&amp;gt;&amp;gt;P: &amp;#34;讀取 AppxSignature.p7x&amp;#34;
P-&amp;gt;&amp;gt;P: &amp;#34;萃取簽章與憑證&amp;#34;
P-&amp;gt;&amp;gt;P: &amp;#34;驗證數學運算 (雜湊值相符？)&amp;#34;
P-&amp;gt;&amp;gt;C: &amp;#34;檢查發行者憑證的信任&amp;#34;
alt &amp;#34;憑證位於受信任的根憑證授權單位存放區&amp;#34;
C--&amp;gt;&amp;gt;P: &amp;#34;信任驗證成功&amp;#34;
P-&amp;gt;&amp;gt;U: &amp;#34;提示安裝 (安裝按鈕為可用狀態)&amp;#34;
U-&amp;gt;&amp;gt;P: &amp;#34;按下安裝&amp;#34;
P-&amp;gt;&amp;gt;U: &amp;#34;安裝成功&amp;#34;
else &amp;#34;憑證不被信任 (陷阱)&amp;#34;
C--&amp;gt;&amp;gt;P: &amp;#34;信任驗證失敗 (0x800B0109)&amp;#34;
P-&amp;gt;&amp;gt;U: &amp;#34;顯示錯誤：已處理憑證鏈結，但終止於不受信任的根憑證&amp;#34;
P-&amp;gt;&amp;gt;U: &amp;#34;安裝按鈕為停用狀態&amp;#34;
end
&lt;/pre>
&lt;p>這正是所謂的「陷阱」。儘管開發者自行建立並正確簽署了套件，但在 Windows 11 的預設狀態下，因為它不認識（不信任）該自簽章憑證，所以會伴隨錯誤代碼 &lt;code>0x800B0109&lt;/code> 而阻擋安裝。安裝程式的「安裝」按鈕會呈現灰色而無法點擊。&lt;/p>
&lt;p>許多開發者在面臨這個錯誤時，會陷入「MSIX 滿是錯誤」、「一定是設定錯了」而反覆修改資訊清單檔案的迷宮中，但問題並不在於套件的結構，而是在於是否已將憑證登錄到 OS 的憑證存放區 (Certificate Store)。&lt;/p>
&lt;h2 id="7-解決方案使用-powershell-建立與部署自簽章憑證">7. 解決方案：使用 PowerShell 建立與部署自簽章憑證
&lt;/h2>&lt;p>為了解決這個問題，必須確實執行以下兩個步驟：&lt;/p>
&lt;ol>
&lt;li>建立有效的自簽章憑證，並匯出包含私鑰的 PFX 檔案。&lt;/li>
&lt;li>將所建立憑證的公鑰部分 (CER 檔案)，安裝到所有目標 PC 的**「受信任的根憑證授權單位 (Trusted Root Certification Authorities)」存放區**中。&lt;/li>
&lt;/ol>
&lt;p>透過使用 PowerShell，就能確實且自動地處理這些工作。&lt;/p>
&lt;h3 id="步驟-1建立與匯出自簽章憑證">步驟 1：建立與匯出自簽章憑證
&lt;/h3>&lt;p>首先以系統管理員權限啟動 PowerShell，執行以下指令碼來建立憑證。在這裡，我們將產生專用於程式碼簽章 (Code Signing) 的憑證。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 1. 參數定義&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$SubjectName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;CN=MyCompany Self-Signed, O=MyCompany&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$CertStoreLocation&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Cert:\CurrentUser\My&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 2. 產生自簽章憑證 (程式碼簽章用途: 1.3.6.1.5.5.7.3.3)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$Cert&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">New-SelfSignedCertificate&lt;/span> &lt;span class="n">-Type&lt;/span> &lt;span class="n">Custom&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">-Subject&lt;/span> &lt;span class="nv">$SubjectName&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">-KeyUsage&lt;/span> &lt;span class="n">DigitalSignature&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">-FriendlyName&lt;/span> &lt;span class="s2">&amp;#34;MyCompany MSIX Signing Cert&amp;#34;&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">-CertStoreLocation&lt;/span> &lt;span class="nv">$CertStoreLocation&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">-TextExtension&lt;/span> &lt;span class="vm">@&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;2.5.29.37={text}1.3.6.1.5.5.7.3.3&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;2.5.29.19={text}&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;已產生憑證。指紋 (Thumbprint): &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$Cert&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Thumbprint&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 3. 建立匯出 PFX (含私鑰) 用的密碼&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$Password&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">ConvertTo-SecureString&lt;/span> &lt;span class="n">-String&lt;/span> &lt;span class="s2">&amp;#34;YourSecurePassword123!&amp;#34;&lt;/span> &lt;span class="n">-Force&lt;/span> &lt;span class="n">-AsPlainText&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 4. 匯出 PFX 檔案 (供 SignTool 簽章用)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$PfxPath&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;C:\Path\To\Output\MyCompanyCert.pfx&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Export-PfxCertificate&lt;/span> &lt;span class="n">-Cert&lt;/span> &lt;span class="nv">$Cert&lt;/span> &lt;span class="n">-FilePath&lt;/span> &lt;span class="nv">$PfxPath&lt;/span> &lt;span class="n">-Password&lt;/span> &lt;span class="nv">$Password&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 5. 匯出 CER (僅含公鑰) (供安裝至用戶端 PC 用)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$CerPath&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;C:\Path\To\Output\MyCompanyCert.cer&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Export-Certificate&lt;/span> &lt;span class="n">-Cert&lt;/span> &lt;span class="nv">$Cert&lt;/span> &lt;span class="n">-FilePath&lt;/span> &lt;span class="nv">$CerPath&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>使用此處建立的 &lt;code>$PfxPath&lt;/code> 檔案，為 MSIX 套件進行簽章。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmd" data-lang="cmd">&lt;span class="line">&lt;span class="cl">SignTool.exe sign /fd SHA256 /a /f &lt;span class="s2">&amp;#34;C:\Path\To\Output\MyCompanyCert.pfx&amp;#34;&lt;/span> /p &lt;span class="s2">&amp;#34;YourSecurePassword123!&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;C:\Path\To\Output\AwesomeApp_1.0.0.0_x64.msix&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="步驟-2將憑證安裝至用戶端-pc-解除陷阱">步驟 2：將憑證安裝至用戶端 PC (解除陷阱)
&lt;/h3>&lt;p>即使將已簽章的 MSIX 帶到另一台 PC (或虛擬環境)，直接連按兩下也如前所述無法安裝。必須在事前 (或同時) 將剛才匯出的 &lt;code>$CerPath&lt;/code> 檔案安裝到「本機電腦」的「受信任的根憑證授權單位」。&lt;/p>
&lt;p>為此，請在部署目標的 PC 上開啟&lt;strong>具備系統管理員權限&lt;/strong>的 PowerShell，並執行以下命令。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># CER 檔案的路徑&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$CerPath&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;C:\Path\To\Output\MyCompanyCert.cer&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 匯入至本機電腦的「受信任的根憑證授權單位」&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Import-Certificate&lt;/span> &lt;span class="n">-FilePath&lt;/span> &lt;span class="nv">$CerPath&lt;/span> &lt;span class="n">-CertStoreLocation&lt;/span> &lt;span class="s2">&amp;#34;Cert:\LocalMachine\Root&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;已將憑證安裝至受信任的根憑證授權單位。&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;blockquote>
&lt;p>[!CAUTION]
要新增至「本機電腦 (&lt;code>LocalMachine&lt;/code>)」的根憑證授權單位存放區，必須具備系統管理員權限。如果放進使用者個人的存放區 (&lt;code>CurrentUser&lt;/code>)，可能會因為 App Installer 權限情境的緣故而無法被識別，請務必注意。&lt;/p>
&lt;/blockquote>
&lt;p>此指令碼成功執行後，請嘗試再次連按兩下剛才發生錯誤的 MSIX 檔案。錯誤訊息會宛如施了魔法般消失，並顯示鮮豔藍色、處於可用狀態的「安裝」按鈕。如此一來便成功完全突破了「自簽章憑證的陷阱」。&lt;/p>
&lt;h2 id="8-企業環境中的維運與最佳實務">8. 企業環境中的維運與最佳實務
&lt;/h2>&lt;p>如果是開發者的本機測試，上述步驟已經足夠，但若要將側載應用程式部署到公司內數十台、數百台的 PC 上，要求每位使用者執行憑證安裝指令碼是不切實際的，且伴隨著安全風險。&lt;/p>
&lt;p>企業環境中的最佳實務如下：&lt;/p>
&lt;h3 id="1-活用-active-directory-群組原則-gpo">1. 活用 Active Directory 群組原則 (GPO)
&lt;/h3>&lt;p>若公司內部有導入 Active Directory，可以使用 GPO 的「公開金鑰原則」，將自簽章憑證 (CER 檔案) 自動派發到所有加入網域的 PC 的「受信任的根憑證授權單位」。透過此方式，員工完全不需意識到憑證的存在，只需連按兩下共用資料夾上的 MSIX 檔案即可安裝。&lt;/p>
&lt;h3 id="2-透過-microsoft-intune-mdm-部署">2. 透過 Microsoft Intune (MDM) 部署
&lt;/h3>&lt;p>在現代化的環境中，會使用 Microsoft Intune 來進行裝置管理。在 Intune 中，可以使用「組態設定檔」功能將受信任的憑證 (.cer) 推送傳遞至端點。之後，即可將 MSIX 套件本身以無訊息安裝的方式做為企業營運 (LOB) 應用程式來部署。&lt;/p>
&lt;h3 id="3-透過-app-installer-檔案-appinstaller-自動更新">3. 透過 App Installer 檔案 (.appinstaller) 自動更新
&lt;/h3>&lt;p>MSIX 具備強大的自動更新應用程式功能。只要建立以 XML 為基礎的 &lt;code>.appinstaller&lt;/code> 檔案，並將其放置在網頁伺服器或 SMB 共用資料夾上，就能在應用程式啟動時於背景檢查是否有新版本的 MSIX，並自動套用更新。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-xml" data-lang="xml">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;utf-8&amp;#34;?&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;AppInstaller&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">Uri=&lt;/span>&lt;span class="s">&amp;#34;https://internal.mycompany.com/apps/AwesomeApp.appinstaller&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">Version=&lt;/span>&lt;span class="s">&amp;#34;1.0.0.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">xmlns=&lt;/span>&lt;span class="s">&amp;#34;http://schemas.microsoft.com/appx/appinstaller/2018&amp;#34;&lt;/span>&lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;MainPackage&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">Name=&lt;/span>&lt;span class="s">&amp;#34;MyCompany.AwesomeApp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">Publisher=&lt;/span>&lt;span class="s">&amp;#34;CN=MyCompany Self-Signed, O=MyCompany&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">Version=&lt;/span>&lt;span class="s">&amp;#34;1.0.0.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">ProcessorArchitecture=&lt;/span>&lt;span class="s">&amp;#34;x64&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">Uri=&lt;/span>&lt;span class="s">&amp;#34;https://internal.mycompany.com/apps/AwesomeApp_1.0.0.0_x64.msix&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;UpdateSettings&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;OnLaunch&lt;/span> &lt;span class="na">HoursBetweenUpdateChecks=&lt;/span>&lt;span class="s">&amp;#34;0&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/UpdateSettings&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/AppInstaller&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>將此檔案派發給使用者安裝後，未來只需替換伺服器上的 MSIX 檔案並更新 &lt;code>.appinstaller&lt;/code> 的版本號碼，所有使用者的應用程式就會自動更新。&lt;/p>
&lt;h2 id="9-疑難排解與憑證相關的常見錯誤">9. 疑難排解：與憑證相關的常見錯誤
&lt;/h2>&lt;p>最後，在此彙整其他與憑證或簽章相關、可能會發生的常見錯誤與解決方案。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>0x800B0101&lt;/strong>：用於簽章的憑證已過期。請重新核發新的憑證，或在簽章時使用時間戳記伺服器 (例如：&lt;code>http://timestamp.digicert.com&lt;/code>)，以證明簽章是在憑證有效期間內進行的 (只要加上時間戳記，即使憑證本身過期，該簽章仍會被視為有效)。&lt;/li>
&lt;li>&lt;strong>0x80080204&lt;/strong>：&lt;code>AppxManifest.xml&lt;/code> 中記載的 &lt;code>Publisher&lt;/code> 值與憑證的 &lt;code>Subject&lt;/code> 值沒有完全一致。請嚴格確認字串是否完全相符，例如逗號後是否有空白等。&lt;/li>
&lt;li>&lt;strong>檢查事件檢視器&lt;/strong>：要尋找錯誤更詳細的原因，開啟 Windows 的事件檢視器，並檢查「應用程式及服務記錄檔」-&amp;gt;「Microsoft」-&amp;gt;「Windows」-&amp;gt;「AppxPackagingOM」或「AppXDeployment-Server」的記錄檔，這點非常重要。&lt;/li>
&lt;/ul>
&lt;h2 id="10-總結">10. 總結
&lt;/h2>&lt;p>面向 Windows 11 的 MSIX 封裝是一項強大的技術，能夠飛躍性地提升應用程式的生命週期管理。能從 Win Rot 與 DLL 地獄中解脫，提供使用者乾淨又安全的環境。&lt;/p>
&lt;p>另一方面，由於安全模型變得更為嚴格，對於數位簽章與憑證「信任鏈結」的深入理解是不可或缺的。「自簽章憑證的陷阱」可說是初次接觸 MSIX 技術的開發者幾乎必然會面臨的難關。只要理解本文所解說的憑證產生、匯出，以及匯入適當存放區的機制，並活用指令碼或 GPO 來進行自動化，就能引出 MSIX 的最大潛力，實現順暢的部署。&lt;/p>
&lt;p>請務必善用這些知識，建構次世代的乾淨 Windows 應用程式散佈環境。&lt;/p></description></item><item><title>Windows 登錄檔的基礎知識與可程式化之安全編輯方法</title><link>http://kenji.blog/zh-tw/p/windows-registry-safe-programmable-editing/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/p/windows-registry-safe-programmable-editing/</guid><description>&lt;img src="http://kenji.blog/p/windows-registry-safe-programmable-editing/img/eyecatch.jpg" alt="Featured image of post Windows 登錄檔的基礎知識與可程式化之安全編輯方法" />&lt;h1 id="windows-登錄檔的基礎知識與可程式化之安全編輯方法">Windows 登錄檔的基礎知識與可程式化之安全編輯方法
&lt;/h1>&lt;p>在 Windows 作業系統中，「登錄檔（Registry）」是一個用來儲存系統和應用程式各種設定的龐大階層式資料庫。本文將從 Windows 登錄檔的基礎架構開始，非常詳細地解說如何使用 PowerShell 和 C# 進行可程式化且安全的登錄檔編輯方法。&lt;/p>
&lt;h2 id="1-簡介windows-登錄檔的歷史與演進">1. 簡介：Windows 登錄檔的歷史與演進
&lt;/h2>&lt;p>在 Windows 的早期版本（Windows 3.x 時代）中，系統與應用程式的設定主要儲存在 &lt;code>.ini&lt;/code>（初始化檔案）裡。然而，隨著每個應用程式的無數 INI 檔案散佈在整個系統中，管理變得極度繁雜。此外，由於 INI 檔案是基於純文字格式，難以儲存二進位資料，且不存在存取控制（安全性）的機制。檔案的解析速度也很慢，不適合用來儲存大規模的設定。&lt;/p>
&lt;p>為了根本解決這些問題，從 Windows NT 和 Windows 95 開始，正式採用了「登錄檔」作為集中式的設定資料庫。登錄檔是一個階層化的資料庫，提供強型別、二進位資料的支援，以及透過存取控制清單（ACL）達成的堅固安全性功能。這使得從作業系統核心到使用者空間的應用程式等所有元件，都能透過統一的介面（Win32 API 的 &lt;code>Reg*&lt;/code> 函式群）來讀寫設定。&lt;/p>
&lt;p>一直到現代的 Windows 11，登錄檔仍然持續作為作業系統的核心在運作。硬體配置、裝置驅動程式的載入順序、使用者的桌面環境、已安裝軟體的清單等，系統運作所需的所有中繼資料都集中在登錄檔中。&lt;/p>
&lt;h2 id="2-架構深層登錄檔-hive-的實體與記憶體對應">2. 架構深層：登錄檔 Hive 的實體與記憶體對應
&lt;/h2>&lt;p>登錄檔在邏輯上雖然看起來是一個巨大的樹狀結構，但在實體上是被分割成多個稱為「Hive」的檔案並儲存在磁碟上。這樣可以將整個系統的設定與使用者特定的設定分離，實現高效的讀取。&lt;/p>
&lt;p>主要的 Hive 檔案通常存在於 &lt;code>%SystemRoot%\System32\config&lt;/code> 目錄中。&lt;/p>
&lt;ul>
&lt;li>&lt;code>SYSTEM&lt;/code>: 作業系統啟動所需的重要設定（驅動程式、服務、開機設定等）。&lt;/li>
&lt;li>&lt;code>SOFTWARE&lt;/code>: 已安裝軟體之全系統設定。第三方應用程式的設定大多存放在這裡。&lt;/li>
&lt;li>&lt;code>SAM&lt;/code>: 安全性帳戶管理員 (Security Accounts Manager)（本機使用者帳戶與密碼雜湊）。&lt;/li>
&lt;li>&lt;code>SECURITY&lt;/code>: 本機安全性原則與權限指派。&lt;/li>
&lt;li>&lt;code>DEFAULT&lt;/code>: 預設使用者的設定檔（建立新使用者時的範本）。&lt;/li>
&lt;/ul>
&lt;p>使用者個別的 Hive 檔案則作為隱藏檔案存在於使用者的設定檔目錄中（例如：&lt;code>C:\Users\Username&lt;/code>）。&lt;/p>
&lt;ul>
&lt;li>&lt;code>NTUSER.DAT&lt;/code>: 該使用者的基本設定（HKCU 的大部分）。&lt;/li>
&lt;li>&lt;code>UsrClass.dat&lt;/code>: 該使用者的檔案副檔名關聯設定（存在於 &lt;code>AppData\Local\Microsoft\Windows&lt;/code> 中）。&lt;/li>
&lt;/ul>
&lt;p>這些檔案會在作業系統啟動時，由核心的「設定管理員 (Configuration Manager, CM)」對應到核心分頁集區記憶體中。設定管理員是處理登錄檔讀寫要求的核心模式元件。&lt;/p>
&lt;p>值得一提的是，並非所有登錄檔資料都存在於磁碟上。例如，&lt;code>HARDWARE&lt;/code> Hive 是揮發性（Volatile）的，完全不會儲存在磁碟上的檔案中。每次作業系統啟動，隨插即用（PnP）管理員偵測到硬體時，就會在記憶體中動態重建。&lt;/p>
&lt;p>此外，為了提高登錄檔的可靠性，最新的 Windows 實作了交易記錄（Transaction Logging）。對 Hive 檔案的變更不會直接寫入資料檔，而是會先記錄在交易記錄檔（&lt;code>.log1&lt;/code>, &lt;code>.log2&lt;/code>）中。這可以防止在寫入過程中發生意外斷電或系統當機時的資料損毀（Corruption），並以接近 ACID 特性的方式確保資料庫的完整性。&lt;/p>
&lt;h2 id="3-登錄檔機碼與值的階層結構">3. 登錄檔機碼與值的階層結構
&lt;/h2>&lt;p>登錄檔具有非常類似於檔案系統的階層結構。作為根節點的部分稱為「根機碼（Root Key）」或「Hive」，其下方會儲存「機碼（Key）」、「子機碼（Subkey）」，以及作為資料實體的「值（Value）」。可以將機碼想像成目錄，值想像成檔案，這樣會更容易理解。&lt;/p>
&lt;p>主要的根機碼分為以下 5 種：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>HKEY_LOCAL_MACHINE (HKLM)&lt;/strong>: 儲存適用於整部電腦（所有使用者）的系統設定與軟體設定。變更需要管理員權限。&lt;/li>
&lt;li>&lt;strong>HKEY_CURRENT_USER (HKCU)&lt;/strong>: 儲存目前登入使用者的專屬設定。事實上，這並不是一個獨立的資料庫，而只是指向 &lt;code>HKEY_USERS&lt;/code> 下方對應使用者 SID（安全性識別碼）機碼的符號連結（別名）。&lt;/li>
&lt;li>&lt;strong>HKEY_CLASSES_ROOT (HKCR)&lt;/strong>: 儲存檔案副檔名關聯、COM（元件物件模型）類別的登錄資訊，以及 Shell 擴充功能。這個機碼很特殊，是由設定管理員將 &lt;code>HKLM\SOFTWARE\Classes&lt;/code>（全系統）與 &lt;code>HKCU\Software\Classes&lt;/code>（目前使用者）合併後顯示的虛擬檢視。若有衝突，則優先使用使用者特定的設定（HKCU）。&lt;/li>
&lt;li>&lt;strong>HKEY_USERS (HKU)&lt;/strong>: 儲存系統上所有使用者設定檔（目前已載入記憶體中者）的設定。它是基於 SID 進行階層化。&lt;/li>
&lt;li>&lt;strong>HKEY_CURRENT_CONFIG (HKCC)&lt;/strong>: 目前硬體設定檔的相關設定。實體是指向 &lt;code>HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Current&lt;/code> 的連結。&lt;/li>
&lt;/ol>
&lt;p>將這個複雜的階層結構與連結關係視覺化如下：&lt;/p>
&lt;pre class="mermaid">
mindmap
root((&amp;#34;Windows 登錄檔&amp;#34;))
HKLM((&amp;#34;HKEY_LOCAL_MACHINE&amp;#34;))
SAM((&amp;#34;SAM (安全性帳戶)&amp;#34;))
SECURITY((&amp;#34;SECURITY&amp;#34;))
SOFTWARE((&amp;#34;SOFTWARE&amp;#34;))
SYSTEM((&amp;#34;SYSTEM&amp;#34;))
HARDWARE((&amp;#34;HARDWARE (揮發性)&amp;#34;))
HKCU((&amp;#34;HKEY_CURRENT_USER (連結)&amp;#34;))
AppEvents((&amp;#34;AppEvents&amp;#34;))
Console((&amp;#34;Console&amp;#34;))
Software((&amp;#34;Software&amp;#34;))
System((&amp;#34;System&amp;#34;))
HKCR((&amp;#34;HKEY_CLASSES_ROOT (合併檢視)&amp;#34;))
HKU((&amp;#34;HKEY_USERS&amp;#34;))
SID((&amp;#34;使用者 SIDs...&amp;#34;))
HKCC((&amp;#34;HKEY_CURRENT_CONFIG (連結)&amp;#34;))
&lt;/pre>
&lt;h2 id="4-登錄檔的資料型別詳細解說">4. 登錄檔的資料型別（詳細解說）
&lt;/h2>&lt;p>登錄檔的「值」各自都定義了嚴格的資料型別。當以程式化的方式操作登錄檔時，正確理解這些型別並以適當的型別寫入資料是不可或缺的。如果以錯誤的型別寫入，可能會導致應用程式擲回例外狀況，或成為作業系統功能停止運作的原因。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>REG_SZ (字串值)&lt;/strong>: 最常見的資料型別。儲存以 NULL 結尾的 Unicode 字串（UTF-16LE）。用於檔案路徑、URL、UI 顯示名稱等。&lt;/li>
&lt;li>&lt;strong>REG_DWORD (32 位元整數值)&lt;/strong>: 32 位元（4 個位元組）的無號整數值。頻繁用於布林值（0=停用、1=啟用）、以毫秒為單位的逾時值、錯誤碼設定等。由於 Windows 是 Little-Endian 架構，因此在磁碟上會從低位元組開始依序儲存（例如：0x12345678 會儲存為 &lt;code>78 56 34 12&lt;/code>）。&lt;/li>
&lt;li>&lt;strong>REG_QWORD (64 位元整數值)&lt;/strong>: 64 位元（8 個位元組）的整數值。隨著 64 位元架構的普及，用來儲存龐大的數值（如磁碟配額、大容量記憶體的大小指定等）或指標大小的設定。&lt;/li>
&lt;li>&lt;strong>REG_MULTI_SZ (多字串值)&lt;/strong>: 連續儲存多個以 NULL 結尾的字串，並在最後再放置一個空的 NULL 結尾字元（雙 NULL）作為終止的形式。適合用來儲存陣列狀的資料，如 IP 位址清單、具相依性的服務清單、繫結順序等。&lt;/li>
&lt;li>&lt;strong>REG_EXPAND_SZ (可擴充字串值)&lt;/strong>: 包含未展開之環境變數字串（例如 &lt;code>%USERPROFILE%&lt;/code> 或 &lt;code>%SystemRoot%&lt;/code>）的特殊字串型別。當應用程式透過 &lt;code>RegQueryValueEx&lt;/code> API 讀取，或呼叫 &lt;code>ExpandEnvironmentStrings&lt;/code> API 時，作業系統會動態將其展開為實際的絕對路徑。&lt;/li>
&lt;li>&lt;strong>REG_BINARY (二進位值)&lt;/strong>: 任意的原始二進位資料流。會儲存加密過的密碼（如 LSA Secrets）、數位憑證、應用程式特定的複雜結構或序列化資料。&lt;/li>
&lt;li>&lt;strong>REG_NONE&lt;/strong>: 未定義型別的資料。非常罕見，但會用於加密金鑰的保留區域等。&lt;/li>
&lt;li>&lt;strong>REG_RESOURCE_LIST&lt;/strong> / &lt;strong>REG_FULL_RESOURCE_DESCRIPTOR&lt;/strong>: 裝置驅動程式用來記錄硬體資源（IRQ、I/O 連接埠、DMA 通道）分配資訊的進階核心專用型別。&lt;/li>
&lt;/ul>
&lt;h2 id="5-作業系統中登錄檔的數學模型與效能">5. 作業系統中登錄檔的數學模型與效能
&lt;/h2>&lt;p>由於登錄檔直接關係到作業系統的效能（尤其是開機時間和處理程序的初始化速度），其內部使用了稱為「Cell Index」、類似 B-Tree（B 樹）的進階資料結構來進行最佳化。&lt;/p>
&lt;h3 id="搜尋的時間複雜度-time-complexity">搜尋的時間複雜度 (Time Complexity)
&lt;/h3>&lt;p>搜尋登錄檔內特定機碼（路徑）的時間複雜度 $T_{\text{search}}$ 取決於樹狀結構的深度以及各階層中的節點數量。探索深度為 $d$ 的子機碼（例如：&lt;code>A\B\C\D&lt;/code> 則 $d=4$）時的複雜度，理論上可以建立如下的模型：&lt;/p>
$$
T_{\text{search}}(d, L) = \sum_{i=1}^{d} O(\log(C_i) \cdot L_i)
$$&lt;p>這裡的 $C_i$ 是深度 $i$ 的子節點（子機碼或值）數量，$L_i$ 是作為比較目標的字串長度（字元數）。在作為登錄檔實體的 Hive 檔案中，子機碼清單是以名稱的雜湊值或依字母順序排序的索引來保存。因此，它可以進行二元搜尋 $O(\log(C_i))$，而不是單純的線性搜尋 $O(C_i)$，即使一個機碼下存在數萬個子機碼，也能實現極快的存取速度。&lt;/p>
&lt;h3 id="儲存空間使用量-space-complexity">儲存空間使用量 (Space Complexity)
&lt;/h3>&lt;p>登錄檔的整體大小（在實體磁碟上的占用量）是計算各 Hive 的總和。&lt;/p>
$$
\text{Size}_{\text{Total}} = \sum_{h \in \text{Hives}} \left( N_{h} \times S_{\text{key\_metadata}} + \sum_{v \in h} S_{\text{value}}(v) \right) + S_{\text{overhead}}
$$&lt;p>$N_h$ 是 Hive $h$ 內的機碼數量，$S_{\text{key\_metadata}}$ 是每個機碼的中繼資料（最後寫入的時間戳記、安全性描述元的指標、父機碼的指標等）大小，$S_{\text{value}}(v)$ 則是值 $v$ 的有效負載大小。其中還包含了交易記錄檔或不再需要的空白單元（碎片化）所造成的額外負擔 $S_{\text{overhead}}$。如果登錄檔中長期放置不需要的資料（例如未完全解除安裝的軟體殘骸），這個空間占用就會增加，可能會壓迫作業系統的分頁集區記憶體，從而導致效能下降。&lt;/p>
&lt;h2 id="6-威脅系統穩固性的手動編輯風險與損毀機率">6. 威脅系統穩固性的手動編輯風險與損毀機率
&lt;/h2>&lt;p>使用登錄編輯程式（&lt;code>regedit.exe&lt;/code>）進行手工作業的編輯，應被視為系統管理的最後手段。登錄檔並沒有內建像一般文件編輯器那樣的「復原（Undo）」功能，對於值的變更或機碼的刪除，會立即透過設定管理員反映在系統上。&lt;/p>
&lt;p>特別是對於系統啟動不可或缺的關鍵機碼（例如：&lt;code>HKLM\SYSTEM\CurrentControlSet\Services&lt;/code> 底下的磁碟控制器驅動程式設定，或是 &lt;code>HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon&lt;/code> 的 &lt;code>Userinit&lt;/code> 值等），就算只是一個字元誤編或誤刪，都存在著導致作業系統發生藍白畫面（BSoD）而無法開機，或是停留在登入畫面無法繼續前進（黑畫面）的致命風險。&lt;/p>
&lt;h3 id="損毀機率的數學模型">損毀機率的數學模型
&lt;/h3>&lt;p>讓我們來考慮一下，如果隨機變更或刪除登錄檔內的機碼，發生系統故障的機率。假設讓系統正常運作不可或缺的關鍵機碼集合為 $C$，其總數為 $N_c = |C|$。登錄檔整體的機碼總數為 $N_{\text{total}}$。
若隨機刪除或破壞 $k$ 個機碼，則至少有一個關鍵機碼損毀的機率 $P_{\text{failure}}$，可透過取出不放回（Sampling without replacement）的機率計算表示如下：&lt;/p>
$$
P_{\text{failure}} = 1 - \frac{\binom{N_{\text{total}} - N_c}{k}}{\binom{N_{\text{total}}}{k}} = 1 - \prod_{i=0}^{k-1} \left( 1 - \frac{N_c}{N_{\text{total}} - i} \right)
$$&lt;p>登錄檔整體的機碼數量 $N_{\text{total}}$ 大約在數十萬到數百萬的數量級，而 $N_c$ 也存在數萬的數量級。在數學上，即使是隨機操作，只要 $k$ 增加，故障機率就會急遽上升。況且在現實的手動操作中，使用者並非「隨機」編輯，而是會刻意去操作與系統設定或軟體運作有直接關係的部位（例如看著教學網站進行），因此觸碰到關鍵機碼的機率會遠比上述的理論值還要高。&lt;/p>
&lt;h2 id="7-登錄檔的虛擬化與-wow64-架構">7. 登錄檔的虛擬化與 WOW64 架構
&lt;/h2>&lt;p>Windows 為了維持舊版應用程式的相容性，對登錄檔存取實作了幾種進階的「虛擬化（重新導向）」機制。如果在不了解這一點的情況下進行程式設計，將會成為引發重大 Bug 的原因。&lt;/p>
&lt;h3 id="uac-登錄檔虛擬化-registry-virtualization">UAC 登錄檔虛擬化 (Registry Virtualization)
&lt;/h3>&lt;p>從 Windows Vista 開始，引入了使用者帳戶控制（UAC）。當 Windows XP 時代所開發的舊應用程式（以標準使用者權限執行），嘗試寫入原本需要管理員權限的 &lt;code>HKLM\SOFTWARE&lt;/code> 等受保護機碼時，為了防止因存取遭拒（Access Denied）錯誤而當機，Windows 會悄悄地將該寫入操作重新導向至使用者設定檔內的虛擬存放區 &lt;code>HKCU\Software\Classes\VirtualStore\MACHINE\SOFTWARE&lt;/code>。讀取時，也會將原始位置與虛擬存放區合併後傳回。如此一來，應用程式就能在未偵測到錯誤的情況下繼續正常運作。
但是，如果要開發以程式化方式變更整個系統設定的工具，就必須在資訊清單檔案（Manifest file）中指定 &lt;code>&amp;lt;requestedExecutionLevel level=&amp;quot;requireAdministrator&amp;quot; /&amp;gt;&lt;/code> 來停用此虛擬化功能。&lt;/p>
&lt;h3 id="wow64-windows-32-bit-on-windows-64-bit-的重新導向">WOW64 (Windows 32-bit on Windows 64-bit) 的重新導向
&lt;/h3>&lt;p>在 64 位元版的 Windows（目前的主流）上執行舊的 32 位元應用程式時，為了避免 32 位元應用程式不小心覆寫了 64 位元原生的系統設定，或載入不相容的 64 位元 DLL，特定的登錄機碼會被自動隔離並重新導向。
例如，當 32 位元應用程式嘗試存取 &lt;code>HKLM\SOFTWARE\Vendor\App&lt;/code> 時，作業系統會透通地將其重新導向至 &lt;code>HKLM\SOFTWARE\WOW6432Node\Vendor\App&lt;/code>。&lt;/p>
&lt;pre class="mermaid">
flowchart TD
App32[&amp;#34;32 位元應用程式&amp;#34;]
App64[&amp;#34;64 位元應用程式&amp;#34;]
RegAPI[&amp;#34;登錄檔 API (Advapi32.dll)&amp;#34;]
CM[&amp;#34;設定管理員 (核心)&amp;#34;]
HKLM_Soft[&amp;#34;HKLM\SOFTWARE&amp;#34;]
HKLM_WOW64[&amp;#34;HKLM\SOFTWARE\WOW6432Node&amp;#34;]
App32 --&amp;gt;| RegOpenKeyEx() | RegAPI
App64 --&amp;gt;| RegOpenKeyEx() | RegAPI
RegAPI --&amp;gt; CM
CM --&amp;gt;| 如果是 64 位元處理程序 | HKLM_Soft
CM --&amp;gt;| 如果是 32 位元處理程序 (重新導向) | HKLM_WOW64
&lt;/pre>
&lt;p>從 PowerShell 指令碼或 C# 應用程式編輯登錄檔時，必須強烈意識到正在執行的處理程序本身是 32 位元還是 64 位元。否則，將會引發「明明已經寫入的設定卻在檔案總管中看不到（寫到其他地方去了）」這種棘手的問題。&lt;/p>
&lt;h2 id="8-透過-powershell-進行可程式化的安全編輯">8. 透過 PowerShell 進行可程式化的安全編輯
&lt;/h2>&lt;p>為了將手動編輯登錄檔的風險降到最低，現代的最佳實務是使用 PowerShell 指令碼將操作程式碼化（基礎架構即程式碼，Infrastructure as Code），以確保自動化、可重現性與可測試性。PowerShell 具備了「Registry Provider（登錄檔提供者）」，能以操作檔案系統（如 C: 磁碟機）完全相同的 Cmdlet（例如 &lt;code>Get-ChildItem&lt;/code>、&lt;code>Get-ItemProperty&lt;/code>、&lt;code>New-Item&lt;/code> 等）來透通地操作登錄檔。&lt;/p>
&lt;p>PowerShell 預設已經掛載了 &lt;code>HKLM:&lt;/code> 與 &lt;code>HKCU:&lt;/code> 這種專屬的 PSDrive（類似於磁碟機代號）。&lt;/p>
&lt;h3 id="基本的-crud-操作">基本的 CRUD 操作
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 1. 確認存在與否 (Read)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$keyPath&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;HKCU:\Software\MyCustomApp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">-Not&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Test-Path&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$keyPath&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 2. 建立新機碼 (Create)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">New-Item&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;HKCU:\Software&amp;#34;&lt;/span> &lt;span class="n">-Name&lt;/span> &lt;span class="s2">&amp;#34;MyCustomApp&amp;#34;&lt;/span> &lt;span class="n">-Force&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">Out-Null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;已建立機碼。&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 3. 寫入或更新值 (Update) - 將 1 寫入為 REG_DWORD&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Set-ItemProperty&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$keyPath&lt;/span> &lt;span class="n">-Name&lt;/span> &lt;span class="s2">&amp;#34;EnableDebug&amp;#34;&lt;/span> &lt;span class="n">-Value&lt;/span> &lt;span class="mf">1&lt;/span> &lt;span class="n">-Type&lt;/span> &lt;span class="n">DWord&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 4. 讀取值 (Read)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$debugFlag&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Get-ItemProperty&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$keyPath&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="py">EnableDebug&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;目前的偵錯旗標: &lt;/span>&lt;span class="nv">$debugFlag&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 5. 刪除值 (Delete)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Remove-ItemProperty&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$keyPath&lt;/span> &lt;span class="n">-Name&lt;/span> &lt;span class="s2">&amp;#34;EnableDebug&amp;#34;&lt;/span> &lt;span class="n">-Force&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="實作範例-1開發環境的自動設定新增環境變數-path">實作範例 1：開發環境的自動設定（新增環境變數 PATH）
&lt;/h3>&lt;p>以下的指令碼是一個自動化的範例，可讓開發人員在設定新的 Windows 機器時，將自訂工具的目錄安全地新增至使用者環境變數 &lt;code>PATH&lt;/code> 中。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$envKey&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;HKCU:\Environment&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$newPath&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;C:\tools\bin&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 讀取目前的 PATH（抑制錯誤以確保安全取得）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$currentPathInfo&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-ItemProperty&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$envKey&lt;/span> &lt;span class="n">-Name&lt;/span> &lt;span class="s2">&amp;#34;Path&amp;#34;&lt;/span> &lt;span class="n">-ErrorAction&lt;/span> &lt;span class="n">SilentlyContinue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$currentPath&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$currentPathInfo&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nv">$currentPathInfo&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Path&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 使用正則表達式檢查是否已經包含&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$currentPath&lt;/span> &lt;span class="o">-notmatch&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="no">regex&lt;/span>&lt;span class="p">]::&lt;/span>&lt;span class="n">Escape&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nv">$newPath&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 如果結尾沒有分號則加上並進行合併&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$currentPath&lt;/span> &lt;span class="o">-and&lt;/span> &lt;span class="nv">$currentPath&lt;/span> &lt;span class="o">-notmatch&lt;/span> &lt;span class="s2">&amp;#34;;$&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$currentPath&lt;/span> &lt;span class="p">+=&lt;/span> &lt;span class="s2">&amp;#34;;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$updatedPath&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nv">$currentPath&lt;/span> &lt;span class="p">+&lt;/span> &lt;span class="nv">$newPath&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 以 REG_EXPAND_SZ 型別寫入（重要）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Set-ItemProperty&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$envKey&lt;/span> &lt;span class="n">-Name&lt;/span> &lt;span class="s2">&amp;#34;Path&amp;#34;&lt;/span> &lt;span class="n">-Value&lt;/span> &lt;span class="nv">$updatedPath&lt;/span> &lt;span class="n">-Type&lt;/span> &lt;span class="n">ExpandString&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;已更新 PATH 環境變數: &lt;/span>&lt;span class="nv">$newPath&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 通知執行中的處理程序環境變數已變更 (WM_SETTINGCHANGE)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 如此一來，不需重新開機即可反映在新的檔案總管等程式中&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="no">Environment&lt;/span>&lt;span class="p">]::&lt;/span>&lt;span class="n">SetEnvironmentVariable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Path&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nv">$updatedPath&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="no">EnvironmentVariableTarget&lt;/span>&lt;span class="p">]::&lt;/span>&lt;span class="n">User&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;PATH 已經新增過了。&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="實作範例-2在快顯功能表中新增自訂動作">實作範例 2：在快顯功能表中新增自訂動作
&lt;/h3>&lt;p>這個指令碼會在右鍵點擊特定的檔案或目錄時的快顯功能表中，新增一個「使用 My IDE 開啟」的獨立項目。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 在目錄背景（空白處）點擊右鍵時的功能表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$menuPath&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;HKCR:\Directory\Background\shell\OpenWithMyIDE&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$commandPath&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$menuPath&lt;/span>&lt;span class="s2">\command&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 建立功能表項目的父機碼&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">New-Item&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$menuPath&lt;/span> &lt;span class="n">-Force&lt;/span> &lt;span class="n">-ErrorAction&lt;/span> &lt;span class="n">Stop&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">Out-Null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 在 (default) 值中設定顯示名稱&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Set-ItemProperty&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$menuPath&lt;/span> &lt;span class="n">-Name&lt;/span> &lt;span class="s2">&amp;#34;(default)&amp;#34;&lt;/span> &lt;span class="n">-Value&lt;/span> &lt;span class="s2">&amp;#34;使用 My IDE 開啟&amp;#34;&lt;/span> &lt;span class="n">-Type&lt;/span> &lt;span class="n">String&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 設定圖示（非必要）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Set-ItemProperty&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$menuPath&lt;/span> &lt;span class="n">-Name&lt;/span> &lt;span class="s2">&amp;#34;Icon&amp;#34;&lt;/span> &lt;span class="n">-Value&lt;/span> &lt;span class="s2">&amp;#34;C:\Program Files\MyIDE\ide.exe,0&amp;#34;&lt;/span> &lt;span class="n">-Type&lt;/span> &lt;span class="n">String&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 建立 command 子機碼，並設定要執行的命令列&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># %V 會展開為目前目錄的路徑變數&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">New-Item&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$commandPath&lt;/span> &lt;span class="n">-Force&lt;/span> &lt;span class="n">-ErrorAction&lt;/span> &lt;span class="n">Stop&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">Out-Null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Set-ItemProperty&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$commandPath&lt;/span> &lt;span class="n">-Name&lt;/span> &lt;span class="s2">&amp;#34;(default)&amp;#34;&lt;/span> &lt;span class="n">-Value&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">`&amp;#34;&lt;/span>&lt;span class="s2">C:\Program Files\MyIDE\ide.exe&lt;/span>&lt;span class="se">`&amp;#34;&lt;/span>&lt;span class="s2"> &lt;/span>&lt;span class="se">`&amp;#34;&lt;/span>&lt;span class="s2">%V&lt;/span>&lt;span class="se">`&amp;#34;&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="n">-Type&lt;/span> &lt;span class="n">String&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;已新增快顯功能表項目。&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Error&lt;/span> &lt;span class="s2">&amp;#34;登錄檔變更失敗。請確認是否以管理員權限執行。錯誤: &lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="從-powershell-存取登錄檔的內部序列">從 PowerShell 存取登錄檔的內部序列
&lt;/h3>&lt;p>以下為 PowerShell 指令碼變更登錄檔時，在作業系統內部的運作序列。&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
participant U as &amp;#34;管理員 / PowerShell&amp;#34;
participant PS as &amp;#34;登錄檔提供者 (.NET)&amp;#34;
participant CM as &amp;#34;設定管理員 (核心)&amp;#34;
participant Disk as &amp;#34;NTFS 上的 Hive 檔案&amp;#34;
U-&amp;gt;&amp;gt;PS: &amp;#34;Set-ItemProperty -Path ... -Value ...&amp;#34;
PS-&amp;gt;&amp;gt;PS: &amp;#34;解析路徑與驗證資料型別&amp;#34;
PS-&amp;gt;&amp;gt;CM: &amp;#34;NtSetValueKey (系統呼叫)&amp;#34;
CM-&amp;gt;&amp;gt;CM: &amp;#34;根據機碼 ACL 檢查存取權杖&amp;#34;
alt &amp;#34;授予存取權限 (管理員權杖)&amp;#34;
CM-&amp;gt;&amp;gt;CM: &amp;#34;在揮發性快取中配置單元&amp;#34;
CM-&amp;gt;&amp;gt;Disk: &amp;#34;排清至交易記錄檔 (.log1)&amp;#34;
Disk--&amp;gt;&amp;gt;CM: &amp;#34;記錄寫入成功&amp;#34;
CM-&amp;gt;&amp;gt;Disk: &amp;#34;延遲寫入至 Hive 資料檔 (背景)&amp;#34;
CM--&amp;gt;&amp;gt;PS: &amp;#34;STATUS_SUCCESS (0x00000000)&amp;#34;
PS--&amp;gt;&amp;gt;U: &amp;#34;命令已完成&amp;#34;
else &amp;#34;拒絕存取 (標準使用者)&amp;#34;
CM--&amp;gt;&amp;gt;PS: &amp;#34;STATUS_ACCESS_DENIED (0xC0000022)&amp;#34;
PS--&amp;gt;&amp;gt;U: &amp;#34;擲回 UnauthorizedAccessException&amp;#34;
end
&lt;/pre>
&lt;h2 id="9-透過-c-net-進行堅固的登錄檔存取">9. 透過 C# (.NET) 進行堅固的登錄檔存取
&lt;/h2>&lt;p>從 .NET 應用程式（如 C# 等）存取登錄檔時，會使用 &lt;code>Microsoft.Win32.Registry&lt;/code> 類別與 &lt;code>RegistryKey&lt;/code> 類別。
使用 C# 的最大優點在於：可透過強大的例外處理（&lt;code>try-catch&lt;/code>）進行堅固的錯誤處理、嚴格的型別檢查，以及能使用 &lt;code>RegistryView&lt;/code> 列舉明確指定 32 位元/64 位元的檢視畫面。&lt;/p>
&lt;p>以下是在 64 位元作業系統環境下，確實讀寫 64 位元端登錄檔（迴避 WOW6432Node 重新導向）的 C# 程式碼範例。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">System&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">System.Security&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">Microsoft.Win32&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">RegistryEditor&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">static&lt;/span> &lt;span class="k">void&lt;/span> &lt;span class="n">Main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// HKLM 底下的路徑 (需要管理員權限)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">string&lt;/span> &lt;span class="n">keyPath&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">@&amp;#34;SOFTWARE\MyEnterpriseApp\Settings&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 指定 RegistryView.Registry64 來開啟 64 位元原生檢視&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 使用 using 陳述式，確保登錄機碼的控制代碼 (非受控資源) 確實被 Dispose&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">using&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">RegistryKey&lt;/span> &lt;span class="n">baseKey&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">RegistryKey&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">OpenBaseKey&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">RegistryHive&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">LocalMachine&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">RegistryView&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Registry64&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 以寫入權限 (writable: true) 開啟機碼。若不存在則建立。&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">using&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">RegistryKey&lt;/span> &lt;span class="n">subKey&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">baseKey&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">CreateSubKey&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">keyPath&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">writable&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">subKey&lt;/span> &lt;span class="p">!=&lt;/span> &lt;span class="kc">null&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 寫入為 REG_DWORD 值&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">subKey&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">SetValue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;MaxConnections&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="m">100&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">RegistryValueKind&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">DWord&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 寫入為 REG_SZ 值&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">subKey&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">SetValue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;ApiEndpoint&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;https://api.example.com&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">RegistryValueKind&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 寫入為 REG_BINARY 位元組陣列&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">byte&lt;/span>&lt;span class="p">[]&lt;/span> &lt;span class="n">secretData&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="m">0x01&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="m">0x02&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="m">0x0A&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="m">0xFF&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">subKey&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">SetValue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;BinarySecret&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">secretData&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">RegistryValueKind&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Binary&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WriteLine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;成功寫入登錄檔。&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">catch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">UnauthorizedAccessException&lt;/span> &lt;span class="n">ex&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 未以管理員身分執行時經常發生&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WriteLine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">$&amp;#34;權限錯誤: 請「以系統管理員身分執行」程式。詳細: {ex.Message}&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">catch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">SecurityException&lt;/span> &lt;span class="n">ex&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 被 .NET 的程式碼存取安全性 (CAS) 封鎖時&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WriteLine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">$&amp;#34;安全性例外狀況: {ex.Message}&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">catch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">Exception&lt;/span> &lt;span class="n">ex&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 其他非預期的 IO 錯誤等&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WriteLine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">$&amp;#34;非預期的錯誤: {ex.Message}&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>開啟登錄機碼時，由作業系統傳回的「控制代碼（Handle）」，是會消耗記憶體與系統資源的非受控資源。因此，在 C# 程式設計中，使用 &lt;code>using&lt;/code> 區塊，或在 &lt;code>finally&lt;/code> 區塊內明確地呼叫 &lt;code>.Dispose()&lt;/code>（或 &lt;code>.Close()&lt;/code>）以確保防範控制代碼外洩，是一項鐵則。&lt;/p>
&lt;h2 id="10-登錄檔的備份與還原手法">10. 登錄檔的備份與還原手法
&lt;/h2>&lt;p>即使是透過指令碼或程式進行的自動化，在進行關鍵變更之前，取得備份絕對是不可或缺的。&lt;/p>
&lt;h3 id="透過-reg-檔案備份與匯入">透過 .reg 檔案備份與匯入
&lt;/h3>&lt;p>最古典且通用的方法就是匯出為 &lt;code>.reg&lt;/code> 檔案。這個檔案是具有獨特格式的文字型檔案，其結構如下：&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">Windows Registry Editor Version 5.00
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">[HKEY_CURRENT_USER\Software\MyCustomApp]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;#34;EnableDebug&amp;#34;=dword:00000001
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;#34;ApiEndpoint&amp;#34;=&amp;#34;https://api.example.com&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;#34;BinaryData&amp;#34;=hex:01,02,0a,ff
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;em>註：二進位資料是以接在 &lt;code>hex:&lt;/code> 後面、以逗號分隔的 16 進位數來表示。&lt;/em>&lt;/p>
&lt;p>您可以使用命令列工具 &lt;code>reg.exe&lt;/code>，在批次指令碼內實作自動備份。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmd" data-lang="cmd">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">REM 備份指定的機碼（也會遞迴匯出子機碼）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">reg export HKLM\SOFTWARE\MyEnterpriseApp C:\backup\myapp_backup.reg /y
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">REM 還原備份&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">reg import C:\backup\myapp_backup.reg
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="利用-powershell-的進階備份手法">利用 PowerShell 的進階備份手法
&lt;/h3>&lt;p>不僅僅是作為文字，我們還可以活用 PowerShell 的物件導向特性，將登錄檔的物件匯出並儲存為 XML 格式（CliXML）。這樣一來，在還原時就不必依賴字串的解析，並能在維持型別資訊的情況下進行處理。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 取得備份（將屬性儲存為 XML）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Get-ItemProperty&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;HKCU:\Software\MyCustomApp&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">Export-Clixml&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;C:\backup\reg_backup.xml&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 還原的概念&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$backup&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Import-Clixml&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;C:\backup\reg_backup.xml&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 由於 $backup 內儲存了已還原的自訂 PSObject，&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 因此可透過迴圈讀取其屬性，並編寫使用 Set-ItemProperty 重新套用的邏輯。&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="11-使用-sysinternals-process-monitor-procmon-進行疑難排解">11. 使用 Sysinternals Process Monitor (Procmon) 進行疑難排解
&lt;/h2>&lt;p>若不清楚程式寫入了登錄檔的哪個地方，或者想尋找「Access Denied」的原因時，Microsoft 免費提供的 Sysinternals 工具 &lt;strong>Process Monitor (Procmon)&lt;/strong> 非常強大。
使用 Procmon，可以即時擷取在作業系統上發生的所有登錄檔 API 呼叫（如 &lt;code>RegOpenKey&lt;/code>、&lt;code>RegQueryValue&lt;/code>、&lt;code>RegSetValue&lt;/code> 等），並透過以下進階篩選功能進行疑難排解：&lt;/p>
&lt;ul>
&lt;li>&lt;code>Process Name&lt;/code> is &lt;code>powershell.exe&lt;/code>&lt;/li>
&lt;li>&lt;code>Operation&lt;/code> begins with &lt;code>Reg&lt;/code>&lt;/li>
&lt;li>&lt;code>Result&lt;/code> is &lt;code>ACCESS DENIED&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>這樣一來，就能在瞬間找出是哪個機碼的 ACL 設定不足，或者是是否錯誤地重新導向到了 WOW6432Node。&lt;/p>
&lt;h2 id="12-安全性與最佳實務">12. 安全性與最佳實務
&lt;/h2>&lt;p>最後，總結在處理登錄檔時重要的設計原則與最佳實務。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>貫徹最低權限原則&lt;/strong>：應用程式或指令碼的設定，應盡可能儲存在 &lt;code>HKCU&lt;/code>（目前使用者）內的 &lt;code>Software&lt;/code> 機碼底下。寫入 &lt;code>HKLM&lt;/code> 會要求透過 UAC 提升至管理員權限，這將擴大安全性上的攻擊面（Attack Surface），並損害使用者體驗。&lt;/li>
&lt;li>&lt;strong>啟用稽核 (Auditing)&lt;/strong>：針對安全性上極其重要的機碼（例如：負責自動啟動的 &lt;code>Run&lt;/code> 機碼，或服務設定的機碼等），應設定 SACL（System Access Control List，系統存取控制清單），以便在 Windows 事件檢視器的「安全性記錄」中，記錄（稽核）是誰在何時變更或刪除了值。&lt;/li>
&lt;li>&lt;strong>因應交易功能的棄用&lt;/strong>：過去在 Windows Vista 導入、利用「核心交易管理員 (KTM)」的登錄檔交易功能 (TxR)，自 Windows 10 起已標示為已被取代（Deprecated）。必須在應用程式端自行實作備份與復原機制（例如在變更前先讀取原始值並保留在記憶體中）。&lt;/li>
&lt;li>&lt;strong>注意與群組原則 (GPO) 的衝突&lt;/strong>：&lt;code>HKLM\SOFTWARE\Policies&lt;/code> 和 &lt;code>HKCU\Software\Policies&lt;/code> 區域，應交由 Active Directory 的群組原則統一管理。即使從指令碼直接改寫這些機碼，在下一次群組原則背景更新週期（通常每隔 90 到 120 分鐘）時，也會被網域控制站的設定強制覆寫，成為設定無法永久保留的原因。&lt;/li>
&lt;/ol>
&lt;h2 id="總結">總結
&lt;/h2>&lt;p>Windows 登錄檔是個強大且複雜的基礎系統，統整管理了作業系統的所有行為與應用程式設定。手動且無序的編輯將伴隨極高的系統損毀風險，這在數學上也是可以被證實的。因此，使用 PowerShell 和 C# 等可程式化的手段，遵循「基礎架構即程式碼 (Infrastructure as Code)」的原則，以安全、可測試且可重現的方式進行組態管理，在現代的系統管理與開發中是不可或缺的。請活用本文所解說的深層架構理解與實作模式，目標是建構出更堅固且安全的 Windows 環境。&lt;/p></description></item></channel></rss>