Browse Source

fix(access): report what the initialization of the authorization manager throws

Get-NTFSEffectiveAccess returned no access and no error when Windows refused
to start the authorization manager for the computer of -ServerName.
Win32.GetEffectiveAccess ignored what the initialization threw (an outer
catch { }), so the result looked like an account without any rights. It
reproduces on Windows Server 2025 in both editions with a name of 32,718
characters or more, which fails with error 14, where a shorter name gets RPC
server unavailable and falls back to this computer.

One try/catch now records every exception, and the cmdlet writes a
GetEffectiveAccessError. The warning that the result is based on this computer
comes only with a result now: it also preceded an error, such as for an
account that Windows can't resolve when the computer can't be reached, which
the cmdlet page and the lab tests contradict.

Two tests failed first in Windows PowerShell 5.1 and PowerShell 7, as an
administrator and as a basic user, and pass in all four configurations. The
cmdlet page, the help file, and the CHANGELOG say what changed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
pull/127/head
Raimund Andree 2 weeks ago
parent
commit
25fe77500e
  1. 9
      CHANGELOG.md
  2. 2
      Docs/Cmdlets/Get-NTFSEffectiveAccess.md
  3. 3
      NTFSSecurity/AccessCmdlets/GetEffectiveAccess.cs
  4. 1
      NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml
  5. 24
      Security2/Win32/Lib.cs
  6. 40
      Tests/Access.Tests.ps1

9
CHANGELOG.md

@ -207,6 +207,15 @@ The format is based on
Operators. It now uses the local authorization manager of this computer when
the remote one refuses the user, as it already did when the remote one can't
be reached. For the name of another computer, the error stays
- Fix `Get-NTFSEffectiveAccess`, which returned no access and no error when
Windows refused to start the authorization manager for the computer of
`-ServerName`, for example for a name of 32,718 characters or more: the
result looked like an account without any rights. The cmdlet now writes
a `GetEffectiveAccessError` with the error that Windows reported and
returns no result, as it does when a later step of the calculation fails.
The warning that the result is based on this computer now comes only with
a result; it also came before an error when the computer couldn't be
reached
- Fix `Get-NTFSOwner`, which wrote a "The pipeline has been stopped" error
for every path when a command such as `Select-Object -First 1` stopped the
pipeline, and which repeated a failed read instead of reporting the

2
Docs/Cmdlets/Get-NTFSEffectiveAccess.md

@ -188,6 +188,8 @@ Before 5.0.0-rc7, the warning about a computer that couldn't be reached didn't n
Before 5.0.0-rc7, a user who wasn't an administrator got the error "Access is denied" and no result on a computer in a domain, also for a name of this computer, such as the default `localhost`.
Before 5.0.0-rc8, the cmdlet returned no access and no error when Windows refused to start the authorization manager for the computer of `-ServerName`, for example for a name of 32,718 characters or more, so that the result looked like an account without any rights. The cmdlet now writes a non-terminating `GetEffectiveAccessError` with the error that Windows reported and returns no result for the item, as it does for every other failure of the calculation. It warns that the result is based on this computer only when it returns a result; before 5.0.0-rc8, the warning also came before an error when the computer couldn't be reached.
## RELATED LINKS
[Get-NTFSAccess](Get-NTFSAccess.md)

3
NTFSSecurity/AccessCmdlets/GetEffectiveAccess.cs

