<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>PowerShell on KnightLi的博客</title>
        <link>https://knightli.com/zh-tw/tags/powershell/</link>
        <description>Recent content in PowerShell on KnightLi的博客</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-tw</language>
        <lastBuildDate>Wed, 01 Jul 2026 10:06:48 +0800</lastBuildDate><atom:link href="https://knightli.com/zh-tw/tags/powershell/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Codex 大戰 PowerShell：powershell-safe-invocation Skill 解決了什麼</title>
        <link>https://knightli.com/zh-tw/2026/07/01/codex-vs-powershell-safe-invocation/</link>
        <pubDate>Wed, 01 Jul 2026 10:06:48 +0800</pubDate>
        
        <guid>https://knightli.com/zh-tw/2026/07/01/codex-vs-powershell-safe-invocation/</guid>
        <description>&lt;p&gt;最近看到一張很有節目效果的截圖：Codex 在 PowerShell 裡修一個 Markdown 檔案，先是 here-string 沒執行，接著 CRLF/LF 匹配失敗，再到反引號被 PowerShell 解析、路徑反斜線處理不穩、&lt;code&gt;-split&lt;/code&gt; 參數寫法踩坑。模型一路自我診斷，一路繼續補腳本，最後留言區給它起了一個很準確的標題：經典 GPT 5.5 大戰 PowerShell。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://knightli.com/2026/07/01/codex-vs-powershell-safe-invocation/codex-powershell-battle.jpg&#34;
	width=&#34;1080&#34;
	height=&#34;2400&#34;
	srcset=&#34;https://knightli.com/2026/07/01/codex-vs-powershell-safe-invocation/codex-powershell-battle_hu_5b7da40f3bf17d89.jpg 480w, https://knightli.com/2026/07/01/codex-vs-powershell-safe-invocation/codex-powershell-battle_hu_a1711b2e97eccd27.jpg 1024w&#34;
	
		loading=&#34;eager&#34;
		fetchpriority=&#34;high&#34;
		decoding=&#34;sync&#34;
	
	
		alt=&#34;Codex 在 PowerShell 中反覆修腳本的截圖&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;45&#34;
		data-flex-basis=&#34;108px&#34;
	
