Check for open file and retry operation

44 Views Asked by At

Using powershell, i have this code block

ForEach ($Filepath in $BaselineFile_NME,$DailyOutputFile_NME)
{
 $SHA1 = [Security.Cryptography.HashAlgorithm]::Create( "SHA1" )
 $stream_HSH = ([IO.StreamReader]"$Filepath").BaseStream
 -join ($SHA1.ComputeHash($stream_HSH) |
 ForEach { "{0:x2}" -f $_ })
 $stream_HSH.Close()
 }

I am receiving this error

Exception calling "ComputeHash" with "1" argument(s): "Cannot access a closed file."

on this line $stream_HSH = ([IO.StreamReader]"$Filepath").BaseStream

It appears that the McAfee virus inspector has locking this file.

Is there a way to do a little code block to retry after a minute or two?

2

There are 2 best solutions below

0
Santiago Squarzon On

I don't see the point on using a StreamReader there, use File.Open instead with ReadWrite share permissions. That might work if your AV has a handle on those files. Adding also the retry function where you can define how long you want to wait before retrying.

function retry {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [scriptblock] $scriptblock,

        [Parameter()]
        [scriptblock] $retryHandler,

        [Parameter()]
        [ValidateNotNull()]
        [int] $retryCount = 3
    )


    $ErrorActionPreference = 'Stop'

    do {
        $retryCount--
        try {
            & $scriptblock
            return
        }
        catch {
            if ($retryHandler) {
                & $retryHandler
            }
            $previousError = $_
        }

    }
    while ($retryCount)

    $PSCmdlet.ThrowTerminatingError($previousError)
}

$SHA1 = [Security.Cryptography.HashAlgorithm]::Create('SHA1')

# NOTE: make sure `$BaselineFile_NME` & `$DailyOutputFile_NME` are absolute paths to your files.
foreach ($Filepath in $BaselineFile_NME, $DailyOutputFile_NME) {
    retry {
        try {
            $stream_HSH = [System.IO.File]::Open(
                $Filepath.FullName,
                [System.IO.FileMode]::Open,
                [System.IO.FileAccess]::Read,
                [System.IO.FileShare]::ReadWrite)

            [System.BitConverter]::ToString($SHA1.ComputeHash($stream_HSH))
        }
        finally {
            if ($stream_HSH) {
                $stream_HSH.Dispose()
            }
        }
    } -retryHandler { Start-Sleep -Seconds 60 } -retryCount 10 # <= Tweak these values
}
0
Gregor y On

You may also want to consider using the Get-FileHash commandlet

$Second  = 1000
$Minute  = 60 * $Second
$Hour    = 60 * $Minute

$Retries = 10; $Try = 0

ForEach($Filepath in $BaselineFile_NME,$DailyOutputFile_NME){
   $try = 0
   while($try -lt $Retries){
      try{
         (Get-FileHash -Path $Filepath -Algorithm SHA1 -ErrorAction Stop).Hash
         $try = $Retries
      }catch [Microsoft.PowerShell.Commands.WriteErrorException]{
         $try++
         Start-Sleep -Milliseconds (2 * $Minute)
      }catch {throw}
   }
}