Import-Module之「Missing argument in parameter list」鬼打牆筆記

Import-Module之「Missing argument in parameter list」鬼打牆筆記

故事是這樣的,我在PowerShell Core環境下開發了一個PowerShell Module。但不是每一台Windows Server都有PowerShell Core的執行環境,當部屬至Windows Server的PowerShell時才發現某些主機怪怪的。

此Module在我Windows 11開發機裡的PowerShell或PowerShell Core都有先測試過都,都能正常執行。

Import Module Success
Import Module Fail

兩台不同的Windows Server 2019主機上,PowerShell的Import-Module一台正常,一台不正常。而且在特定同事的開發機上也有類似的情況,也會出現匯入錯誤的情況。

我改寫一個可重現此錯誤的測試程式碼:

function Send-UdspMail {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]
        $Subject,
        [Parameter(Mandatory = $true)]
        [string]
        $Content,
        [Parameter(Mandatory = $true)]
        [string]
        $TO,
        [string]
        $CC = "",
        [string]
        $BCC = ""
    )
    
    begin {
        Write-Debug "Running time: $(Get-Date)"
        Write-Debug "FunctionName: Send-UdspMail"
    }
    
    process {

        if  (("" -eq $CC) -and ("" -eq $BCC)) {
            Write-Debug "無CC.無BCC."

            $jsonParam = 
@"
`"{`\`"From`\`":`\`"i@test.com`\`",`\`"Subject`\`":`\`"$Subject`\`",`\`"Content`\`":`\`"$Content`\`",`\`"CreatedBy`\`":`\`"PowerShell`\`",`\`"ReceiverList`\`":[{`\`"Type`\`":`\`"To`\`",`\`"MailAddress`\`":`\`"$TO`\`"}],`\`"Tags`\`":[`\`"PowerShell`\`"]}`"
"@
        }

        if  (("" -ne $CC) -and ("" -eq $BCC)) {
            Write-Debug "有CC: $CC ;無BCC."

            $jsonParam = 
@"
`"{`\`"From`\`":`\`"i@test.com`\`",`\`"Subject`\`":`\`"$Subject`\`",`\`"Content`\`":`\`"$Content`\`",`\`"CreatedBy`\`":`\`"PowerShell`\`",`\`"ReceiverList`\`":[{`\`"Type`\`":`\`"To`\`",`\`"MailAddress`\`":`\`"$TO`\`"},{`\`"Type`\`":`\`"CC`\`",`\`"MailAddress`\`":`\`"$CC`\`"}],`\`"Tags`\`":[`\`"PowerShell`\`"]}`"
"@
        }
        
        if  (("" -eq $CC) -and ("" -ne $BCC)) {
            Write-Debug "無CC;有BCC: $BCC ."

            $jsonParam = 
@"
`"{`\`"From`\`":`\`"i@test.com`\`",`\`"Subject`\`":`\`"$Subject`\`",`\`"Content`\`":`\`"$Content`\`",`\`"CreatedBy`\`":`\`"PowerShell`\`",`\`"ReceiverList`\`":[{`\`"Type`\`":`\`"To`\`",`\`"MailAddress`\`":`\`"$TO`\`"},{`\`"Type`\`":`\`"BCC`\`",`\`"MailAddress`\`":`\`"$BCC`\`"}],`\`"Tags`\`":[`\`"PowerShell`\`"]}`"
"@
        }
        
        
        if  (("" -ne $CC) -and ("" -ne $BCC)) {
            Write-Debug "有CC: $CC ;有BCC: $BCC ."

            $jsonParam = 
@"
`"{`\`"From`\`":`\`"i@test.com`\`",`\`"Subject`\`":`\`"$Subject`\`",`\`"Content`\`":`\`"$Content`\`",`\`"CreatedBy`\`":`\`"PowerShell`\`",`\`"ReceiverList`\`":[{`\`"Type`\`":`\`"To`\`",`\`"MailAddress`\`":`\`"$TO`\`"},{`\`"Type`\`":`\`"CC`\`",`\`"MailAddress`\`":`\`"$CC`\`"},{`\`"Type`\`":`\`"BCC`\`",`\`"MailAddress`\`":`\`"$BCC`\`"}],`\`"Tags`\`":[`\`"PowerShell`\`"]}`"
"@
        }

        $body = ...

        $response = Invoke-RestMethod YourAPIURI -Method 'POST' -Headers $headers -Body $body
    }
    
    end {
        return $response
    }
}

