diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHash.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHash.cs
index c851c2bc81..65e55a86ab 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHash.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHash.cs
@@ -126,49 +126,10 @@ namespace Microsoft.PowerShell.Commands
foreach (string path in pathsToProcess)
{
- byte[] bytehash = null;
- string hash = null;
- Stream openfilestream = null;
-
- try
+ if (ComputeFileHash(path, out string hash))
{
- openfilestream = File.OpenRead(path);
- bytehash = hasher.ComputeHash(openfilestream);
-
- hash = BitConverter.ToString(bytehash).Replace("-", string.Empty);
WriteHashResult(Algorithm, hash, path);
}
- catch (FileNotFoundException ex)
- {
- var errorRecord = new ErrorRecord(
- ex,
- "FileNotFound",
- ErrorCategory.ObjectNotFound,
- path);
- WriteError(errorRecord);
- }
- catch (UnauthorizedAccessException ex)
- {
- var errorRecord = new ErrorRecord(
- ex,
- "UnauthorizedAccessError",
- ErrorCategory.InvalidData,
- path);
- WriteError(errorRecord);
- }
- catch (IOException ioException)
- {
- var errorRecord = new ErrorRecord(
- ioException,
- "FileReadError",
- ErrorCategory.ReadError,
- path);
- WriteError(errorRecord);
- }
- finally
- {
- openfilestream?.Dispose();
- }
}
}
@@ -190,6 +151,61 @@ namespace Microsoft.PowerShell.Commands
}
}
+ ///
+ /// Read the file and calculate the hash.
+ ///
+ /// Path to file which will be hashed.
+ /// Will contain the hash of the file content.
+ /// Boolean value indicating whether the hash calculation succeeded or failed.
+ private bool ComputeFileHash(string path, out string hash)
+ {
+ byte[] bytehash = null;
+ Stream openfilestream = null;
+
+ hash = null;
+
+ try
+ {
+ openfilestream = File.OpenRead(path);
+
+ bytehash = hasher.ComputeHash(openfilestream);
+ hash = BitConverter.ToString(bytehash).Replace("-", string.Empty);
+ }
+ catch (FileNotFoundException ex)
+ {
+ var errorRecord = new ErrorRecord(
+ ex,
+ "FileNotFound",
+ ErrorCategory.ObjectNotFound,
+ path);
+ WriteError(errorRecord);
+ }
+ catch (UnauthorizedAccessException ex)
+ {
+ var errorRecord = new ErrorRecord(
+ ex,
+ "UnauthorizedAccessError",
+ ErrorCategory.InvalidData,
+ path);
+ WriteError(errorRecord);
+ }
+ catch (IOException ioException)
+ {
+ var errorRecord = new ErrorRecord(
+ ioException,
+ "FileReadError",
+ ErrorCategory.ReadError,
+ path);
+ WriteError(errorRecord);
+ }
+ finally
+ {
+ openfilestream?.Dispose();
+ }
+
+ return hash != null;
+ }
+
///
/// Create FileHashInfo object and output it.
///
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-FileHash.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-FileHash.Tests.ps1
index eac9bd9c90..6cb3118fec 100644
--- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-FileHash.Tests.ps1
+++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-FileHash.Tests.ps1
@@ -77,4 +77,19 @@ Describe "Get-FileHash" -Tags "CI" {
$result.Path | Should -Be $testDocument
}
}
+
+ Context "File should be closed before Get-FileHash writes pipeline output" {
+ It "Should be able to edit the file without 'file is in use' exceptions" {
+ # This test runs against a copy of the document
+ # because it involves renaming it,
+ # and that might break tests added later on.
+ $testDocumentCopy = "${testDocument}-copy"
+ Copy-Item -Path $testdocument -Destination $testDocumentCopy
+
+ $newPath = Get-FileHash -Path $testDocumentCopy | Rename-Item -NewName {$_.Hash} -PassThru
+ $newPath.FullName | Should -Exist
+
+ Remove-Item -Path $testDocumentCopy -Force
+ }
+ }
}