删除带有特殊字符的文件

Ste*_*eve 4 powershell file-io filenames special-characters

我想从构建服务器中清除日志文件,保留最近几天。我的进程创建的日志文件没有问题。这工作正常:

$logFolders = Get-ChildItem $buildBase -Recurse -include logs -Attributes D
$logFolders | ForEach-Object { Get-ChildItem $_.fullname -filter *.log | where >{$_.lastwritetime -lt (get-date).adddays(-$purgeAfter) -and -not $_.psiscontainer} |% {remove-item $_.fullname -force} };
Run Code Online (Sandbox Code Playgroud)

但是,构建工具生成的日志如下所示:

lrFR_WebHelp - Friday, February 28, 2014 [9.00 PM].mclog
Run Code Online (Sandbox Code Playgroud)

我试过引用文件名:

Get-ChildItem $frReports\Reports -filter *.mclog | where {$_.lastwritetime -lt (get-date).adddays(-$purgeAfter) -and -not $_.psiscontainer}| % {write-host ("'" + $frReports + '\Reports'  + '\' + $_ + "'") }
Run Code Online (Sandbox Code Playgroud)

输出:

'D:\scratch\Reports\lrFR_WebHelp - Friday, February 28, 2014 [9.00 PM].mclog'
Run Code Online (Sandbox Code Playgroud)

但试图删除:

Get-ChildItem $frReports\Reports -filter *.mclog | where {$_.lastwritetime -lt (get-date).adddays(-$purgeAfter) -and -not $_.psiscontainer}| % {remove-item ("'" + $frReports + '\Reports'  + '\' + $_ + "'") }
Run Code Online (Sandbox Code Playgroud)

输出:

remove-item : Cannot find drive. A drive with the name ''D' does not exist.
At line:1 char:145
+ ... container}| % {remove-item ("'" + $frReports + '\Reports'  + '\' + $_ + "'") }
+                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: ('D:String) [Remove-Item], DriveNotFoundException
    + FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand
Run Code Online (Sandbox Code Playgroud)

更改为 unix 斜杠 ('/') 或转义斜杠 ('\\') 不会改变结果

我试着绕过这条路。没有错误,但也没有删除任何文件。

这个:

    $filesToDelete = Get-ChildItem $frReports\Reports -filter *.mclog | where {$_.lastwritetime -lt (get-date).adddays(-$purgeAfter) -and -not $_.psiscontainer}

    Push-Location -path D:\scratch\Reports

    $filesToDelete | ForEach-Object { 
        $fname = ("'" +  $_ + "'");
        write-host $fname;
        remove-item $fname -Force;
        remove-item $_;
}
Run Code Online (Sandbox Code Playgroud)

输出这个:

'lrFR_WebHelp - Friday, February 28, 2014 [9.00 PM].mclog'
'lrFR_WebHelp - Friday, March 14, 2014 [10.24 PM].mclog'
Run Code Online (Sandbox Code Playgroud)

但不会删除文件。

最后,在网上窥探线索后,我尝试了 fso 对象

   $fso = New-Object -ComObject Scripting.FileSystemObject
    $buildBase = "D:\scratch";
    $logFolders = Get-ChildItem $buildBase -Recurse -include Reports -Attributes D


    $logFolders | ForEach-Object { Get-ChildItem $fso.GetFile($_.FullName).ShortPath -filter *.MCL | where {$_.lastwritetime -lt (get-date).adddays(-$purgeAfter) -and -not $_.psiscontainer}} #|% {write-host $_.fullname}  };
Run Code Online (Sandbox Code Playgroud)

输出:

Exception calling "GetFile" with "1" argument(s): "Exception from HRESULT: 0x800A0035 (CTL_E_FILENOTFOUND)"
At line:1 char:32
+ $logFolders | ForEach-Object { Get-ChildItem $fso.GetFile($_.FullName).ShortPath ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ComMethodTargetInvocation
Run Code Online (Sandbox Code Playgroud)

没有任何运气在 PowerShell 中获得有关 $fso.GetFile 的更多信息。谷歌这次让我失望了。

任何人都可以帮忙吗?我更喜欢纯粹的 PowerShell 解决方案,但会感谢任何有效的解决方案。

Ans*_*ers 5

您的问题是由文件名中的方括号引起的。当您将带有路径的字符串传递到 的(隐式)-Path参数时Remove-Item,方括号将被解释为通配符[9.00 PM]因此,子字符串将匹配单个字符,即MP90、 点或空格。您可以使用-LiteralPath而不是-Path通过更改以下内容来避免这种行为:

... | % { Remove-Item $_.FullName -Force }
Run Code Online (Sandbox Code Playgroud)

进入这个:

... | % { Remove-Item -LiteralPath $_.FullName -Force }
Run Code Online (Sandbox Code Playgroud)

但是,Remove-Item接受管道输入,因此您可以完全删除循环并直接从管道读取项目:

... | Remove-Item -Force
Run Code Online (Sandbox Code Playgroud)

这种方式Remove-Item从整个FileInfo对象中获取Get-ChildItem并自动执行 The Right Thing™。

附带说明:您可以通过删除循环来进一步简化代码,因为不仅Remove-Item从管道中读取,而且Get-ChildItem还从管道中读取。像这样的事情应该可以正常工作:

$limit = (Get-Date).AddDays(-$purgeAfter)

Get-ChildItem $buildBase -Recurse -Include logs -Attributes D |
  Get-ChildItem -Filter *.mclog |
  Where-Object { $_.LastWriteTime -lt $limit -and -not $_.PSIsContainer } |
  Remove-Item -Force
Run Code Online (Sandbox Code Playgroud)