我正在創建一個 dos 批處理腳本 (cmd.exe) .cmd,它通過 powershell 將自己提升為管理員。
但是,如果它存盤在名稱中同時包含空格和與符號的檔案夾中,則它將不起作用。
我不是專家,所以我在網上搜索,但我找不到解決問題的解決方案或檔案。因此,我還想知道如何除錯這種特定情況以及問題的可能解決方案,以及在哪里可以找到描述解決方案或到達那里的步驟的檔案......(如果有的話)。
重現問題:我在桌面下創建了一個名為“Pie & tea”的檔案夾,沒有引號。在檔案夾中,我創建了一個腳本“test.cmd”,我只在其中放置了重現問題的必要內容。這是腳本的內容:
@echo off
pause
PowerShell start "%~f0" -verb runas
pause
goto: eof
我通過雙擊運行腳本(這是所需的模式)。此代碼顯示錯誤(我使用翻譯器從意大利語翻譯):
Press any key to continue. . .
In row: 1 car: 34
start C:\Users\fposc\Desktop\Pie & tea\test.cmd -verb runas
~
Ampersand (&) not allowed. The & operator is reserved for future use. Use "&" to pass the ampersand as
string.
CategoryInfo: ParserError: (:) [], ParentContainsErrorRecordException
FullyQualifiedErrorId: AmpersandNotAllowed
Press any key to continue. . .
按照一些說明,我通過將雙引號增加三倍,使用 powershell 修改了代碼行:
PowerShell start """%~f0""" -verb runas
但是 cmd 視窗打開,按下空格后,UAC 啟動,在同意后出現另一個視窗,但它立即關閉,我看不到任何錯誤。
我在網上看到任何使用單引號'或 powershell 轉義字符`或^dos 批處理的脫字符或--%powershell 引數等的解決方案。但我無法解決。我沒有把所做的嘗試放在這里,因為我以一種愚蠢的方式進行了復制(因為我不熟悉混合 cmd / powershell 操作)并且我結合各種解決方案進行了多次隨機嘗試。沒有任何積極的結果。
我還看到了我想評估的解決方案,例如:
- 更改目錄并使用相對路徑。
- 準備字串變數并替換字符。
- 使用 powershell -encodedcommand 傳遞引數。
But the preferred solution is the one that explains how to escape characters on the single line of code
PowerShell start "%~f0" -verb runasand how to get there and the reference documentation.
Some links visited:
VBS Shell.Application and PowerShell Start-Process do not escape ampersands internally
Quoting issues with PowerShell
Issues on windows when the username contains &
Executing PowerShell script via explorer context menu on items containing ampersands in their names
Stackoverflow: batch file deal with Ampersand (&) in folder name
Stackoverflow: How to access file paths in PowerShell containing special characters
Stackoverflow: How to pass strings to powershell from cmd with ampersands in values?
uj5u.com熱心網友回復:
除錯提示:
如果PowerShell端出現問題,您將在呼叫
cmd.exe會話中看到錯誤訊息;要列印 PowerShell 本身看到的命令列,請添加[Environment]::CommandLine;到正在傳遞的命令之前。[1]要使 PowerShell 的
Start-Processcmdlet(其內置別名是start)在保持會話打開的cmd.exe行程中啟動批處理檔案,使用顯式呼叫,并將批處理檔案路徑傳遞給它。一旦您確定一切都按預期作業,請替換為(以創建在批處理檔案終止時終止的會話)。cmd.execmd /k/k/c
您的情況的主要問題:
令人遺憾的是,如果一個批處理檔案路徑包含
&的字符,中的錯誤cmd.exe,需要手動^-escaping的&以及空間,以及可能的其它cmd.exe元字符,即使路徑被封閉在"..."作為一個整體; 此外,似乎必須在呼叫時使用完整的批處理檔案路徑(%~f0確保):例如,呼叫
C:\foo\a & b.cmd,cmd /k "C:\foo\a & b.cmd"是不是不夠-你必須使用cmd /k "C:\foo\a^ ^&^ b.cmd"下面的命令使用一個
-replace操作^在 PowerShell 代碼中對 的值執行此轉義%~f0,該操作cmd.exe將擴展為批處理檔案的完整路徑。
以下解決方案:
- 使用輔助。環境變數使其在大多數情況下都能作業,即使路徑包含其他奇異字符,例如
$,%和'。 - 還包括支持在呼叫時傳遞引數。
有關解決方案的演變,請參閱底部部分,其中包括詳細說明。
@echo off
:: Save the full path of this batch file in an aux. environment variable.
set "__THISFILE=%~f0"
:: Save the arguments received in an aux. environment variable.
:: Note: The space after "=" is required for the PowerShell command
:: to also work if *no* arguments were passed.
set __ARGS= %*
:: Unless already elevated, relaunch this batch file,
:: with arguments passed through.
:: Note: Replace `exit /b` with just `exit` to
:: close the current console window after relaunching.
net session >NUL 2>NUL || (powershell.exe -noprofile -c "Start-Process -Verb RunAs cmd /k, ($env:__THISFILE -replace '[ &%%^]', '^$&'), $env:__ARGS" & exit /b)
:: Reset the aux. variables.
set __ARGS=
set __THISFILE=
echo Now running with elevation. Arguments received:
echo. %*
上述解決方案的演變:
如果您的批處理檔案路徑不包含'字符:
嵌入'...'參考在下面的PowerShell命令所使用的,以避免不得不逃脫嵌入"引號,這可能很麻煩; 這假設批處理檔案路徑本身不包含'字符(如果您的路徑確實包含'字符,請參見下文。)
@echo off
:: Unless already elevated, relaunch this batch file with elevation.
net session >NUL 2>NUL || (powershell.exe -c "Start-Process -Verb RunAs cmd /k, ('%~f0' -replace '[ &]', '^$&')" & goto :eof)
echo Now running with elevation.
筆記:
net session >NUL 2>NULis a simple trick to test if the current process is elevated (being run as admin) or not: it only succeeds in elevated sessions (reflected in exit code0, which the||and&&operators implicitly act on).-c(-Command) makes it explicit that command(s) are being passed topowershell.exe; while not strictly necessary, it is a good habit to form, given thatpwsh.exe, the PowerShell (Core) 7 CLI, now requires it (see the linked CLI documentation below)./k, ...creates an array of arguments, which are positionally passed to the-ArgumentListparameter ofStart-Process- in essence,Start-Processbuilds a command line from the executable name,cmd, and all arguments by string concatenation with spaces behind the scenes - see this answer to your follow-up question for details.
If your batch-file paths contain ' chars., embedded "..." quoting must be used:
With
powershell.exe, the Windows PowerShell CLI, the most robust approach - which is indeed required here - is to use"^""(sic) to escape each embedded", as shown below.(By contrast,
pwsh.exe, the PowerShell (Core) 7 CLI now fortunately accepts"".)
net session >NUL 2>NUL || (powershell.exe -nop -c "Start-Process -Verb RunAs cmd /k, ("^""%~f0"^"" -replace '[ &]', '^$&')" & goto :eof)
If your batch-file paths contain $ chars. and ' chars., an aux. environment variable must be used:
$ chars. alone wouldn't be a problem if you used embedded '...' quoting, but if ' are also present, embedded "..." quoting isn't an option, because PowerShell would treat the $ chars. as the start of a variable reference.
See the solution at the top.
If you additionally want to support passing arguments to the batch file:
Note: The solution at the top now incorporates this approach, while also handling a wider array of exotic batch-file paths.
To prevent further quoting headaches, an aux. environment variable, __ARGS is used in the code below to store all arguments that the batch file received (%*), which the PowerShell code can then access via $env:__ARGS on re-invocation.
@echo off
:: Save the arguments received in an aux. environment variable.
:: Note: The space after "=" is required for the PowerShell command
:: to also work if *no* arguments were passed.
set __ARGS= %*
:: Unless already elevated, relaunch this batch file,
:: with arguments passed through.
net session >NUL 2>NUL || (powershell.exe -nop -c "Start-Process -Verb RunAs cmd /k, ("^""%~f0"^"" -replace '[ &]', '^$&'), $env:__ARGS" & goto :eof)
:: Reset the aux. variable.
set __ARGS=
echo Now running with elevation. Arguments received:
echo. %*
[1] A simple example (call from cmd.exe): powershell -c "[Environment]::CommandLine; '%OS%'"
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/312635.html
標籤:windows powershell batch-file cmd