&gt;
&lt;/p&gt;
&lt;p&gt;截圖裡這串連續補救很有梗，但它背後的坑並不罕見。&lt;/p&gt;
&lt;p&gt;這張圖好笑，是因為它太像真實開發現場。PowerShell 並不是簡單的「Windows 版 Bash」。它有自己的字串規則、參數繫結規則、cmdlet 錯誤模型和原生命令傳參方式。Agent 一旦把 Bash 習慣帶進 PowerShell，寫檔案、替換文字、呼叫外部程式這些看似普通的任務，就會變成連續小翻車。&lt;/p&gt;
&lt;p&gt;Misaka-Mikoto-Tech 的 &lt;a class=&#34;link&#34; href=&#34;https://github.com/Misaka-Mikoto-Tech/agent-skills/tree/main/skills/powershell-safe-invocation&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;powershell-safe-invocation&lt;/a&gt; skill，正好把這些坑收束成一套簡潔規則。它不是教人「多背 PowerShell 語法」，而是告訴 Agent：在 Windows 上執行命令時，先選不容易出錯的呼叫形態。&lt;/p&gt;
&lt;h2 id=&#34;最大的問題不是-powershell-難而是-agent-容易把它當-bash&#34;&gt;最大的問題不是 PowerShell 難，而是 Agent 容易把它當 Bash
&lt;/h2&gt;&lt;p&gt;截圖裡的幾個問題很典型。&lt;/p&gt;
&lt;p&gt;第一類是字串和換行。Markdown 裡有反引號，PowerShell 也把反引號當轉義符；文件可能是 CRLF，腳本卻按 LF 精確匹配；here-string 的起止格式只要縮排或引號不對，就可能根本沒有按預期產生文字。&lt;/p&gt;
&lt;p&gt;第二類是路徑和參數。Windows 路徑天然帶反斜線，目錄裡還常有空格、中括號和中文。把命令拼成一整串再執行，很容易讓某個參數被拆開，或者讓某段路徑被當成轉義、萬用字元、正規表示式或另一個 shell 的語法。&lt;/p&gt;
&lt;p&gt;第三類是錯誤判斷。外部程式要看 &lt;code&gt;$LASTEXITCODE&lt;/code&gt;，PowerShell cmdlet 則應該依賴終止錯誤和 &lt;code&gt;$ErrorActionPreference = &#39;Stop&#39;&lt;/code&gt;。如果 Agent 混用這兩套模型，就會出現「命令其實沒成功，但腳本以為成功了」的狀態。&lt;/p&gt;
&lt;p&gt;這些都不是大故障，卻很消耗注意力。Agent 還會因為「看起來已經執行過命令」而繼續在錯誤假設上修補，越修越繞。&lt;/p&gt;
&lt;h2 id=&#34;這個-skill-的核心不要拼大字串&#34;&gt;這個 skill 的核心：不要拼大字串
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;powershell-safe-invocation&lt;/code&gt; 裡最重要的一條，是不要把可執行檔、路徑、參數和引號拼成一個巨大的命令字串。&lt;/p&gt;
&lt;p&gt;呼叫原生程式時，應該把每個參數作為陣列裡的一個獨立元素：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-powershell&#34; data-lang=&#34;powershell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$exe&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;C:\Path With Spaces\tool.exe&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$args&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s1&#34;&gt;&amp;#39;--input&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s1&#34;&gt;&amp;#39;C:\Data Folder\input.json&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s1&#34;&gt;&amp;#39;--flag&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$exe&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;@args&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$exitCode&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$LASTEXITCODE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$exitCode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-ne&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$exe&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; failed with exit code &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$exitCode&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;這段看起來比一行命令囉嗦，但它把風險拆開了：路徑就是路徑，參數就是參數，呼叫就是呼叫。Agent 不需要猜這一層引號是給 PowerShell 的、給 cmd 的，還是給目標程式的。&lt;/p&gt;
&lt;p&gt;對 PowerShell cmdlet，則更適合用 hashtable splatting：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-powershell&#34; data-lang=&#34;powershell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$params&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;LiteralPath&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;C:\Data[1]\input.txt&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Destination&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;C:\Output&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Force&lt;/span&gt;       &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;$true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ErrorAction&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;Stop&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;Copy-Item&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;@params&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;這裡的關鍵是 &lt;code&gt;-LiteralPath&lt;/code&gt;。真實路徑預設按字面量處理，只有確實需要萬用字元時才使用會展開的路徑參數。對 Agent 來說，這比臨時判斷路徑裡有沒有 &lt;code&gt;[&lt;/code&gt;、&lt;code&gt;]&lt;/code&gt;、&lt;code&gt;*&lt;/code&gt;、&lt;code&gt;?&lt;/code&gt; 更穩。&lt;/p&gt;
&lt;h2 id=&#34;複雜命令別塞進--command&#34;&gt;複雜命令別塞進 &lt;code&gt;-Command&lt;/code&gt;
&lt;/h2&gt;&lt;p&gt;很多 Windows 自動化事故，都從這一類命令開始：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cmd.exe /c pwsh.exe -Command &amp;#34;...&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;裡面一旦出現 JSON、XML、正規表示式、管線、重新導向、多行文字、非 ASCII 路徑或 Markdown 反引號，轉義層數就會迅速失控。對人來說難讀，對 Agent 來說更容易誤判。&lt;/p&gt;
&lt;p&gt;skill 給出的選擇很樸素：複雜一點就寫臨時 &lt;code&gt;.ps1&lt;/code&gt; 檔案，再用 &lt;code&gt;pwsh.exe -NoLogo -NoProfile -NonInteractive -File script.ps1&lt;/code&gt; 執行。&lt;/p&gt;
&lt;p&gt;這條規則特別適合 Agent。因為 Agent 產生腳本檔案後，可以分步檢查腳本內容、執行結果和檔案差異。把所有東西塞進一條 &lt;code&gt;-Command&lt;/code&gt;，失敗時只剩一團很難定位的引號和轉義。&lt;/p&gt;
&lt;h2 id=&#34;powershellexe-不是-pwshexe&#34;&gt;&lt;code&gt;powershell.exe&lt;/code&gt; 不是 &lt;code&gt;pwsh.exe&lt;/code&gt;
&lt;/h2&gt;&lt;p&gt;另一個容易被忽略的點是版本。&lt;/p&gt;
&lt;p&gt;安裝 PowerShell 7，並不會讓 &lt;code&gt;powershell.exe&lt;/code&gt; 自動變成 PowerShell 7。通常：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;powershell.exe&lt;/code&gt; 是 Windows PowerShell 5.1&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pwsh.exe&lt;/code&gt; 是 PowerShell 7&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;兩者在原生命令參數傳遞、編碼預設值和一些行為細節上並不完全相同。Agent 如果不知道自己跑在哪個 shell 裡，就應該先檢查：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-powershell&#34; data-lang=&#34;powershell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$PSVersionTable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;PSVersion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$PSNativeCommandArgumentPassing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;這不是儀式感。很多「我本機可以，Agent 跑不行」的問題，根源就是 shell 版本和參數傳遞規則不同。&lt;/p&gt;
&lt;h2 id=&#34;寫檔案時編碼和換行要當成一等問題&#34;&gt;寫檔案時，編碼和換行要當成一等問題
&lt;/h2&gt;&lt;p&gt;截圖裡最有意思的地方，是 Agent 反覆圍繞 Markdown 檔案替換失敗打轉。這裡面至少有三個隱含前提：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;檔案實際編碼是什麼&lt;/li&gt;
&lt;li&gt;檔案換行是 CRLF 還是 LF&lt;/li&gt;
&lt;li&gt;替換目標是否被 PowerShell 字串語法改變過&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;中文文章、Markdown 程式碼區塊、front matter、短代碼、反引號混在一起時，最好不要用隨手拼出來的 PowerShell here-string 寫入正文。要嘛使用明確編碼的檔案 API，要嘛讓腳本本身只處理 ASCII 控制邏輯，把非 ASCII 正文交給更可靠的寫入路徑。&lt;/p&gt;
&lt;p&gt;對 Agent 工作流來說，還有一條額外經驗：寫完檔案後立刻驗證。至少檢查 UTF-8 可讀、front matter 閉合、Markdown 連結沒有斷、正文裡沒有連續問號或明顯 mojibake。很多亂碼問題越早發現越便宜。&lt;/p&gt;
&lt;h2 id=&#34;一套更穩的決策順序&#34;&gt;一套更穩的決策順序
&lt;/h2&gt;&lt;p&gt;這個 skill 最實用的部分，是給 Agent 一個決策順序：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;能用 PowerShell cmdlet，就用 cmdlet。&lt;/li&gt;
&lt;li&gt;呼叫外部程式時，用 &lt;code&gt;&amp;amp; $exe @args&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;命令複雜時，寫 &lt;code&gt;.ps1&lt;/code&gt; 檔案並用 &lt;code&gt;pwsh.exe -File&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;必須精確控制程序參數時，用 &lt;code&gt;ProcessStartInfo.ArgumentList&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;只有需要新視窗、提權、脫離目前程序等特殊行為時，才用 &lt;code&gt;Start-Process&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;只有確實需要 cmd 語義時，才套 &lt;code&gt;cmd.exe /c&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Invoke-Expression&lt;/code&gt; 放到最後，且要非常克制。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;這套順序的好處是，它把「能跑」變成「可解釋、可檢查、可重現」。對人類開發者如此，對 Agent 更是如此。&lt;/p&gt;
&lt;h2 id=&#34;給-codex-的現實建議&#34;&gt;給 Codex 的現實建議
&lt;/h2&gt;&lt;p&gt;如果讓 Codex 在 Windows 倉庫裡改檔案，我會給它幾條硬約束：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不要用 Bash 風格的 &lt;code&gt;\&amp;quot;&lt;/code&gt; 去寫 PowerShell。&lt;/li&gt;
&lt;li&gt;不要把路徑和參數拼成一整條字串。&lt;/li&gt;
&lt;li&gt;不要用 &lt;code&gt;Start-Process -ArgumentList&lt;/code&gt; 處理複雜參數。&lt;/li&gt;
&lt;li&gt;不要用 &lt;code&gt;cmd.exe /c&lt;/code&gt; 包一層來解決普通呼叫問題。&lt;/li&gt;
&lt;li&gt;對真實檔案路徑優先使用 &lt;code&gt;-LiteralPath&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;對複雜腳本優先寫 &lt;code&gt;.ps1&lt;/code&gt;，再用 &lt;code&gt;pwsh.exe -File&lt;/code&gt; 跑。&lt;/li&gt;
&lt;li&gt;寫入中文、日文等非 ASCII 內容後，必須檢查編碼和亂碼標記。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PowerShell 並不是 Agent 的敵人。真正的問題是 Agent 太容易沿用「拼字串，然後交給 shell 猜」的舊習慣。只要把呼叫邊界拆清楚，PowerShell 反而能提供很強的結構化能力。&lt;/p&gt;
&lt;p&gt;所以這場「Codex 大戰 PowerShell」的結論不是讓 Agent 避開 Windows，而是給它一份戰術手冊：少賭引號，多用結構；少塞一行命令，多保留可檢查的中間狀態。&lt;/p&gt;
&lt;p&gt;笑點在截圖裡，經驗在規則裡。&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
