我写了一个脚本,这样我就可以从播客播放器访问我新录制的媒体。脚本按预期从命令行运行,但从任务计划程序运行时,它无法从子文件夹获取完整路径。使用此错误路径的每次foreach传递都有多个错误。下面是一个这样错误
get-item : Cannot find path 'D:\Radio\202303100400.mp4' because it does not exist.
At C:\Users\jj9wo\mpxtorss.ps1:38 char:23
+ foreach ($folder in ((get-item $media).DirectoryName) | Select-Object ...
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (D:\Radio\202303100400.mp4:String) [Get-Item], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand
文件的正确路径是D:\Radio\kmox\202303100400.mp4
这里是完整的脚本。有一对夫妇的事情,仍然需要工作,但它是完全运作,除了问题,我说。我知道我的脚本喜欢一行程序,缺乏足够的注解。我希望我的评论仅限于我的具体问题
$path= 'D:\Radio'
$site='mysite.com'
Set-Location -Path $path
if ($path -and $(Try{Test-Path $path.trim()} Catch{}) -and (((get-item $path).Attributes) -match "Directory")){
$path = Get-Item $path
} else {Write-Host "mp2rss error: Invalid" ;exit}
$media = (Get-ChildItem -path $path -File -Recurse -Filter "*.mp*") | Where-Object `
{$_.extension -in ".mp3",".mp4"} | Sort-Object -Descending -Property LastWriteTime
if (!$media.Count){Write-Host "mp2rss error: No Media Found" ;exit}
# done verifying
function when_long($param){
$param = ($param.AddMinutes(-($param.minute %5)).ToString("h:mmtt ddd, MMM d'th'") -replace
'(?<!1)1th$','1st' -replace'(?<!1)2th$','2nd' -replace '(?<!1)3th$','3rd') -replace
'(?<=:\d\d)AM','a' -replace '(?<=:\d\d)PM','p'
return $param
}
function when_short($param){
$param = ($param.ToString("ddd"),($param.AddMinutes(-($param.minute %5))).ToString("M/dd h:mmt").ToLower() -join " ")
return $param
}
if ((Get-Volume -DriveLetter $path.ToString().Substring(0,1)).FileSystemLabel){
$title_alt = (Get-Volume -DriveLetter $path.ToString().Substring(0,1)).FileSystemLabel
}else{$title_alt = "$env:COMPUTERNAME`($($path.FullName.Substring(0,1))`)"}
if ($path.FullName -eq $path.Root.FullName){
$title = $title_alt
$htm_out = "$($path)mpx.htm"
}else{
$title = $path.BaseName
$htm_out = "$path\mpx.htm"
}
$html = @("<html><head><title>$title</title></head><body>")
foreach ($folder in ((get-item $media).DirectoryName) | Select-Object -Unique){
$ext = @('mp3','mp4')
foreach ($ext in $ext){
if ($media | Where-Object {$_.DirectoryName -in $folder -and $_.Extension -match $ext}){
if ((Get-Item $folder).FullName -ne (Get-Item $folder).Root.FullName){
$title = (Get-Item $folder).BaseName
}else{$title = $title_alt}
if ($ext -match 'mp4'){$title = "$title [V]"}
$url = (([System.Uri]$folder).AbsoluteUri.TrimStart(([System.Uri]($path.ToString())).AbsoluteUri))
if ($url){$url = "$site/$url/"}else{$url = "$site/"}
$qty = (($media | Where-Object {$_.DirectoryName -in $folder -and $_.Extension -match $ext}) | Measure-Object).Count
$whn = (when_long ($media | Where-Object {$_.DirectoryName -in $folder -and $_.Extension -match $ext} | Select-Object -First 1).CreationTime)
$html += "<p><a href=`"http://$url$ext.rss`">$title</a><br>$qty files updated $whn</p>"
$rss = @("<rss><channel><title>$title</title>")
$rss += "<description>$qty files updated $whn</description>"
foreach ($file in ($media | Where-Object {$_.DirectoryName -in $folder -and $_.Extension -match $ext})){
if ($file.BaseName -match "^\d+$"){
if ($file.BaseName -match "^\d{12}$"){
$title = (when_short ([Datetime]::ParseExact($file.BaseName, 'yyyyMMddHHmm', $null)))
$dsc = (when_long ([Datetime]::ParseExact($file.BaseName, 'yyyyMMddHHmm', $null)))
}else{
$title = (when_short $file.CreationTime)
$dsc = (when_long $file.CreationTime)
}
}else{
$title = $file.BaseName
$dsc = (when_long $file.CreationTime)
}
$rss += "<item><title>$title</title>"
$rss += "<description>$dsc</description>"
$rss += "<enclosure url=`"http://$url$([uri]::EscapeDataString($file.Name))`"/></item>"
}
$rss += "</channel></rss>"
$rss_out = "$folder\$ext.rss"
if (-not (Test-Path $rss_out) -or (Compare-Object (Get-Content -Path $rss_out) $rss)){Out-File -InputObject $rss -FilePath $rss_out}
}
}
}
if (-not (Test-Path $htm_out) -or (Compare-Object (Get-Content -Path $htm_out) $html)){Out-File -InputObject $html -FilePath $htm_out}
1条答案
按热度按时间hc2pp10m1#
tl;dr
**没有 * 需要使用
Get-Item
的参数已经 * 是 *[System.IO.FileInfo]
(或[System.IO.DirectoryInfo]
)示例,例如Get-ChildItem
的输出。(Get-Item $media).DirectoryName
替换为$media.DirectoryName
在为 Windows PowerShell 编写的代码和 * 跨版本 * 代码中,需要额外的努力才能将
FileInfo
/DirectoryInfo
* 用作字符串:针对接受文件路径的 * cmdlet,通过pipeline*传递
FileInfo
示例 ,该pipeline**会将FileInfo
/DirectoryInfo
示例的 * 完整路径 * 稳健绑定到目标cmdlet的-LiteralPath
参数上-背景信息请参见this answer;例如:针对 * 外部程序/其他需要字符串 * 表示
FileInfo
示例的 * 全路径 * 的上下文,显式使用其.FullName
属性**;例如:请继续阅读以获得解释。
正如Mathias R. Jessen所指出的,将
Get-Item
与$media
一起使用是“不必要的”,因为$media
已经包含了[System.IO.FileInfo]
示例,因为它包含了早期Get-ChildItem
-File
调用的输出。将
(Get-Item $media).DirectoryName
替换为$media.DirectoryName
不仅更简单、更高效,而且实际上 * 隐含地解决了您的问题 。也就是说,
Get-Item $media
在Windows PowerShell 中 * 无法 * 按预期 * 工作:FileInfo
示例被 * 字符串化 *。(此部分也适用于PowerShell (Core) 7+)。FileInfo
示例作为 arguments 传递时,它们被转换为 strings,因为它们绑定到(位置上)隐含的-Path
参数,该参数是[string[]
类型的。-LiteralPath
参数(当通过管道提供FileInfo
/DirectoryInfo
instances _时,该参数是 * 隐式 * 绑定的)。这对于包含
[
和]
字符的路径很重要,因为它们在PowerShell的通配符语言中是 * 元字符 *(用于定义字符范围和集合)。.Name
),而不是其 full path(.FullName
)用于获取字符串表示。.FullName
。.Name
或.FullName
字符串化取决于 *Get-ChildItem
调用的细节 *(请参阅链接的答案),在您的情况下,只发生.Name
字符串化。-Recurse
,Get-Item
将无法找到在$path
的 * 子目录 * 中找到的任何FileInfo
示例,因为由于.Name
字符串化而丢失了路径信息。D:\Radio
是您的 * 当前 * 位置,由于Set-Location $path
调用。Get-ChildItem
调用然后查找文件D:\Radio\kmox\202303100400.mp4
,并将其FileInfo
表示作为数组的一部分存储在$media
中Get-Item $media
调用中,该文件然后被字符串化为202303100400.mp4
only(由.Name
),在没有 path 信息的情况下,Get-Item
试图根据 current 位置(目录)进行解析。Get-Item
查找D:\Radio\202303100400.mp4
(缺少kmox
路径组件)-它不存在,并导致您看到的错误。