Skip to content

Commit 755ad31

Browse files
authored
*-SqlDscServerPermission: Add commands SQL Server permission management (#2157)
1 parent 5356e0c commit 755ad31

19 files changed

+2697
-22
lines changed

.github/instructions/dsc-community-style-guidelines-pester.instructions.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ applyTo: "**/*.[Tt]ests.ps1"
1414
- Never test verbose messages, debug messages or parameter binding behavior
1515
- Pass all mandatory parameters to avoid prompts
1616

17+
## Requirements
18+
- Inside `It` blocks, assign unused return objects to `$null` (unless part of pipeline)
19+
- Tested entity must be called from within the `It` blocks
20+
- Keep results and assertions in same `It` block
21+
- Avoid try-catch-finally for cleanup, use `AfterAll` or `AfterEach`
22+
- Avoid unnecessary remove/recreate cycles
23+
1724
## Naming
1825
- One `Describe` block per file matching the tested entity name
1926
- `Context` descriptions start with 'When'
@@ -51,10 +58,6 @@ applyTo: "**/*.[Tt]ests.ps1"
5158
- Keep scope close to usage context
5259

5360
## Best Practices
54-
- Inside `It` blocks, assign unused return objects to `$null` (unless part of pipeline)
55-
- Tested entity must be called from within the `It` blocks
56-
- Keep results and assertions in same `It` block
5761
- Cover all scenarios and code paths
5862
- Use `BeforeEach` and `AfterEach` sparingly
59-
- Avoid try-catch-finally for cleanup, use `AfterAll` or `AfterEach`
60-
- Avoid unnecessary remove/recreate cycles
63+
- Use `$PSDefaultParameterValues` only for Pester commands (`Describe`, `Context`, `It`, `Mock`, `Should`, `InModuleScope`)

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3535
- Enhanced workflow with proper environment variable configuration and DSCv3 verification.
3636
- Fixed environment variable persistence by using $GITHUB_ENV instead of
3737
job-level env declaration.
38+
- `Grant-SqlDscServerPermission`
39+
- Added new public command to grant server permissions to a principal (Login or ServerRole) on a SQL Server Database Engine instance.
40+
- `Deny-SqlDscServerPermission`
41+
- Added new public command to deny server permissions to a principal (Login or ServerRole).
42+
- `Revoke-SqlDscServerPermission`
43+
- Added new public command to revoke server permissions from a principal (Login or ServerRole).
44+
- `Test-SqlDscServerPermission`
45+
- Added new public command with Grant/Deny parameter sets (and `-WithGrant`) to test server permissions for a principal.
3846
- `Assert-SqlDscLogin`
3947
- Added new public command to validate that a specified SQL Server principal
4048
is a login.

azure-pipelines.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -299,18 +299,24 @@ stages:
299299
'tests/Integration/Commands/Test-SqlDscIsLoginEnabled.Integration.Tests.ps1'
300300
'tests/Integration/Commands/New-SqlDscRole.Integration.Tests.ps1'
301301
'tests/Integration/Commands/Get-SqlDscRole.Integration.Tests.ps1'
302-
'tests/Integration/Commands/Remove-SqlDscRole.Integration.Tests.ps1'
303-
'tests/Integration/Commands/Remove-SqlDscLogin.Integration.Tests.ps1'
302+
'tests/Integration/Commands/Grant-SqlDscServerPermission.Integration.Tests.ps1'
303+
'tests/Integration/Commands/Get-SqlDscServerPermission.Integration.Tests.ps1'
304+
'tests/Integration/Commands/Test-SqlDscServerPermission.Integration.Tests.ps1'
305+
'tests/Integration/Commands/Deny-SqlDscServerPermission.Integration.Tests.ps1'
306+
'tests/Integration/Commands/Revoke-SqlDscServerPermission.Integration.Tests.ps1'
304307
'tests/Integration/Commands/Get-SqlDscDatabase.Integration.Tests.ps1'
305308
'tests/Integration/Commands/New-SqlDscDatabase.Integration.Tests.ps1'
306309
'tests/Integration/Commands/Set-SqlDscDatabase.Integration.Tests.ps1'
307310
'tests/Integration/Commands/Test-SqlDscDatabase.Integration.Tests.ps1'
308-
'tests/Integration/Commands/Remove-SqlDscDatabase.Integration.Tests.ps1'
309311
'tests/Integration/Commands/Get-SqlDscAgentAlert.Integration.Tests.ps1'
310312
'tests/Integration/Commands/New-SqlDscAgentAlert.Integration.Tests.ps1'
311313
'tests/Integration/Commands/Set-SqlDscAgentAlert.Integration.Tests.ps1'
312314
'tests/Integration/Commands/Test-SqlDscAgentAlert.Integration.Tests.ps1'
315+
# Group 8
313316
'tests/Integration/Commands/Remove-SqlDscAgentAlert.Integration.Tests.ps1'
317+
'tests/Integration/Commands/Remove-SqlDscDatabase.Integration.Tests.ps1'
318+
'tests/Integration/Commands/Remove-SqlDscRole.Integration.Tests.ps1'
319+
'tests/Integration/Commands/Remove-SqlDscLogin.Integration.Tests.ps1'
314320
315321
# Group 9
316322
'tests/Integration/Commands/Uninstall-SqlDscServer.Integration.Tests.ps1'
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<#
2+
.SYNOPSIS
3+
The possible server permissions that can be granted, denied, or revoked.
4+
5+
.NOTES
6+
The available permissions can be seen in the ServerPermission Class documentation:
7+
https://learn.microsoft.com/en-us/dotnet/api/microsoft.sqlserver.management.smo.serverpermission
8+
#>
9+
enum SqlServerPermission
10+
{
11+
# cSpell:ignore securables
12+
AdministerBulkOperations = 1
13+
AlterAnyAvailabilityGroup
14+
AlterAnyConnection
15+
AlterAnyCredential
16+
AlterAnyDatabase
17+
AlterAnyEndpoint
18+
AlterAnyEventNotification
19+
AlterAnyEventSession
20+
AlterAnyEventSessionAddEvent
21+
AlterAnyEventSessionAddTarget
22+
AlterAnyEventSessionDisable
23+
AlterAnyEventSessionDropEvent
24+
AlterAnyEventSessionDropTarget
25+
AlterAnyEventSessionEnable
26+
AlterAnyEventSessionOption
27+
AlterAnyLinkedServer
28+
AlterAnyLogin
29+
AlterAnyServerAudit
30+
AlterAnyServerRole
31+
AlterResources
32+
AlterServerState
33+
AlterSettings
34+
AlterTrace
35+
AuthenticateServer
36+
ConnectAnyDatabase
37+
ConnectSql
38+
ControlServer
39+
CreateAnyDatabase
40+
CreateAnyEventSession
41+
CreateAvailabilityGroup
42+
CreateDdlEventNotification
43+
CreateEndpoint
44+
CreateLogin
45+
CreateServerRole
46+
CreateTraceEventNotification
47+
DropAnyEventSession
48+
ExternalAccessAssembly
49+
ImpersonateAnyLogin
50+
SelectAllUserSecurables
51+
Shutdown
52+
UnsafeAssembly
53+
ViewAnyCryptographicallySecuredDefinition
54+
ViewAnyDatabase
55+
ViewAnyDefinition
56+
ViewAnyErrorLog
57+
ViewAnyPerformanceDefinition
58+
ViewAnySecurityDefinition
59+
ViewServerPerformanceState
60+
ViewServerSecurityAudit
61+
ViewServerSecurityState
62+
ViewServerState
63+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<#
2+
.SYNOPSIS
3+
Denies server permissions to a principal on a SQL Server Database Engine instance.
4+
5+
.DESCRIPTION
6+
This command denies server permissions to an existing principal on a SQL Server
7+
Database Engine instance. The principal can be specified as either a Login
8+
object (from Get-SqlDscLogin) or a ServerRole object (from Get-SqlDscRole).
9+
10+
.PARAMETER Login
11+
Specifies the Login object for which the permissions are denied.
12+
This parameter accepts pipeline input.
13+
14+
.PARAMETER ServerRole
15+
Specifies the ServerRole object for which the permissions are denied.
16+
This parameter accepts pipeline input.
17+
18+
.PARAMETER Permission
19+
Specifies the permissions to be denied. Specify multiple permissions by
20+
providing an array of SqlServerPermission enum values.
21+
22+
.PARAMETER Force
23+
Specifies that the permissions should be denied without any confirmation.
24+
25+
.OUTPUTS
26+
None.
27+
28+
.EXAMPLE
29+
$serverInstance = Connect-SqlDscDatabaseEngine
30+
$login = $serverInstance | Get-SqlDscLogin -Name 'MyLogin'
31+
32+
Deny-SqlDscServerPermission -Login $login -Permission ConnectSql, ViewServerState
33+
34+
Denies the specified permissions to the login 'MyLogin'.
35+
36+
.EXAMPLE
37+
$serverInstance = Connect-SqlDscDatabaseEngine
38+
$role = $serverInstance | Get-SqlDscRole -Name 'MyRole'
39+
40+
$role | Deny-SqlDscServerPermission -Permission AlterAnyDatabase -Force
41+
42+
Denies the specified permissions to the role 'MyRole' without prompting for confirmation.
43+
44+
.NOTES
45+
The Login or ServerRole object must come from the same SQL Server instance
46+
where the permissions will be denied. If specifying `-ErrorAction 'SilentlyContinue'`
47+
then the command will silently continue if any errors occur. If specifying
48+
`-ErrorAction 'Stop'` the command will throw an error on any failure.
49+
#>
50+
function Deny-SqlDscServerPermission
51+
{
52+
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the rule does not yet support parsing the code when a parameter type is not available. The ScriptAnalyzer rule UseSyntacticallyCorrectExamples will always error in the editor due to https://github.com/indented-automation/Indented.ScriptAnalyzerRules/issues/8.')]
53+
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('AvoidThrowOutsideOfTry', '', Justification = 'Because the code throws based on an prior expression')]
54+
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
55+
[OutputType()]
56+
param
57+
(
58+
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'Login')]
59+
[Microsoft.SqlServer.Management.Smo.Login]
60+
$Login,
61+
62+
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ServerRole')]
63+
[Microsoft.SqlServer.Management.Smo.ServerRole]
64+
$ServerRole,
65+
66+
[Parameter(Mandatory = $true)]
67+
[SqlServerPermission[]]
68+
$Permission,
69+
70+
[Parameter()]
71+
[System.Management.Automation.SwitchParameter]
72+
$Force
73+
)
74+
75+
process
76+
{
77+
if ($Force.IsPresent -and -not $Confirm)
78+
{
79+
$ConfirmPreference = 'None'
80+
}
81+
82+
# Determine which principal object we're working with
83+
if ($PSCmdlet.ParameterSetName -eq 'Login')
84+
{
85+
$principalName = $Login.Name
86+
$serverObject = $Login.Parent
87+
}
88+
else
89+
{
90+
$principalName = $ServerRole.Name
91+
$serverObject = $ServerRole.Parent
92+
}
93+
94+
$verboseDescriptionMessage = $script:localizedData.ServerPermission_Deny_ShouldProcessVerboseDescription -f $principalName, $serverObject.InstanceName, ($Permission -join ',')
95+
$verboseWarningMessage = $script:localizedData.ServerPermission_Deny_ShouldProcessVerboseWarning -f $principalName
96+
$captionMessage = $script:localizedData.ServerPermission_Deny_ShouldProcessCaption
97+
98+
if ($PSCmdlet.ShouldProcess($verboseDescriptionMessage, $verboseWarningMessage, $captionMessage))
99+
{
100+
# Convert enum array to ServerPermissionSet object
101+
$permissionSet = [Microsoft.SqlServer.Management.Smo.ServerPermissionSet]::new()
102+
foreach ($permissionName in $Permission)
103+
{
104+
$permissionSet.$permissionName = $true
105+
}
106+
107+
# Get the permissions names that are set to $true in the ServerPermissionSet.
108+
$permissionName = $permissionSet |
109+
Get-Member -MemberType 'Property' |
110+
Select-Object -ExpandProperty 'Name' |
111+
Where-Object -FilterScript {
112+
$permissionSet.$_
113+
}
114+
115+
try
116+
{
117+
$serverObject.Deny($permissionSet, $principalName)
118+
}
119+
catch
120+
{
121+
$errorMessage = $script:localizedData.ServerPermission_Deny_FailedToDenyPermission -f $principalName, $serverObject.InstanceName
122+
123+
$PSCmdlet.ThrowTerminatingError(
124+
[System.Management.Automation.ErrorRecord]::new(
125+
$errorMessage,
126+
'DSDSP0001', # cSpell: disable-line
127+
[System.Management.Automation.ErrorCategory]::InvalidOperation,
128+
$principalName
129+
)
130+
)
131+
}
132+
}
133+
}
134+
}

0 commit comments

Comments
 (0)