Skip to content

Commit 9e237b2

Browse files
committed
Enhance Set-SqlDscServerPermission to clarify permission management behavior and ensure existing permissions are left unchanged when parameters are omitted
1 parent 1333c79 commit 9e237b2

File tree

3 files changed

+163
-16
lines changed

3 files changed

+163
-16
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4949

5050
### Fixed
5151

52+
- `Set-SqlDscServerPermission`
53+
- Fixed an issue where unspecified permission parameters would incorrectly
54+
revoke existing permissions. The command now only processes permission
55+
categories that are explicitly specified via parameters. For example,
56+
specifying only `-Grant @()` will now correctly revoke only Grant permissions
57+
while leaving GrantWithGrant and Deny permissions unchanged
58+
([issue #2159](https://github.com/dsccommunity/SqlServerDsc/issues/2159)).
5259
- `New-SqlDscDatabase`
5360
- Fixed parameter types for database-scoped configuration properties from
5461
`System.Boolean` to `Microsoft.SqlServer.Management.Smo.DatabaseScopedConfigurationOnOff`

source/Public/Set-SqlDscServerPermission.ps1

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,23 @@
2323
This parameter accepts pipeline input.
2424
2525
.PARAMETER Grant
26-
Specifies the permissions that should be granted. Any existing granted
27-
permissions not in this list will be revoked.
26+
Specifies the permissions that should be granted. The permissions specified
27+
will be the exact granted permissions - any existing granted permissions not
28+
in this list will be revoked. If this parameter is omitted (not specified),
29+
existing Grant permissions are left unchanged.
2830
2931
.PARAMETER GrantWithGrant
3032
Specifies the permissions that should be granted with the grant option.
31-
Any existing grant-with-grant permissions not in this list will be revoked.
33+
The permissions specified will be the exact grant-with-grant permissions -
34+
any existing grant-with-grant permissions not in this list will be revoked.
35+
If this parameter is omitted (not specified), existing GrantWithGrant
36+
permissions are left unchanged.
3237
3338
.PARAMETER Deny
34-
Specifies the permissions that should be denied. Any existing denied
35-
permissions not in this list will be revoked.
39+
Specifies the permissions that should be denied. The permissions specified
40+
will be the exact denied permissions - any existing denied permissions not
41+
in this list will be revoked. If this parameter is omitted (not specified),
42+
existing Deny permissions are left unchanged.
3643
3744
.PARAMETER Force
3845
Specifies that the permissions should be set without any confirmation.
@@ -83,6 +90,15 @@
8390
where the permissions will be set. If specifying `-ErrorAction 'SilentlyContinue'`
8491
then the command will silently continue if any errors occur. If specifying
8592
`-ErrorAction 'Stop'` the command will throw an error on any failure.
93+
94+
> [!IMPORTANT]
95+
> This command only modifies permission categories that are explicitly specified.
96+
> If you omit a parameter (e.g., don't specify `-Grant`), permissions in that
97+
> category are left unchanged. However, if you specify a parameter (even as an
98+
> empty array like `-Grant @()`), the command sets exact permissions for that
99+
> category only - revoking any permissions not in the list. This allows you to
100+
> independently manage Grant, GrantWithGrant, and Deny permissions without
101+
> affecting the other categories.
86102
#>
87103
function Set-SqlDscServerPermission
88104
{
@@ -103,17 +119,17 @@ function Set-SqlDscServerPermission
103119
[Parameter()]
104120
[AllowEmptyCollection()]
105121
[SqlServerPermission[]]
106-
$Grant = @(),
122+
$Grant,
107123

108124
[Parameter()]
109125
[AllowEmptyCollection()]
110126
[SqlServerPermission[]]
111-
$GrantWithGrant = @(),
127+
$GrantWithGrant,
112128

113129
[Parameter()]
114130
[AllowEmptyCollection()]
115131
[SqlServerPermission[]]
116-
$Deny = @(),
132+
$Deny,
117133

118134
[Parameter()]
119135
[System.Management.Automation.SwitchParameter]
@@ -185,15 +201,35 @@ function Set-SqlDscServerPermission
185201
}
186202
}
187203

188-
# Calculate what needs to be revoked (permissions in current state but not in desired state)
189-
$grantToRevoke = $currentGrant | Where-Object -FilterScript { $_ -notin $Grant }
190-
$grantWithGrantToRevoke = $currentGrantWithGrant | Where-Object -FilterScript { $_ -notin $GrantWithGrant }
191-
$denyToRevoke = $currentDeny | Where-Object -FilterScript { $_ -notin $Deny }
204+
# Calculate what needs to be revoked and added
205+
# Only process permission categories that were explicitly specified via parameters
206+
$grantToRevoke = @()
207+
$grantToAdd = @()
208+
$grantWithGrantToRevoke = @()
209+
$grantWithGrantToAdd = @()
210+
$denyToRevoke = @()
211+
$denyToAdd = @()
212+
213+
# Only process Grant permissions if the parameter was explicitly specified
214+
if ($PSBoundParameters.ContainsKey('Grant'))
215+
{
216+
$grantToRevoke = $currentGrant | Where-Object -FilterScript { $_ -notin $Grant }
217+
$grantToAdd = $Grant | Where-Object -FilterScript { $_ -notin $currentGrant }
218+
}
219+
220+
# Only process GrantWithGrant permissions if the parameter was explicitly specified
221+
if ($PSBoundParameters.ContainsKey('GrantWithGrant'))
222+
{
223+
$grantWithGrantToRevoke = $currentGrantWithGrant | Where-Object -FilterScript { $_ -notin $GrantWithGrant }
224+
$grantWithGrantToAdd = $GrantWithGrant | Where-Object -FilterScript { $_ -notin $currentGrantWithGrant }
225+
}
192226

193-
# Calculate what needs to be granted/denied (permissions in desired state but not in current state)
194-
$grantToAdd = $Grant | Where-Object -FilterScript { $_ -notin $currentGrant }
195-
$grantWithGrantToAdd = $GrantWithGrant | Where-Object -FilterScript { $_ -notin $currentGrantWithGrant }
196-
$denyToAdd = $Deny | Where-Object -FilterScript { $_ -notin $currentDeny }
227+
# Only process Deny permissions if the parameter was explicitly specified
228+
if ($PSBoundParameters.ContainsKey('Deny'))
229+
{
230+
$denyToRevoke = $currentDeny | Where-Object -FilterScript { $_ -notin $Deny }
231+
$denyToAdd = $Deny | Where-Object -FilterScript { $_ -notin $currentDeny }
232+
}
197233

198234
# Revoke permissions that should no longer exist
199235
if ($grantToRevoke -and $grantToRevoke.Count -gt 0)

tests/Unit/Public/Set-SqlDscServerPermission.Tests.ps1

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,110 @@ Describe 'Set-SqlDscServerPermission' -Tag 'Public' {
304304
Should -Invoke -CommandName Grant-SqlDscServerPermission -Exactly -Times 0 -Scope It
305305
}
306306
}
307+
308+
Context 'When revoking only specific permission categories while preserving others' {
309+
BeforeAll {
310+
$mockServerObject = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Server'
311+
$mockServerObject.InstanceName = 'MockInstance'
312+
313+
$mockLoginObject = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Login' -ArgumentList @($mockServerObject, 'DOMAIN\MyLogin')
314+
315+
# Create mock ServerPermissionInfo objects
316+
$mockServerPermissionInfo = @(
317+
New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.ServerPermissionInfo'
318+
)
319+
320+
Mock -CommandName Get-SqlDscServerPermission -MockWith {
321+
return $mockServerPermissionInfo
322+
}
323+
324+
Mock -CommandName ConvertTo-SqlDscServerPermission -MockWith {
325+
return InModuleScope -ScriptBlock {
326+
@(
327+
[ServerPermission]@{
328+
State = 'Grant'
329+
Permission = @('ViewServerState')
330+
}
331+
[ServerPermission]@{
332+
State = 'GrantWithGrant'
333+
Permission = @('CreateAnyDatabase')
334+
}
335+
[ServerPermission]@{
336+
State = 'Deny'
337+
Permission = @('ViewAnyDefinition')
338+
}
339+
)
340+
}
341+
}
342+
343+
Mock -CommandName Grant-SqlDscServerPermission
344+
Mock -CommandName Deny-SqlDscServerPermission
345+
Mock -CommandName Revoke-SqlDscServerPermission
346+
}
347+
348+
It 'Should revoke only Grant permissions when only Grant parameter is specified' {
349+
# Specify only Grant parameter with empty array - should revoke Grant permissions only
350+
Set-SqlDscServerPermission -Login $mockLoginObject -Grant @() -Force
351+
352+
Should -Invoke -CommandName Get-SqlDscServerPermission -Exactly -Times 1 -Scope It
353+
354+
# Should revoke ViewServerState (Grant permission)
355+
Should -Invoke -CommandName Revoke-SqlDscServerPermission -ParameterFilter {
356+
$Permission -contains 'ViewServerState' -and -not $WithGrant
357+
} -Exactly -Times 1 -Scope It
358+
359+
# Should NOT revoke GrantWithGrant or Deny permissions
360+
Should -Invoke -CommandName Revoke-SqlDscServerPermission -ParameterFilter {
361+
$Permission -contains 'CreateAnyDatabase'
362+
} -Exactly -Times 0 -Scope It
363+
364+
Should -Invoke -CommandName Revoke-SqlDscServerPermission -ParameterFilter {
365+
$Permission -contains 'ViewAnyDefinition'
366+
} -Exactly -Times 0 -Scope It
367+
}
368+
369+
It 'Should revoke only GrantWithGrant permissions when only GrantWithGrant parameter is specified' {
370+
# Specify only GrantWithGrant parameter with empty array
371+
Set-SqlDscServerPermission -Login $mockLoginObject -GrantWithGrant @() -Force
372+
373+
Should -Invoke -CommandName Get-SqlDscServerPermission -Exactly -Times 1 -Scope It
374+
375+
# Should revoke CreateAnyDatabase (GrantWithGrant permission)
376+
Should -Invoke -CommandName Revoke-SqlDscServerPermission -ParameterFilter {
377+
$Permission -contains 'CreateAnyDatabase' -and $WithGrant -eq $true
378+
} -Exactly -Times 1 -Scope It
379+
380+
# Should NOT revoke Grant or Deny permissions
381+
Should -Invoke -CommandName Revoke-SqlDscServerPermission -ParameterFilter {
382+
$Permission -contains 'ViewServerState'
383+
} -Exactly -Times 0 -Scope It
384+
385+
Should -Invoke -CommandName Revoke-SqlDscServerPermission -ParameterFilter {
386+
$Permission -contains 'ViewAnyDefinition'
387+
} -Exactly -Times 0 -Scope It
388+
}
389+
390+
It 'Should revoke only Deny permissions when only Deny parameter is specified' {
391+
# Specify only Deny parameter with empty array
392+
Set-SqlDscServerPermission -Login $mockLoginObject -Deny @() -Force
393+
394+
Should -Invoke -CommandName Get-SqlDscServerPermission -Exactly -Times 1 -Scope It
395+
396+
# Should revoke ViewAnyDefinition (Deny permission)
397+
Should -Invoke -CommandName Revoke-SqlDscServerPermission -ParameterFilter {
398+
$Permission -contains 'ViewAnyDefinition' -and -not $WithGrant
399+
} -Exactly -Times 1 -Scope It
400+
401+
# Should NOT revoke Grant or GrantWithGrant permissions
402+
Should -Invoke -CommandName Revoke-SqlDscServerPermission -ParameterFilter {
403+
$Permission -contains 'ViewServerState'
404+
} -Exactly -Times 0 -Scope It
405+
406+
Should -Invoke -CommandName Revoke-SqlDscServerPermission -ParameterFilter {
407+
$Permission -contains 'CreateAnyDatabase'
408+
} -Exactly -Times 0 -Scope It
409+
}
410+
}
307411
}
308412

309413
Context 'When setting permissions for a server role' {

0 commit comments

Comments
 (0)