From 776344518bb8372c95a6d3794f7e28cbfd0318dd Mon Sep 17 00:00:00 2001 From: Raimund Andree Date: Mon, 5 Oct 2026 01:34:36 +0200 Subject: [PATCH] fix: say that a missing New-NTFSHardLink target does not exist Defect 21. For a -Target that didn't exist, New-NTFSHardLink failed with "The target path exist, cannot create the link", the opposite of the cause. The message now names the target and says that it does not exist. Tests/Links.Tests.ps1 (new): 2 tests, one of them for a link that is created. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant --- CHANGELOG.md | 2 + Docs/Cmdlets/New-NTFSHardLink.md | 2 + NTFSSecurity/LinkCmdlets/NewHardLink.cs | 2 +- NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml | 1 + Tests/Links.Tests.ps1 | 44 ++++++++++++++++++++ 5 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 Tests/Links.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 75c19be..bac6de6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -124,5 +124,7 @@ The format is based on the unchanged state of an item also when the change failed, so that the inheritance looked disabled ([#74](https://github.com/raandree/NTFSSecurity/issues/74)) +- Fix the error of `New-NTFSHardLink` for a missing `-Target`, which said + that the target path existed [Unreleased]: https://github.com/raandree/NTFSSecurity/compare/4.2.6...HEAD diff --git a/Docs/Cmdlets/New-NTFSHardLink.md b/Docs/Cmdlets/New-NTFSHardLink.md index 16c4fdd..184f5a7 100644 --- a/Docs/Cmdlets/New-NTFSHardLink.md +++ b/Docs/Cmdlets/New-NTFSHardLink.md @@ -138,6 +138,8 @@ The cmdlet does not overwrite anything. If `-Path` already exists, or if `-Targe Because all names of a file share the same data, the number of hard links is a property of the file, not of an individual name. Use `Get-NTFSHardLink` to list them, and delete a link with `Remove-Item2` or `Remove-Item`, which removes only that name as long as other names remain. +Before 5.0.0, the error for a missing `-Target` said "The target path exist", the opposite of the cause. + ## RELATED LINKS [Get-NTFSHardLink](Get-NTFSHardLink.md) diff --git a/NTFSSecurity/LinkCmdlets/NewHardLink.cs b/NTFSSecurity/LinkCmdlets/NewHardLink.cs index 7f9f47d..cec9d5b 100644 --- a/NTFSSecurity/LinkCmdlets/NewHardLink.cs +++ b/NTFSSecurity/LinkCmdlets/NewHardLink.cs @@ -63,7 +63,7 @@ namespace NTFSSecurity throw new ArgumentException(string.Format("The file '{0}' does already exist, cannot create the link", path)); if (!TryGetFileSystemInfo2(target, out temp)) - throw new ArgumentException("The target path exist, cannot create the link"); + throw new ArgumentException(string.Format("The target '{0}' does not exist, cannot create the link", target)); else if (temp is DirectoryInfo) throw new ArgumentException("The target is not a file, cannot create the link"); diff --git a/NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml b/NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml index a5b974e..aa824f6 100644 --- a/NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml +++ b/NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml @@ -7135,6 +7135,7 @@ PS C:\Data> Get-NTFSSecurityDescriptor Windows supports hard links only for files on the same NTFS volume. A link that points to a file on another volume, or a target on a file system that does not implement hard links, cannot be created. The cmdlet does not overwrite anything. If `-Path` already exists, or if `-Target` is missing or is a folder, the cmdlet reports an error and leaves the file system unchanged. Because all names of a file share the same data, the number of hard links is a property of the file, not of an individual name. Use `Get-NTFSHardLink` to list them, and delete a link with `Remove-Item2` or `Remove-Item`, which removes only that name as long as other names remain. + Before 5.0.0, the error for a missing `-Target` said "The target path exist", the opposite of the cause. diff --git a/Tests/Links.Tests.ps1 b/Tests/Links.Tests.ps1 new file mode 100644 index 0000000..f75509a --- /dev/null +++ b/Tests/Links.Tests.ps1 @@ -0,0 +1,44 @@ +<# + Tests the link cmdlets of the module built in NTFSSecurity\bin\Release in a sandbox folder. +#> +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Pester shares variables between blocks.' +)] +param () + +BeforeAll { + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath 'TestHelpers.psm1') -Force + $modulePath = Join-Path -Path $PSScriptRoot -ChildPath '..\NTFSSecurity\bin\Release\NTFSSecurity.psd1' + Import-Module -Name $modulePath -Force -ErrorAction Stop + $sandbox = New-TestSandbox -Name 'Links' + Push-Location -LiteralPath $sandbox +} + +AfterAll { + Pop-Location + Remove-TestSandbox -Sandbox $sandbox + Remove-Module -Name NTFSSecurity -Force -ErrorAction SilentlyContinue +} + +Describe 'New-NTFSHardLink' { + It 'Should create a hard link to a file' { + $target = New-TestSandboxItem -Sandbox $sandbox -Name 'Target' + $link = Join-Path -Path $sandbox -ChildPath 'Link.txt' + Assert-TestSandboxPath -Sandbox $sandbox -Path $link + + New-NTFSHardLink -Path $link -Target $target -ErrorAction Stop + + $link | Should -Exist + Get-Content -LiteralPath $link | Should -Be (Get-Content -LiteralPath $target) + } + + # Before 5.0.0, the error said "The target path exist" for a target that did not exist. + It 'Should report that a missing target does not exist' { + $missing = Join-Path -Path $sandbox -ChildPath 'Missing.txt' + $link = Join-Path -Path $sandbox -ChildPath 'MissingLink.txt' + Assert-TestSandboxPath -Sandbox $sandbox -Path $missing, $link + + { New-NTFSHardLink -Path $link -Target $missing -ErrorAction Stop } | Should -Throw -ExpectedMessage '*does not exist*' + $link | Should -Not -Exist + } +}