@ -157,7 +157,8 @@ namespace NTFSSecurity
private void WriteEffectiveAccess(EffectiveAccessInfo result, object target)
{
if (!result.FromRemote)
// The warning qualifies a result, which an error leaves out. Before 5.0.0-rc8, it came before the error, too.
if (!result.FromRemote && !result.OperationFailed)
{
// Since 5.0.0-rc7, the warning names the computer, which a command with many items can't tell otherwise.
WriteWarning(string.Format("The effective rights can only be computed based on group membership on this computer, " +

1
NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml

@ -5169,6 +5169,7 @@ PS C:\&gt; Get-NTFSAudit -SecurityDescriptor $sd</dev:code>
<maml:para>Before 5.0.0, `-ExcludeNoneAccessEntries` had no effect, and the cmdlet returned nothing without `-Path` or for `-SecurityDescriptor`. When the computer of `-ServerName` couldn't be reached, the cmdlet warned that it had calculated the result on this computer, but returned no access instead of that result.</maml:para>
<maml:para>Before 5.0.0-rc7, the warning about a computer that couldn't be reached didn't name the computer, and the cmdlet warned for every name of this computer except `localhost` in lowercase, such as `.`, `LOCALHOST`, or the computer name.</maml:para>
<maml:para>Before 5.0.0-rc7, a user who wasn't an administrator got the error "Access is denied" and no result on a computer in a domain, also for a name of this computer, such as the default `localhost`.</maml:para>
<maml:para>Before 5.0.0-rc8, the cmdlet returned no access and no error when Windows refused to start the authorization manager for the computer of `-ServerName`, for example for a name of 32,718 characters or more, so that the result looked like an account without any rights. The cmdlet now writes a non-terminating `GetEffectiveAccessError` with the error that Windows reported and returns no result for the item, as it does for every other failure of the calculation. It warns that the result is based on this computer only when it returns a result; before 5.0.0-rc8, the warning also came before an error when the computer couldn't be reached.</maml:para>
</maml:alert>
</maml:alertSet>
<command:examples>

24
Security2/Win32/Lib.cs

@ -125,19 +125,15 @@ namespace Security2
try
{
GetEffectivePermissions_AuthzInitializeResourceManager(serverName, out remoteServerAvailable);
try
{
GetEffectivePermissions_AuthzInitializeContextFromSid(identity);
effectiveAccess = GetEffectivePermissions_AuthzAccessCheck(sd);
}
catch (Exception ex)
{
authzException = ex;
}
GetEffectivePermissions_AuthzInitializeContextFromSid(identity);
effectiveAccess = GetEffectivePermissions_AuthzAccessCheck(sd);
}
catch (Exception ex)
{
// Also what the initialization of the resource manager throws. Before 5.0.0-rc8, that was ignored, and
// the caller got no access without an error.
authzException = ex;
}
catch
{ }
finally
{
GetEffectivePermissions_FreeResouces();
@ -148,8 +144,8 @@ namespace Security2
#region Win32 Wrapper
// Whether a name of -ServerName names this computer: localhost in any case, ., the NetBIOS name, the DNS host
// name, or the fully qualified domain name. It must not throw, because GetEffectiveAccess hides every exception
// of the resource manager behind a result without access.
// name, or the fully qualified domain name. It answers false when it can't tell and doesn't throw, so that the
// fallback for a computer that can't be reached doesn't fail on this question.
private static bool IsLocalComputer(string serverName)
{
if (string.IsNullOrEmpty(serverName))

40
Tests/Access.Tests.ps1

@ -169,6 +169,46 @@ Describe 'Get-NTFSEffectiveAccess' {
"because the computer '' can't be reached for a remote access check. " +
'For more accurate results, calculate effective access rights on that computer.')
}
# The warning says that the result is the one of this computer, so it has no place before an error that leaves
# no result. Before 5.0.0-rc8, the cmdlet warned and then wrote the error for an account that Windows can't resolve.
It 'Should write the error and no warning about this computer for an identity that cannot be resolved' {
$identity = [Security2.IdentityReference2] 'S-1-5-21-1-2-3-1001'
$identity.AccountName | Should -BeNullOrEmpty
$result = @(Get-NTFSEffectiveAccess -Path $effectiveFile -Account $identity -ServerName 'ntfssecurity-test.invalid' -WarningVariable accessWarnings -WarningAction SilentlyContinue -ErrorVariable accessErrors -ErrorAction SilentlyContinue)
$result | Should -BeNullOrEmpty
$accessErrors | Should -HaveCount 1
$accessErrors[0].FullyQualifiedErrorId | Should -BeLike 'GetEffectiveAccessError,*'
@($accessWarnings.Message | Where-Object -FilterScript { $_ -like '*can''t be reached for a remote access check*' }) | Should -BeNullOrEmpty
}
}
# Before 5.0.0-rc8, the cmdlet ignored what the initialization of the authorization manager threw and returned no
# access without an error, which looks like an account without rights. On Windows Server 2025, a name of 32,718
# characters or more fails there with the error 14, "Not enough memory resources are available to complete this
# operation", while a shorter name gets RPC server unavailable, and the cmdlet falls back to this computer. Another
# version of Windows may answer the long name like the short one, so the test accepts both outcomes and fails for
# no access without an error.
Context 'When Windows rejects the name of -ServerName' {
It 'Should write an error or return the result of this computer, never no access' {
$expected = Get-NTFSEffectiveAccess -Path $effectiveFile -WarningAction SilentlyContinue -ErrorAction Stop
[long] $expected.AccessRights | Should -BeGreaterThan ([long] [Security2.FileSystemRights2]::Synchronize)
$result = @(Get-NTFSEffectiveAccess -Path $effectiveFile -ServerName ('a' * 40000) -WarningVariable accessWarnings -WarningAction SilentlyContinue -ErrorVariable accessErrors -ErrorAction SilentlyContinue)
if ($accessErrors) {
$result | Should -BeNullOrEmpty
$accessErrors | Should -HaveCount 1
$accessErrors[0].FullyQualifiedErrorId | Should -BeLike 'GetEffectiveAccessError,*'
@($accessWarnings.Message | Where-Object -FilterScript { $_ -like '*can''t be reached for a remote access check*' }) | Should -BeNullOrEmpty
}
else {
$result | Should -HaveCount 1
$result[0].AccessRights | Should -Be $expected.AccessRights
}
}
}
# Not every computer offers the remote interface of the authorization manager; the cmdlet then calculates the result

Loading…
Cancel
Save