從我的 RMM ( NinjaOne ) 部署 PowerShell 腳本時,腳本是從.bat(批處理檔案)呼叫的。
例子:
@powershell -ExecutionPolicy Bypass -File "test.ps1" -stringParam "testing" -switchParam > "output.txt" 2>&1
我正在呼叫的腳本需要 PowerShell 7 ,因此我需要通過pwsh使用當前引數呼叫來重新啟動腳本。我計劃通過以下方式完成此任務:
Invoke-Command { & pwsh -Command $MyInvocation.Line } -NoNewScope
不幸的是,$MyInvocation.Line當從批處理檔案呼叫 PowerShell 腳本時,不會回傳正確的結果。在這種情況下存在哪些替代方案?
筆記:
- 我無法更改
.bat檔案。 $PSBoundParameters也不回傳預期的結果。
測驗腳本(從批處理中呼叫):
Param(
[string]$string,
[switch]$switch
)
if (!($PSVersionTable.PSVersion.Major -ge 7)) {
Write-Output "`n"
Write-Output 'Attempting to restart in PowerShell 7'
if(!$MyInvocation.Line) {
Write-Output 'Parameters not carried over - cannot restart'
Exit
} else { Write-Output $MyInvocation.Line }
Invoke-Command { & pwsh -Command $MyInvocation.Line } -NoNewScope # PowerShell 7
Exit
}
Write-Output 'Parameters carried over:'
Write-Output $PSBoundParameters
Write-Output "`nSuccessfully restarted"
編輯:我發現$MyInvocation/$PSBoundParameters未正確設定的原因是由于使用了-File而不是當我的 RMM 提供程式從檔案中-Command呼叫 PowerShell 腳本時。.bat我建議他們實施此更改以解決問題。在他們這樣做之前,我仍在尋找替代品。
uj5u.com熱心網友回復:
將 RMM 提供商排除在外(其參與可能或可能無關緊要),以下test.ps1內容應該有效:
# Note: Place [CmdletBinding()] above param(...) to make
# the script an *advanced* one, which then prevents passing
# extra arguments that don't bind to declared parameters.
param(
[string] $stringParam,
[switch] $switchParam
)
# If invoked via powershell.exe, re-invoke via pwsh.exe
if ((Get-Process -Id $PID).Name -eq 'powershell') {
# $PSCommandPath is the current script's full file path,
# and @PSBoundParameters uses splatting to pass all
# arguments that were bound to declared parameters through.
# Any extra arguments, if present, are passed through with @args
pwsh -ExecutionPolicy Bypass -File $PSCommandPath @PSBoundParameters @args
exit $LASTEXITCODE
}
# Getting here means that the file is being executed by pwsh.exe
# Print the arguments received:
if ($PSBoundParameters.Count) {
"-- Bound parameters and their values:`n"
# !! Because $PSBoundParameters causes table-formatted
# !! output, synchronous output must be forced to work around a bug.
# !! See notes below.
$PSBoundParameters | Out-Host
}
if ($args) {
"`n-- Unbound (positional) arguments:`n"
$args
}
exit 0
正如代碼注釋中所建議的那樣,將腳本放在塊[CmdletBinding()]上方param(...)以使腳本成為高級腳本,在這種情況下,會主動阻止傳遞額外的引數(不系結到正式宣告的引數的引數)(在這種情況下$args不會定義)。
警告:
請注意,需要管道
$PSBoundParameters以Out-Host強制同步輸出其 value 的(默認)表格格式表示。這同樣適用于輸出任何其他會導致Format-Table不基于預定義格式資料的隱式格式的值($args作為元素為字串的陣列不受影響)。(請注意,雖然輸出通常不適合從PowerShell 會話內部輸出資料 ,但它確實會寫入外部呼叫者的stdout。)Out-Host這種需求源于一個非常不幸的輸出計時錯誤,存在于 Windows PowerShell 和當前的 PowerShell(核心)版本 7.2.1 中;它是此答案中詳細行為的變體表現,并在GitHub 問題 #13985中報告并適用于此處,因為
exit在 300 毫秒內呼叫。啟動隱式表格格式的輸出;如果你省略最后的exit 0陳述,問題就不會出現。
另見:
自動
$PSCommandPath變數,反映運行腳本的完整(絕對)路徑。自動
$PSBoundParameters變數,包含所有系結引數及其值(引數)的字典,以及自動變數$args,包含未系結到正式宣告的引數的所有(剩余)位置引數。引數splatting,其中使用 sigil
@而不是參考哈希表(字典)或陣列變數$,將哈希表的條目/陣列的元素作為單獨的引數傳遞。powershell.exe,Windows PowerShell CLI;pwsh,PowerShell(核心)7 CLI。上面使用的其他自動變數,即
$PID(當前行程的ID)和$LASTEXITCODE(最近執行的外部程式的退出代碼)。
至于你嘗試了什么:
$MyInvocation.Line通過 PowerShell 的 CLI呼叫腳本時未定義;但是,定義了反映運行腳本的完整檔案路徑的自動$PSCommandPath變數。即使已定義,由于潛在的參考問題和 - 當從 PowerShell內部呼叫時- 由于反映未擴展
$MyInvocation.Line的引數,它也不會啟用原始引數的健壯傳遞。(此外,該值將以可執行檔案/腳本名稱/路徑開頭,必須將其洗掉。)雖然
[Environment]::CommandLine確實反映了CLI 呼叫的行程命令列(也以可執行檔案名稱/路徑開頭),但參考問題也適用于此。
Invoke-Command此外,用于本地呼叫幾乎毫無意義- 請參閱此答案。
uj5u.com熱心網友回復:
我會嘗試在您的路徑早期放置一個名為的檔案powershell.bat(至少,在路徑上比C:\Windows\System32\WindowsPowerShell\v1.0\;條目更早的目錄中)并組裝適當的引數(我不知道您需要的結構$myinvocationline- 毫無疑問它可以派生從傳遞到的引數powershell.bat)。
我的想法是,這應該覆寫powershell、重新組裝這些位并將它們交付給pwsh.
uj5u.com熱心網友回復:
我把這一行放在 test.ps1 中:
$MyInvocation | Format-List -Property *
在 output.txt 中找到此內容:
MyCommand : test.ps1
BoundParameters : {}
UnboundArguments : {-stringParam, testing, -switchParam}
ScriptLineNumber : 0
OffsetInLine : 0
HistoryId : 1
ScriptName :
Line :
PositionMessage :
PSScriptRoot :
PSCommandPath :
InvocationName : D:\Temp\StackOverflow\71087897\test.ps1
PipelineLength : 2
PipelinePosition : 1
ExpectingInput : False
CommandOrigin : Runspace
DisplayScriptPosition :
然后在 test.ps1 中嘗試了這個:
[string]$MySelf = $MyInvocation.InvocationName
Write-Host "###$MySelf###"
[string[]]$Params = $MyInvocation.UnboundArguments
foreach ($Param in $Params) {
Write-Host "Param: '$Param'"
}
并在 output.txt 中找到了這個:
###D:\Temp\StackOverflow\71087897\test.ps1###
Param: '-stringParam'
Param: 'testing'
Param: '-switchParam'
然后在 test.ps1 中嘗試了這個:
[string]$Line = "$($MyInvocation.InvocationName) $($MyInvocation.UnboundArguments)"
Write-Host "$Line"
并在 output.txt 中找到了這個:
D:\Temp\StackOverflow\71087897\test.ps1 -stringParam testing -switchParam
這能讓你到達你需要去的地方嗎?
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/428974.html
上一篇:使用包含丹麥語字符的引數從批處理檔案呼叫Java程式
下一篇:根據文本檔案的輸出設定引數?
