diff --git a/CHANGELOG.md b/CHANGELOG.md index 59e851e..07b28ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -439,5 +439,11 @@ The format is based on - Fix [Get-ChildItem2](Docs/Cmdlets/Get-ChildItem2.md) with `-Hidden`, which omitted the first hidden item unless `-Force` was also supplied +- Fix the comparison of an identity with a name, such as + `$entry.Account -eq 'nt authority\system'`, in the Turkish culture + (`tr-TR`): it changed the case of both names with the culture of the thread, + which turns `I` into a dotless `ı`, so an account whose name holds an + uppercase `I`, such as `NT AUTHORITY\SYSTEM` or `BUILTIN\Administrators`, + did not match the same name in another case [Unreleased]: https://github.com/raandree/NTFSSecurity/compare/4.2.6...HEAD diff --git a/Security2/IdentityReference2.cs b/Security2/IdentityReference2.cs index 9f01a96..2a72c3b 100644 --- a/Security2/IdentityReference2.cs +++ b/Security2/IdentityReference2.cs @@ -195,7 +195,8 @@ namespace Security2 if (this.ntAccount != null) { - if (this.ntAccount.Value.ToLower() == value.ToLower()) + // Not ToLower: with the culture of the thread, tr-TR lowercases I to U+0131 and misses names such as NT AUTHORITY\SYSTEM. + if (string.Equals(this.ntAccount.Value, value, StringComparison.OrdinalIgnoreCase)) { return true; } diff --git a/Tests/ObjectApis.Tests.ps1 b/Tests/ObjectApis.Tests.ps1 index d608a17..575e34c 100644 --- a/Tests/ObjectApis.Tests.ps1 +++ b/Tests/ObjectApis.Tests.ps1 @@ -159,6 +159,25 @@ Describe 'Identity comparisons and conversions' { $identity.Equals($other) | Should -Be $Expected } + # tr-TR lowercases I to U+0131, so a comparison that lowercases both names with the current culture misses an account name that holds an + # uppercase I (NT AUTHORITY, BUILTIN) when the other name has another case. The name must match in every culture. + It 'Should compare a name with the account ignoring case in Turkish, where I and i are different letters' { + $system = [Security2.IdentityReference2] 'S-1-5-18' + $system.AccountName | Should -MatchExactly 'I' -Because 'the test needs an account name with an uppercase I' + $original = [System.Threading.Thread]::CurrentThread.CurrentCulture + try { + [System.Threading.Thread]::CurrentThread.CurrentCulture = [System.Globalization.CultureInfo]::GetCultureInfo('tr-TR') + 'I'.ToLower() | Should -Be ([string][char]0x131) -Because 'the culture of the thread has to be Turkish for the test to mean anything' + $system.Equals($system.AccountName) | Should -BeTrue + $system.Equals($system.AccountName.ToLowerInvariant()) | Should -BeTrue + $system.Equals($system.AccountName.ToUpperInvariant()) | Should -BeTrue + $system.Equals('NTFSSecurity-not-an-account') | Should -BeFalse + } + finally { + [System.Threading.Thread]::CurrentThread.CurrentCulture = $original + } + } + It 'Should compare null operands and distinct instances through both operators' { $same = [Security2.IdentityReference2] 'S-1-1-0' $different = [Security2.IdentityReference2] 'S-1-5-32-546'