我正在嘗試讀取檔案的內容:
$releaseNotesPath = "$(System.DefaultWorkingDirectory)\_ccp-develop\ccp\ccp\ReleaseNotes\ReleaseNotes\"
$latestReleaseNotesFile = Get-ChildItem -Path $releaseNotesPath -Filter *.txt | Select-Object FullName,Name | Sort-Object -Property Name | Select-Object -First 1
問題出現在這里:
$releaseNote = Get-Content $latestReleaseNotesFile
2021-11-14T14:29:07.0729088Z ##[error]Cannot find drive. A drive with the name '@{FullName=D' does not exist.
2021-11-14T14:29:07.1945879Z ##[error]PowerShell exited with code '1'.
我究竟做錯了什么?
uj5u.com熱心網友回復:
您需要提供檔案路徑 ( FullName):
$releaseNote = Get-Content $latestReleaseNotesFile.FullName
uj5u.com熱心網友回復:
Shayki Abramczyk 已經回答了如何,我將加入為什么部分。
那么,讓我們一步一步地看看發生了什么
# Assign a value to variable, simple enough
$latestReleaseNotesFile =
# Get a list of all
Get-ChildItem -Path $releaseNotesPath -Filter *.txt |
# Interested only on file full name and shortname. Here's the catch
Select-Object FullName,Name |
# Sort the results by name
Sort-Object -Property Name |
# Return the first object of collection.
Select-Object -First 1
請注意,在 catch 部分,您隱式地創建了一個新的自定義 Powershell 物件,該物件包含兩個成員:完全限定的檔案名和短名稱。當您稍后將自定義物件傳遞給 時Get-Content,它不知道如何處理自定義物件。所以,因此錯誤。Shayki 的回答有效,因為它明確告訴使用FullName包含井檔案全名的成員。
uj5u.com熱心網友回復:
現有答案中有很好的資訊;讓我總結并補充它們:
您的命令的簡化和強大的重新制定:
$latestReleaseNotesFile =
Get-ChildItem -LiteralPath $releaseNotesPath -Filter *.txt |
Select-Object -First 1
$releaseNote = $latestReleaseNotesFile | Get-Content
Get-ChildItem-LiteralPath引數確保它的引數按字面(逐字)處理,而不是作為通配符運算式,這是所-Path期望的。Get-ChildItem的輸出已經按名稱排序(雖然這個事實沒有正式記錄,但這是用戶已經開始依賴的行為,它不會改變)。通過不使用
Select-Object FullName, Name轉換System.IO.FileInfo輸出的實體Get-ChildItem來創建[pscustomobject]僅具有指定屬性的實體,結果物件可以作為一個整體通過管道傳輸到Get-Content,在那里它由其.PSPath屬性值隱式系結到-LiteralPath(其別名為-PSPath),其中包含完整路徑(帶有 PowerShell提供程式前綴)。- 有關此基于管道的系結如何作業的詳細資訊,請參閱此答案。
至于你嘗試了什么:
Get-Content $latestReleaseNotesFile
這在位置上將變數的值系結$latestReleaseNotesFile到Get-Content的-Path引數。
由于-Path是[string[]]型別化的(即,它接受一個或多個字串;用于Get-Help Get-Content查看),如有必要,$latestReleaseNotesFile的值通過其方法進行字串化.ToString()。
Select-Object FullName, Name
這將創建[pscustomobject]具有.FullName和.Name屬性的實體,其值取自System.IO.FileInfo輸出的實體Get-ChildItem。
對[pscustomobject]實體進行字串化會產生一種非正式的、類似于哈希表的表示,僅適用于人類觀察者;例如:
# -> '@{FullName=/path/to/foo; Name=foo})'
"$([pscustomobject] @{ FullName = '/path/to/foo'; Name = 'foo' }))"
注意:我使用可擴展字串( "...") 進行字串化,因為由于GitHub 問題 #6163 中描述的長期錯誤,.ToString()直接呼叫會意外地產生空字串。
不出所料,傳遞帶有內容的字串@{FullName=/path/to/foo; Name=foo})不是有效的檔案系統路徑,并導致您看到的錯誤。
.FullName改為傳遞屬性值,如 Shayki 的回答所示,解決了這個問題:
- 為了完全穩健,最好使用
-LiteralPath而不是(位置隱含的)-Path - Specifically, paths that contain verbatim
[or]will otherwise be misinterpreted as a wildcard expression.
Get-Content -LiteralPath $latestReleaseNotesFile.FullName
As shown at the top, sticking with System.IO.FileInfo instances and providing them via the pipeline implicitly binds robustly to -LiteralPath:
# Assumes that $latestReleaseNotesFile is of type [System.IO.FileInfo]
# This is the equivalent of:
# Get-Content -LiteralPath $latestReleaseNotesFile.PSPath
$latestReleaseNotesFile | Get-Content
Pitfall: One would therefore expect that passing the same type of object as an argument results in the same binding, but that is not true:
# !! NOT the same as:
# $latestReleaseNotesFile | Get-Content
# !! Instead, it is the same as:
# Get-Content -Path $latestReleaseNotesFile.ToString()
Get-Content $latestReleaseNotesFile
That is, the argument is not bound by its
.PSPathproperty value to-LiteralPath; instead, the stringified value is bound to-Path.In PowerShell (Core) 7 , this is typically not a problem, because
System.IO.FileInfo(andSystem.IO.DirectoryInfo) instances consistently stringify to their full path (.FullNameproperty value) - however, it still malfunctions for literal paths containing[or].In Windows PowerShell, such instances situationally stringify to the file name (
.Name) only, making malfunctioning and subtle bugs likely - see this answer.
This problematic asymmetry is discussed in GitHub issue #6057.
The following is a summary of the above with concrete guidance:
Robustly passing file-system paths to file-processing cmdlets:
Note: The following applies not just to Get-Content, but to all file-processing standard cmdlets - with the unfortunate exception of Import-Csv in Windows PowerShell, due to a bug.
as an argument:
Use
-LiteralPathexplicitly, because using-Path(which is also implied if neither parameter is named) interprets its argument as a wildcard expression, which notably causes literal file paths containing[or]to be misinterpreted.# $pathString is assumed to be a string ([string]) # OK: -LiteralPath ensures interpretation as a literal path. Get-Content -LiteralPath $pathString # Same as: # Get-Content -Path $pathString # !! Path is treated as a *wildcard expression*. # !! This will often not matter, but breaks with paths with [ or ] Get-Content $pathStringAdditionally, in Windows PowerShell, when passing a
System.IO.FileInfoorSystem.IO.DirectoryInfoinstance, explicitly use the.FullName(file-system-native path) or.PSPathproperty (includes a PowerShell provider prefix; path may be based on a PowerShell-specific drive) to ensure that its full path is used; this is no longer required in PowerShell (Core) 7 , where such instances consistently stringify to their.FullNameproperty - see this answer.# $fileSysInfo is assumed to be of type # [System.IO.FileInfo] or [System.IO.DirectoryInfo]. # Required for robustness in *Windows PowerShell*, works in both editions. Get-Content -LiteralPath $fileSysInfo.FullName # Sufficient in *PowerShell (Core) 7 *: Get-Content -LiteralPath $fileSysInfo
via the pipeline:
System.IO.FileInfoandSystem.IO.DirectoryInfoinstances, such as emitted byGet-ChildItemandGet-Item, can be passed as a whole, and robustly bind to-LiteralPathvia their.PSPathproperty values - in both PowerShell editions, so you can safely use this approach in cross-edition scripts.# Same as: # Get-Content -LiteralPath $fileSysInfo.PSPath $fileSysInfo | Get-ContentThis mechanism - explained in more detail in this answer - relies on a property name matching a parameter name, including the parameter's alias names. Therefore, input objects of any type that have either a
.LiteralPath, a.PSPath, or, in PowerShell (Core) 7 only, a.LPproperty (all alias names of the-LiteralPathparameter) are bound by that property's value.[1]# Same as: # Get-Content -LiteralPath C:\Windows\win.ini [pscustomobject] @{ LiteralPath = 'C:\Windows\win.ini' } | Get-ContentBy contrast, any object with a
.Pathproperty binds to the wildcard-supporting-Pathparameter by that property's value.# Same as: # Get-Content -Path C:\Windows\win.ini # !! Path is treated as a *wildcard expression*. [pscustomobject] @{ Path = 'C:\Windows\win.ini' } | Get-ChildItemDirect string input and the stringified representations of any other objects also bind to
-Path.# Same as: # Get-Content -Path C:\Windows\win.ini # !! Path is treated as a *wildcard expression*. 'C:\Windows\win.ini' | Get-ContentPitfall: Therefore, feeding the lines of a text file via
Get-ContenttoGet-ChildItem, for instance, can also malfunction with paths containing[or]. A simple workaround is to pass them as an argument to-LiteralPath:Get-ChildItem -LiteralPath (Get-Content -LiteralPath Paths.txt)
[1] That this logic is only applied to pipeline input, and not also to input to the same parameter by argument is an unfortunate asymmetry discussed in GitHub issue #6057.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/358644.html
