Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b41547f
Initial plan
Copilot Aug 30, 2025
683ea11
Add core server permission commands and private functions
Copilot Aug 30, 2025
6e04b2e
Add integration tests and update CHANGELOG for new server permission …
Copilot Aug 30, 2025
f4db6ab
Update server permission commands to use State parameter and ServerPe…
Copilot Aug 30, 2025
4299b88
Merge branch 'main' into copilot/fix-e806ea1d-2077-4c68-a272-f8dea527…
johlju Aug 30, 2025
167bac9
Restructure server permission commands based on feedback - rename com…
Copilot Aug 30, 2025
24f4c67
Change Permission parameter to accept string array for easier usage
Copilot Aug 30, 2025
a1c5aab
Implement all requested improvements to server permission commands
Copilot Aug 31, 2025
50e8487
Address feedback: update server permission commands to use Login/Serv…
Copilot Aug 31, 2025
345461e
Clean up code
johlju Aug 31, 2025
aea4697
Fix blank line EOF
johlju Aug 31, 2025
3dcc4a4
Change error handling to use PSCmdlet.ThrowTerminatingError in server…
Copilot Aug 31, 2025
f78e7d6
Merge branch 'main' into copilot/fix-e806ea1d-2077-4c68-a272-f8dea527…
johlju Aug 31, 2025
3ec521e
Remove unused $principalObject variables from server permission commands
Copilot Aug 31, 2025
cb5e97a
Refactor SQL DSC Server Permission Tests
johlju Aug 31, 2025
8a3dd4d
Update integration tests
johlju Aug 31, 2025
2c337e3
Merge branch 'main' into copilot/fix-e806ea1d-2077-4c68-a272-f8dea527…
johlju Aug 31, 2025
a14e934
Remove integration tests for Get-SqlDscServerPermission
johlju Aug 31, 2025
1edcd8f
Refactor permission handling in integration and unit tests to elimina…
johlju Aug 31, 2025
7278bfe
Update CHANGELOG.md
johlju Aug 31, 2025
5c9a575
Update tests/Integration/Commands/Deny-SqlDscServerPermission.Integra…
johlju Aug 31, 2025
01d832a
Update tests/Integration/Commands/Deny-SqlDscServerPermission.Integra…
johlju Aug 31, 2025
eba49be
Remove unit test stub imports from server permission integration tests
Copilot Aug 31, 2025
bc3112f
Reorganize server permissions in SqlServerPermission enum for clarity…
johlju Aug 31, 2025
8c1aaa3
Reorganize integration test commands by grouping and adding missing r…
johlju Aug 31, 2025
546e22e
Refactor AfterAll block in Deny-SqlDscServerPermission integration te…
johlju Aug 31, 2025
a7ea287
Update Pester guidelines to consolidate requirements and best practic…
johlju Aug 31, 2025
475290e
Refactor integration tests to remove default parameter values and add…
johlju Aug 31, 2025
47586c2
Reorganize integration test commands to improve clarity and add missi…
johlju Aug 31, 2025
360c066
Remove redundant module removal command from AfterAll blocks in integ…
johlju Aug 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ applyTo: "**/*.[Tt]ests.ps1"
- Never test verbose messages, debug messages or parameter binding behavior
- Pass all mandatory parameters to avoid prompts

## Requirements
- Inside `It` blocks, assign unused return objects to `$null` (unless part of pipeline)
- Tested entity must be called from within the `It` blocks
- Keep results and assertions in same `It` block
- Avoid try-catch-finally for cleanup, use `AfterAll` or `AfterEach`
- Avoid unnecessary remove/recreate cycles

## Naming
- One `Describe` block per file matching the tested entity name
- `Context` descriptions start with 'When'
Expand Down Expand Up @@ -51,10 +58,6 @@ applyTo: "**/*.[Tt]ests.ps1"
- Keep scope close to usage context

