PowerShell - 关闭文件使用Remove-Item之前

时间:2015-04-16 02:03:29

标签: powershell

我正在编写一个脚本来检查2 .zip文件的内容,比较每个.zip文件的名称(作为日期时间),然后删除最旧的2个文件。一切似乎工作得很好,直到最后我试图用一个简单的'Remove-Item'删除最旧的文件(我已经尝试了-Force选项没有改进)。我所做的每一次尝试都会导致此错误:

  

删除项目:无法删除项目C:\ Scripts \ Test2.zip:该过程   因为正在使用它,所以无法访问文件'C:\ Scripts \ Test2.zip'   通过另一个过程。在行:44 char:5   + Remove-Item $ newLocation -Force   + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~       + CategoryInfo:WriteError:(C:\ Scripts \ Test2.zip:FileInfo)[Remove-Item],IOException       + FullyQualifiedErrorId:RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand

这是我提出的剧本(温柔,它可能不是地球上最顺畅的东西):

$scriptLocation = "C:\Scripts\"
$oldLocation = "C:\Scripts\Test1.zip"
$newLocation = "C:\Scripts\Test2.zip"

cd $scriptLocation

$fileOld = .\GetZipContents.ps1 -FileName $oldLocation | Where {$_.FileExtn -eq ".txt"}
$fileNew = .\GetZipContents.ps1 -FileName $newLocation | Where {$_.FileExtn -eq ".txt"}

function Convert-DateString ([String]$Date, [String[]]$Format)
{
   $result = New-Object DateTime

   $convertible = [DateTime]::TryParseExact(
      $Date,
      $Format,
      [System.Globalization.CultureInfo]::InvariantCulture,
      [System.Globalization.DateTimeStyles]::None,
      [ref]$result)

   if ($convertible) { $result }
}

$oldName = $fileOld.FileName
$oldDate = $oldName.Substring(0,$oldName.Length-4)

$newName = $fileNew.FileName
$newDate = $newName.Substring(0,$newName.Length-4)


$convOldDate = Convert-DateString -Date $oldDate -Format 'MMMM_dd_yyyy'
$convNewDate = Convert-DateString -Date $newDate -Format 'MMMM_dd_yyyy'
$compare = $convOldDate -ge $convNewDate

If($compare -eq $True)
#OLD
{
    Remove-Item $oldLocation -Force
    "OLD FILE IS OLD - REMOVING: ({0})" -f ($oldLocation) 
}
Else
#NEW
{
    Remove-Item $newLocation -Force
    "NEW FILE IS NEW - REMOVING: ({0})" -f ($newLocation)
} 

这是在$ fileOld和$ fileNew中调用的GetZipContents.ps1:

[cmdletbinding()]            
param(            
 [Parameter(Mandatory=$true)]            
 [string[]]$FileName,            
 [String]$ExportCSVFileName            
)            
#Exit if the shell is using lower version of dotnet            

$dotnetversion = [Environment]::Version            
if(!($dotnetversion.Major -ge 4 -and $dotnetversion.Build -ge 30319)) {            
 write-error "You do not have Microsoft .Net Framework 4.5 installed. Script exiting..."            
 exit(1)            
}            

# Import dotnet libraries            

