Remove-DbaPrivilege - Add a command to revoke Windows privileges - #10739
Conversation
The counterpart of Set-DbaPrivilege. It exports the user rights with secedit, takes the accounts out of the right's line and applies the policy again. With -User it revokes from that account (a name or a SID), otherwise from the SQL Server engine service accounts and their per-service SIDs, skipping the shared built-in accounts. (do *Privilege*) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
potatoqualitee
left a comment
There was a problem hiding this comment.
Blocking: normalize \.\ local service accounts before resolving their SID (public/Remove-DbaPrivilege.ps1, around line 120).
Get-DbaService passes StartName through unchanged, and Windows accepts .\SqlSvc as a service identity. The new resolver sends that string directly to NTAccount.Translate(), which cannot resolve the .\ form and returns $null through the catch. secedit exports the same local account as a bare name or *SID, so the text fallback also cannot match it.
Concrete failure: when SQL runs as .\SqlSvc and that account holds LPIM/IFI, discovery includes the account but this command leaves its grant intact. If the per-service SID also has the right, the command can report that removal while silently leaving the service account's grant. Explicit -User ".\SqlSvc" fails the same way. I independently reproduced the identity boundary: .\cl fails translation while PC\cl and bare cl both resolve to the same SID.
Please normalize a leading .\ to $env:COMPUTERNAME\ on the target before SID translation (the original name can still be retained for output), and add coverage that grants to a qualified local account and revokes via .\name, including the discovery form.
(do Remove-DbaPrivilege) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Fixed in f25dd05. This text was created by Claude and reviewed by Andreas Jordan. |
potatoqualitee
left a comment
There was a problem hiding this comment.
Reviewed the complete current head, including the prior .\ local-account blocking finding, SID translation, secedit/error/cleanup paths, real privilege regressions, exact-head CI, and discussions. The earlier defect is corrected: leading .\ identities are normalized against the target computer, and both explicit and discovered service-account paths are covered. No material defect remains.
Closes #10617. This implements shape 1 of the issue: the secedit approach that
Set-DbaPrivilegealready uses.The command
It takes the same parameters as
Set-DbaPrivilege:-ComputerName,-Credential,-Type(IFI,LPIM,BatchLogon,SecAudit,ServiceLogon,CreateGlobalObjects) and-User. It also uses the same credential handling for the pre-flight checks (the #10616 pattern).On the target computer, one script block does the whole job, with cleanup in a
finally:secedit /export /areas USER_RIGHTS).secedit /configure /areas USER_RIGHTSif something changed.Both secedit calls check the exit code.
Output. The command returns one object per revoked right:
ComputerName,User,Type,Privilege,Status = "Removed". A right the account did not hold returns nothing; the command warns about it instead. UnlikeSet-DbaPrivilege, it returns objects, because what was actually revoked is what a caller wants to know.ConfirmImpactisHigh, and the ShouldProcess check comes before the service discovery, so-WhatIfcontacts nothing.Details worth a look
*SIDor an account name, and secedit writes a local account by its bare name (dbatoolsci_priv1234, without the computer name). That form is whatSet-DbaPrivilegeproduces for a local account. So every entry is resolved to its SID on the target computer and compared with the account's SID. Only if one side cannot be resolved (for example, the account was deleted) are they compared as text. The position of an entry does not matter.SeLockMemoryPrivilege =in the file, andsecedit /configurethen clears the right. This was checked in the lab: afterwards, the right has no line at all in the export.-Usercollects the per-service SID (NT SERVICE\<ServiceName>) and the service account of every engine service, and revokes from both. Since Set-DbaPrivilege: Use per-service SID (NT SERVICE\ServiceName) for IFI, LPIM, SecAudit聽#10228,Set-DbaPrivilegegrants IFI, LPIM and SecAudit to the per-service SID, but earlier versions granted them to the service account.-User.Tests
tests/Remove-DbaPrivilege.Tests.ps1:Set-DbaPrivilege, and checks the output objects.SeCreateGlobalPrivilege(Administrators, SERVICE, ...) are unchanged afterwards.-WhatIfchanges nothing.AfterAllrevokes all six rights by SID and removes the users.Lab results from the testing-dbatools harness, on pwsh 7.6.3 and Windows PowerShell 5.1:
*-DbaPrivilege: 16 of 16 tests pass on both editions (Remove 6, Set 5, Get 5).Beyond the tests, a manual remote run against a second computer (SQL03) over WinRM:
Set-DbaPrivilegeand revoked them withRemove-DbaPrivilege; the BUILTIN holders were unchanged.Side finding, not changed here
Get-DbaPrivilegereports a local account by its bare name, exactly as secedit exports it, soGet-DbaPrivilege | Where-Object User -eq "SQL03\localuser"finds nothing.created by Claude and reviewed by Andreas Jordan
馃 Generated with Claude Code