## Best Practices
- Inside `It` blocks, assign unused return objects to `$null` (unless part of pipeline)
- Tested entity must be called from within the `It` blocks
- Keep results and assertions in same `It` block
- Cover all scenarios and code paths
- Use `BeforeEach` and `AfterEach` sparingly
- Avoid try-catch-finally for cleanup, use `AfterAll` or `AfterEach`
- Avoid unnecessary remove/recreate cycles
- Use `$PSDefaultParameterValues` only for Pester commands (`Describe`, `Context`, `It`, `Mock`, `Should`, `InModuleScope`)
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Enhanced workflow with proper environment variable configuration and DSCv3 verification.
- Fixed environment variable persistence by using $GITHUB_ENV instead of
job-level env declaration.
- `Grant-SqlDscServerPermission`
- Added new public command to grant server permissions to a principal (Login or ServerRole) on a SQL Server Database Engine instance.
- `Deny-SqlDscServerPermission`
- Added new public command to deny server permissions to a principal (Login or ServerRole).
- `Revoke-SqlDscServerPermission`
- Added new public command to revoke server permissions from a principal (Login or ServerRole).
- `Test-SqlDscServerPermission`
- Added new public command with Grant/Deny parameter sets (and `-WithGrant`) to test server permissions for a principal.
- `Assert-SqlDscLogin`
- Added new public command to validate that a specified SQL Server principal
is a login.
Expand Down
12 changes: 9 additions & 3 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -299,18 +299,24 @@ stages:
'tests/Integration/Commands/Test-SqlDscIsLoginEnabled.Integration.Tests.ps1'
'tests/Integration/Commands/New-SqlDscRole.Integration.Tests.ps1'
'tests/Integration/Commands/Get-SqlDscRole.Integration.Tests.ps1'
'tests/Integration/Commands/Remove-SqlDscRole.Integration.Tests.ps1'
'tests/Integration/Commands/Remove-SqlDscLogin.Integration.Tests.ps1'
'tests/Integration/Commands/Grant-SqlDscServerPermission.Integration.Tests.ps1'
'tests/Integration/Commands/Get-SqlDscServerPermission.Integration.Tests.ps1'
'tests/Integration/Commands/Test-SqlDscServerPermission.Integration.Tests.ps1'
'tests/Integration/Commands/Deny-SqlDscServerPermission.Integration.Tests.ps1'
'tests/Integration/Commands/Revoke-SqlDscServerPermission.Integration.Tests.ps1'
'tests/Integration/Commands/Get-SqlDscDatabase.Integration.Tests.ps1'
'tests/Integration/Commands/New-SqlDscDatabase.Integration.Tests.ps1'
'tests/Integration/Commands/Set-SqlDscDatabase.Integration.Tests.ps1'
'tests/Integration/Commands/Test-SqlDscDatabase.Integration.Tests.ps1'
'tests/Integration/Commands/Remove-SqlDscDatabase.Integration.Tests.ps1'
'tests/Integration/Commands/Get-SqlDscAgentAlert.Integration.Tests.ps1'
'tests/Integration/Commands/New-SqlDscAgentAlert.Integration.Tests.ps1'
'tests/Integration/Commands/Set-SqlDscAgentAlert.Integration.Tests.ps1'
'tests/Integration/Commands/Test-SqlDscAgentAlert.Integration.Tests.ps1'
# Group 8
'tests/Integration/Commands/Remove-SqlDscAgentAlert.Integration.Tests.ps1'
'tests/Integration/Commands/Remove-SqlDscDatabase.Integration.Tests.ps1'
'tests/Integration/Commands/Remove-SqlDscRole.Integration.Tests.ps1'
'tests/Integration/Commands/Remove-SqlDscLogin.Integration.Tests.ps1'

# Group 9
'tests/Integration/Commands/Uninstall-SqlDscServer.Integration.Tests.ps1'
Expand Down
63 changes: 63 additions & 0 deletions source/Enum/002.ServerPermission.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<#
.SYNOPSIS
The possible server permissions that can be granted, denied, or revoked.

.NOTES
The available permissions can be seen in the ServerPermission Class documentation:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.sqlserver.management.smo.serverpermission
#>
enum SqlServerPermission
{
# cSpell:ignore securables
AdministerBulkOperations = 1
AlterAnyAvailabilityGroup
AlterAnyConnection
AlterAnyCredential
AlterAnyDatabase
AlterAnyEndpoint
AlterAnyEventNotification
AlterAnyEventSession
AlterAnyEventSessionAddEvent
AlterAnyEventSessionAddTarget
AlterAnyEventSessionDisable
AlterAnyEventSessionDropEvent
AlterAnyEventSessionDropTarget
AlterAnyEventSessionEnable
AlterAnyEventSessionOption
AlterAnyLinkedServer
AlterAnyLogin
AlterAnyServerAudit
AlterAnyServerRole
AlterResources
AlterServerState
AlterSettings
AlterTrace
AuthenticateServer
ConnectAnyDatabase
ConnectSql
ControlServer
CreateAnyDatabase
CreateAnyEventSession
CreateAvailabilityGroup
CreateDdlEventNotification
CreateEndpoint
CreateLogin
CreateServerRole
CreateTraceEventNotification
DropAnyEventSession
ExternalAccessAssembly
ImpersonateAnyLogin
SelectAllUserSecurables
Shutdown
UnsafeAssembly
ViewAnyCryptographicallySecuredDefinition
ViewAnyDatabase
ViewAnyDefinition
ViewAnyErrorLog
ViewAnyPerformanceDefinition
ViewAnySecurityDefinition
ViewServerPerformanceState
ViewServerSecurityAudit
ViewServerSecurityState
ViewServerState
}
134 changes: 134 additions & 0 deletions source/Public/Deny-SqlDscServerPermission.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<#
.SYNOPSIS
Denies server permissions to a principal on a SQL Server Database Engine instance.