它是一段發送Email的服務,因為要判斷是否有$CC$BCC這幾個選項,擁有不同選項所需要的JSON格式不同。雖然是在PowerShell Core開發,但都有特別小心不要用到PowerShell未提供的語法,且在正常主機中,不論PowerShell或PowerShell Core都能正常執行。

但錯誤訊息「Missing argument in parameter list」讓我測試了好久好久,可以說完全沒有頭緒。

PS C:> Import-Module UdspService
At C:\PsScript\Modules\UdspService\UdspService.ps1:40 char:35
+ `"{`\`"From`\`":`\`"i@test.com`\`",`\`"Subject`\`":`\`"$Subject`\`",` ...
+                                   ~
Missing argument in parameter list.
At C:\PsScript\Modules\UdspService\UdspService.ps1:40 char:185
+ ... owerShell`\`",`\`"ReceiverList`\`":[{`\`"Type`\`":`\`"To`\`",`\`"Mail ...
+                                                                 ~
Missing argument in parameter list.
At C:\PsScript\Modules\UdspService\UdspService.ps1:40 char:243
+ ... `",`\`"MailAddress`\`":`\`"$TO`\`"},{`\`"Type`\`":`\`"CC`\`",`\`"Mail ...
+                                                                 ~
Missing argument in parameter list.
At C:\PsScript\Modules\UdspService\UdspService.ps1:45 char:26
+             Write-Debug "無CC;有BCC: $BCC ."
+                          ~~~~~~~~~~~~~~~~~~~~~
Unexpected token '無CC;有BCC: $BCC ."' in expression or statement.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingArgument

不可能是在組合JSON格式的段落有問題,如果有問題,應該是全部都有問題,為何是部分Windows Server,又或者部分同事開發機有問題。

就在快追不下去時,同事傳來一個消息,它如果是以這樣的指令來執行,那麼可以執行成功。

powershell.exe -ExcutionPolicy Bypass -File .\Test.ps1

我嘗試了許多次,都已經把所有-ExcutionPolicy都開到**無限制(Unrestricted)**了,但還是解決不了Import-Module的錯誤。而且相互比對之後,成功與失敗主機本身的-ExcutionPolicy並無不同。這下又進入死胡同了。

在沒日沒夜的測試之後,終於找問題點,我們先來看看修改之後不會失敗的程式碼:

function Send-UdspMail {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]
        $Subject,
        [Parameter(Mandatory = $true)]
        [string]
        $Content,
        [Parameter(Mandatory = $true)]
        [string]
        $TO,
        [string]
        $CC = "",
        [string]
        $BCC = ""
    )
    
    begin {
        Write-Debug "Running time: $(Get-Date)"
        Write-Debug "FunctionName: Send-UdspMail"
    }
    
    process {

        if  (("" -eq $CC) -and ("" -eq $BCC)) {
            Write-Debug "No CC.No BCC."

            $jsonParam = 
@"
`"{`\`"From`\`":`\`"i@test.com`\`",`\`"Subject`\`":`\`"$Subject`\`",`\`"Content`\`":`\`"$Content`\`",`\`"CreatedBy`\`":`\`"PowerShell`\`",`\`"ReceiverList`\`":[{`\`"Type`\`":`\`"To`\`",`\`"MailAddress`\`":`\`"$TO`\`"}],`\`"Tags`\`":[`\`"PowerShell`\`"]}`"
"@
        }

        if  (("" -ne $CC) -and ("" -eq $BCC)) {
            Write-Debug "Have CC: $CC ;No BCC."

            $jsonParam = 
@"
`"{`\`"From`\`":`\`"i@test.com`\`",`\`"Subject`\`":`\`"$Subject`\`",`\`"Content`\`":`\`"$Content`\`",`\`"CreatedBy`\`":`\`"PowerShell`\`",`\`"ReceiverList`\`":[{`\`"Type`\`":`\`"To`\`",`\`"MailAddress`\`":`\`"$TO`\`"},{`\`"Type`\`":`\`"CC`\`",`\`"MailAddress`\`":`\`"$CC`\`"}],`\`"Tags`\`":[`\`"PowerShell`\`"]}`"
"@
        }
        
        if  (("" -eq $CC) -and ("" -ne $BCC)) {
            Write-Debug "No CC;Have BCC: $BCC ."

            $jsonParam = 
@"
`"{`\`"From`\`":`\`"i@test.com`\`",`\`"Subject`\`":`\`"$Subject`\`",`\`"Content`\`":`\`"$Content`\`",`\`"CreatedBy`\`":`\`"PowerShell`\`",`\`"ReceiverList`\`":[{`\`"Type`\`":`\`"To`\`",`\`"MailAddress`\`":`\`"$TO`\`"},{`\`"Type`\`":`\`"BCC`\`",`\`"MailAddress`\`":`\`"$BCC`\`"}],`\`"Tags`\`":[`\`"PowerShell`\`"]}`"
"@
        }
        
        
        if  (("" -ne $CC) -and ("" -ne $BCC)) {
            Write-Debug "Have CC: $CC ;Have BCC: $BCC ."

            $jsonParam = 
@"
`"{`\`"From`\`":`\`"i@test.com`\`",`\`"Subject`\`":`\`"$Subject`\`",`\`"Content`\`":`\`"$Content`\`",`\`"CreatedBy`\`":`\`"PowerShell`\`",`\`"ReceiverList`\`":[{`\`"Type`\`":`\`"To`\`",`\`"MailAddress`\`":`\`"$TO`\`"},{`\`"Type`\`":`\`"CC`\`",`\`"MailAddress`\`":`\`"$CC`\`"},{`\`"Type`\`":`\`"BCC`\`",`\`"MailAddress`\`":`\`"$BCC`\`"}],`\`"Tags`\`":[`\`"PowerShell`\`"]}`"
"@
        }

        $body = ...

        $response = Invoke-RestMethod YourAPIURI -Method 'POST' -Headers $headers -Body $body
    }
    
    end {
        return $response
    }
}

原因不在JSON格式上面,是因為我在Write-Debug "無CC.無BCC."裡面寫了中文。但部屬到英文版的Windows Server的PowerShell執行時會有問題。PowerShell Core對於UniCode的相容性很好,因此就算在英文版Windows Server上也能正常執行。請有問題的同事修改本機指令碼測試,它的開發機是英文版,因此也中了一樣的頭獎,修改訊息為英文之後,一切正常。

回頭看看錯誤訊息,其實訊息有反應出看不懂中文的問題:Unexpected token 'ç„¡CC;有BCC: $BCC ."' in expression or statement.,只是一直被前面那一句「Missing argument in parameter list」搞得不知所措。

最後一個迷團,為何一開始的Windows Server 2019,有一台能正常,有一台不正常?以下是我所能找到的合理解釋:

Windows Region Setting

正常這台有升級過一次,我猜是之前是中文版然後升為英文版,但核心保留中文資源,以致於Module裡Write-Debug的中文沒有造成錯誤。但如果是純英文版環境,則程式碼包含中文就有一定的風險了。

完全沒想到「中文訊息輸出訊息」+「英文版PowerShell」+「錯誤的錯誤訊息」一連串連鎖反應,造成這難以偵錯的過程。

沒有留言:

張貼留言

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。