[Void][Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem')            
$ObjArray = @()            
foreach($zipfile in $FileName) {            
if(Test-Path $ZipFile) {            
 $RawFiles = [IO.Compression.ZipFile]::OpenRead($zipFile).Entries            
 foreach($RawFile in $RawFiles) {            

  $object = New-Object -TypeName PSObject            
  $Object | Add-Member -MemberType NoteProperty -Name FileName -Value $RawFile.Name            
  $Object | Add-Member -MemberType NoteProperty -Name FullPath -Value $RawFile.FullName            
  $Object | Add-Member -MemberType NoteProperty -Name CompressedLengthInKB -Value ($RawFile.CompressedLength/1KB).Tostring("00")            
  $Object | Add-Member -MemberType NoteProperty -Name UnCompressedLengthInKB -Value ($RawFile.Length/1KB).Tostring("00")            
  $Object | Add-Member -MemberType NoteProperty -Name FileExtn -Value ([System.IO.Path]::GetExtension($RawFile.FullName))            
  $Object | Add-Member -MemberType NoteProperty -Name ZipFileName -Value $zipfile            
  $ObjArray += $Object            
  if(!$ExportCSVFileName) {            
   $Object            
  }            
 }            
} else {            
 Write-Warning "$ZipFileInput File path not found"            
}            
if ($ExportCSVFileName){            
 try {            
  $ObjArray  | Export-CSV -Path $ExportCSVFileName -NotypeInformation            
 } catch {            
  Write-Error "Failed to export the output to CSV. Details : $_"            
 }            
}            

}

我从这里得到的是:http://techibee.com/powershell/reading-zip-file-contents-without-extraction-using-powershell/2152

我已经运行Handle.exe来查找打开这些文件的进程,并且它显示PowerShell ISE本身就是问题所在。

任何帮助将不胜感激。我试图搜索类似的问题,但只发现其他进程保持打开文件的问题,然后您可以使用Handle.exe终止。如果PowerShell ISE需要放手,我不知道如何做到这一点......

2 个答案:

答案 0 :(得分:2)

当然,问题是你调用了[IO.Compression.ZipFile]::OpenRead()但是你永远不会关闭文件。您应该在If脚本块中执行的最后一件事是关闭您开始的OpenRead。您正在使用的对象是System.IO.Compression.ZipArchive,您可以在以下网址阅读:

https://msdn.microsoft.com/en-us/library/system.io.compression.ziparchive(v=vs.110).aspx

您需要做的是释放您使用$ Rawfiles打开的​​文件实例的资源。为此,您可以调用Dispose()方法。在我Else陈述之前,我建议这样做。因此,将GetZipContents.ps1脚本更新为如下所示:

[cmdletbinding()]            
param(            
 [Parameter(Mandatory=$true)]            
 [string[]]$FileName,            
 [String]$ExportCSVFileName            
)            
#Exit if the shell is using lower version of dotnet            

$dotnetversion = [Environment]::Version            
if(!($dotnetversion.Major -ge 4 -and $dotnetversion.Build -ge 30319)) { 
 write-error "You do not have Microsoft .Net Framework 4.5 installed. Script exiting..."            
 exit(1)            
}            

# Import dotnet libraries            

[Void][Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem')            
$ObjArray = @()            
foreach($zipfile in $FileName) {            
if(Test-Path $ZipFile) {            
 $RawFiles = [IO.Compression.ZipFile]::OpenRead($zipFile).Entries            
 foreach($RawFile in $RawFiles) {            

  $object = New-Object -TypeName PSObject            
  $Object | Add-Member -MemberType NoteProperty -Name FileName -Value $RawFile.Name            
  $Object | Add-Member -MemberType NoteProperty -Name FullPath -Value $RawFile.FullName            
  $Object | Add-Member -MemberType NoteProperty -Name CompressedLengthInKB -Value ($RawFile.CompressedLength/1KB).Tostring("00")            
  $Object | Add-Member -MemberType NoteProperty -Name UnCompressedLengthInKB -Value ($RawFile.Length/1KB).Tostring("00")            
  $Object | Add-Member -MemberType NoteProperty -Name FileExtn -Value ([System.IO.Path]::GetExtension($RawFile.FullName))            
  $Object | Add-Member -MemberType NoteProperty -Name ZipFileName -Value $zipfile            
  $ObjArray += $Object            
  if(!$ExportCSVFileName) {            
   $Object            
  }            
 }
 $RawFiles.Dispose()            
} else {            
 Write-Warning "$ZipFileInput File path not found"            
}            
if ($ExportCSVFileName){            
 try {            
  $ObjArray  | Export-CSV -Path $ExportCSVFileName -NotypeInformation            
 } catch {            
  Write-Error "Failed to export the output to CSV. Details : $_"            
 }            
}            

}

答案 1 :(得分:2)

问题是GetZipContents.ps1在完成文件后没有关闭文件。 ZipFile::OpenRead返回一个ZipArchive类(documented here),它实现IDisposable。这表明ZipFile存档需要处理。

试试这个(注意对Dispose的调用:)

if(Test-Path $ZipFile) {
 $ZipArchive = [IO.Compression.ZipFile]::OpenRead($zipFile)
 $RawFiles = $ZipArchive.Entries
 foreach($RawFile in $RawFiles) { 
   $Object = New-Object -TypeName PSObject
   $Object | Add-Member -MemberType NoteProperty -Name FileName -Value $RawFile.Name

   # etc. etc.

 }
 $RawFiles.Dispose()         
} else {            
  Write-Warning "$ZipFileInput File path not found"            
} 

阅读IDisposable将会解释更多内容。