.DESCRIPTION
This command denies server permissions to an existing principal on a SQL Server
Database Engine instance. The principal can be specified as either a Login
object (from Get-SqlDscLogin) or a ServerRole object (from Get-SqlDscRole).

.PARAMETER Login
Specifies the Login object for which the permissions are denied.
This parameter accepts pipeline input.

.PARAMETER ServerRole
Specifies the ServerRole object for which the permissions are denied.
This parameter accepts pipeline input.

.PARAMETER Permission
Specifies the permissions to be denied. Specify multiple permissions by
providing an array of SqlServerPermission enum values.

.PARAMETER Force
Specifies that the permissions should be denied without any confirmation.

.OUTPUTS
None.

.EXAMPLE
$serverInstance = Connect-SqlDscDatabaseEngine
$login = $serverInstance | Get-SqlDscLogin -Name 'MyLogin'

Deny-SqlDscServerPermission -Login $login -Permission ConnectSql, ViewServerState

Denies the specified permissions to the login 'MyLogin'.

.EXAMPLE
$serverInstance = Connect-SqlDscDatabaseEngine
$role = $serverInstance | Get-SqlDscRole -Name 'MyRole'

$role | Deny-SqlDscServerPermission -Permission AlterAnyDatabase -Force

Denies the specified permissions to the role 'MyRole' without prompting for confirmation.

.NOTES
The Login or ServerRole object must come from the same SQL Server instance
where the permissions will be denied. If specifying `-ErrorAction 'SilentlyContinue'`
then the command will silently continue if any errors occur. If specifying
`-ErrorAction 'Stop'` the command will throw an error on any failure.
#>
function Deny-SqlDscServerPermission
{
[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.')]
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('AvoidThrowOutsideOfTry', '', Justification = 'Because the code throws based on an prior expression')]
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
[OutputType()]
param
(
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'Login')]
[Microsoft.SqlServer.Management.Smo.Login]
$Login,

[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ServerRole')]
[Microsoft.SqlServer.Management.Smo.ServerRole]
$ServerRole,

[Parameter(Mandatory = $true)]
[SqlServerPermission[]]
$Permission,

[Parameter()]
[System.Management.Automation.SwitchParameter]
$Force
)

process
{
if ($Force.IsPresent -and -not $Confirm)
{
$ConfirmPreference = 'None'
}

# Determine which principal object we're working with
if ($PSCmdlet.ParameterSetName -eq 'Login')
{
$principalName = $Login.Name
$serverObject = $Login.Parent
}
else
{
$principalName = $ServerRole.Name
$serverObject = $ServerRole.Parent
}

$verboseDescriptionMessage = $script:localizedData.ServerPermission_Deny_ShouldProcessVerboseDescription -f $principalName, $serverObject.InstanceName, ($Permission -join ',')
$verboseWarningMessage = $script:localizedData.ServerPermission_Deny_ShouldProcessVerboseWarning -f $principalName
$captionMessage = $script:localizedData.ServerPermission_Deny_ShouldProcessCaption

if ($PSCmdlet.ShouldProcess($verboseDescriptionMessage, $verboseWarningMessage, $captionMessage))
{
# Convert enum array to ServerPermissionSet object
$permissionSet = [Microsoft.SqlServer.Management.Smo.ServerPermissionSet]::new()
foreach ($permissionName in $Permission)
{
$permissionSet.$permissionName = $true
}

# Get the permissions names that are set to $true in the ServerPermissionSet.
$permissionName = $permissionSet |
Get-Member -MemberType 'Property' |
Select-Object -ExpandProperty 'Name' |
Where-Object -FilterScript {
$permissionSet.$_
}

try
{
$serverObject.Deny($permissionSet, $principalName)
}
catch
{
$errorMessage = $script:localizedData.ServerPermission_Deny_FailedToDenyPermission -f $principalName, $serverObject.InstanceName

$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
$errorMessage,
'DSDSP0001', # cSpell: disable-line
[System.Management.Automation.ErrorCategory]::InvalidOperation,
$principalName
)
)
}
}
}
}
Loading
Loading