1+ [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute (' PSUseDeclaredVarsMoreThanAssignments' , ' ' , Justification = ' Suppressing this rule because Script Analyzer does not understand Pester syntax.' )]
2+ param ()
3+
4+ BeforeDiscovery {
5+ try
6+ {
7+ if (-not (Get-Module - Name ' DscResource.Test' ))
8+ {
9+ # Assumes dependencies have been resolved, so if this module is not available, run 'noop' task.
10+ if (-not (Get-Module - Name ' DscResource.Test' - ListAvailable))
11+ {
12+ # Redirect all streams to $null, except the error stream (stream 2)
13+ & " $PSScriptRoot /../../../build.ps1" - Tasks ' noop' 3>&1 4>&1 5>&1 6>&1 > $null
14+ }
15+
16+ # If the dependencies have not been resolved, this will throw an error.
17+ Import-Module - Name ' DscResource.Test' - Force - ErrorAction ' Stop'
18+ }
19+ }
20+ catch [System.IO.FileNotFoundException ]
21+ {
22+ throw ' DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.'
23+ }
24+ }
25+
26+ BeforeAll {
27+ $script :moduleName = ' SqlServerDsc'
28+
29+ Import-Module - Name $script :moduleName - Force - ErrorAction ' Stop'
30+ }
31+
32+ Describe ' Get-SqlDscDatabasePermission' - Tag @ (' Integration_SQL2017' , ' Integration_SQL2019' , ' Integration_SQL2022' ) {
33+ BeforeAll {
34+ # Starting the named instance SQL Server service prior to running tests.
35+ Start-Service - Name ' MSSQL$DSCSQLTEST' - Verbose - ErrorAction ' Stop'
36+
37+ $script :mockInstanceName = ' DSCSQLTEST'
38+
39+ $mockSqlAdministratorUserName = ' SqlAdmin' # Using computer name as NetBIOS name throw exception.
40+ $mockSqlAdministratorPassword = ConvertTo-SecureString - String ' P@ssw0rd1' - AsPlainText - Force
41+
42+ $script :mockSqlAdminCredential = [System.Management.Automation.PSCredential ]::new($mockSqlAdministratorUserName , $mockSqlAdministratorPassword )
43+
44+ $script :serverObject = Connect-SqlDscDatabaseEngine - InstanceName $script :mockInstanceName - Credential $script :mockSqlAdminCredential
45+
46+ # Create a test database for the integration tests
47+ $script :testDatabaseName = ' SqlDscDatabasePermissionTest_' + (Get-Random )
48+ $null = New-SqlDscDatabase - ServerObject $script :serverObject - Name $script :testDatabaseName - Force - ErrorAction ' Stop'
49+
50+ # Create a test user in the database for permission testing
51+ $script :testUserName = ' SqlDscTestUser_' + (Get-Random )
52+ $testUserSql = " USE [$ ( $script :testDatabaseName ) ]; CREATE USER [$ ( $script :testUserName ) ] WITHOUT LOGIN;"
53+ Invoke-SqlDscQuery - ServerObject $script :serverObject - Database $script :testDatabaseName - Query $testUserSql - ErrorAction ' Stop'
54+
55+ # Grant some permissions to the test user for testing
56+ $grantPermissionSql = " USE [$ ( $script :testDatabaseName ) ]; GRANT CONNECT, SELECT TO [$ ( $script :testUserName ) ];"
57+ Invoke-SqlDscQuery - ServerObject $script :serverObject - Database $script :testDatabaseName - Query $grantPermissionSql - ErrorAction ' Stop'
58+ }
59+
60+ AfterAll {
61+ # Clean up test database (this will also remove the test user)
62+ $testDatabase = Get-SqlDscDatabase - ServerObject $script :serverObject - Name $script :testDatabaseName - ErrorAction ' SilentlyContinue'
63+ if ($testDatabase )
64+ {
65+ $null = Remove-SqlDscDatabase - DatabaseObject $testDatabase - Force - ErrorAction ' Stop'
66+ }
67+
68+ Disconnect-SqlDscDatabaseEngine - ServerObject $script :serverObject
69+
70+ # Stop the named instance SQL Server service to save memory on the build worker.
71+ Stop-Service - Name ' MSSQL$DSCSQLTEST' - Verbose - ErrorAction ' Stop'
72+ }
73+
74+ Context ' When connecting to SQL Server instance' {
75+ Context ' When getting permissions for valid database principals' {
76+ It ' Should return permissions for dbo user in master database' {
77+ $result = Get-SqlDscDatabasePermission - ServerObject $script :serverObject - DatabaseName ' master' - Name ' dbo'
78+
79+ $result | Should -Not - BeNullOrEmpty
80+ $result | Should - BeOfType [Microsoft.SqlServer.Management.Smo.DatabasePermissionInfo ]
81+ }
82+
83+ It ' Should return permissions for dbo user in master database using pipeline' {
84+ $result = $script :serverObject | Get-SqlDscDatabasePermission - DatabaseName ' master' - Name ' dbo'
85+
86+ $result | Should -Not - BeNullOrEmpty
87+ $result | Should - BeOfType [Microsoft.SqlServer.Management.Smo.DatabasePermissionInfo ]
88+ }
89+
90+ It ' Should return permissions for public role in master database' {
91+ $result = Get-SqlDscDatabasePermission - ServerObject $script :serverObject - DatabaseName ' master' - Name ' public'
92+
93+ $result | Should -Not - BeNullOrEmpty
94+ $result | Should - BeOfType [Microsoft.SqlServer.Management.Smo.DatabasePermissionInfo ]
95+ }
96+
97+ It ' Should return permissions for test user in test database' {
98+ $result = Get-SqlDscDatabasePermission - ServerObject $script :serverObject - DatabaseName $script :testDatabaseName - Name $script :testUserName
99+
100+ $result | Should -Not - BeNullOrEmpty
101+ $result | Should - BeOfType [Microsoft.SqlServer.Management.Smo.DatabasePermissionInfo ]
102+
103+ # Verify that the Connect and Select permissions we granted are present
104+ $connectPermission = $result | Where-Object { $_.PermissionType.Connect -eq $true }
105+ $selectPermission = $result | Where-Object { $_.PermissionType.Select -eq $true }
106+
107+ $connectPermission | Should -Not - BeNullOrEmpty - Because ' Connect permission should have been granted to test user'
108+ $connectPermission.PermissionState | Should - Be ' Grant'
109+
110+ $selectPermission | Should -Not - BeNullOrEmpty - Because ' Select permission should have been granted to test user'
111+ $selectPermission.PermissionState | Should - Be ' Grant'
112+ }
113+ }
114+
115+ Context ' When getting permissions for invalid principals' {
116+ It ' Should throw error for non-existent database with ErrorAction Stop' {
117+ { Get-SqlDscDatabasePermission - ServerObject $script :serverObject - DatabaseName ' NonExistentDatabase123' - Name ' dbo' - ErrorAction ' Stop' } |
118+ Should - Throw
119+ }
120+
121+ It ' Should return null for non-existent database with ErrorAction SilentlyContinue' {
122+ $result = Get-SqlDscDatabasePermission - ServerObject $script :serverObject - DatabaseName ' NonExistentDatabase123' - Name ' dbo' - ErrorAction ' SilentlyContinue'
123+
124+ $result | Should - BeNullOrEmpty
125+ }
126+
127+ It ' Should throw error for non-existent principal with ErrorAction Stop' {
128+ { Get-SqlDscDatabasePermission - ServerObject $script :serverObject - DatabaseName ' master' - Name ' NonExistentUser123' - ErrorAction ' Stop' } |
129+ Should - Throw
130+ }
131+
132+ It ' Should return null for non-existent principal with ErrorAction SilentlyContinue' {
133+ $result = Get-SqlDscDatabasePermission - ServerObject $script :serverObject - DatabaseName ' master' - Name ' NonExistentUser123' - ErrorAction ' SilentlyContinue'
134+
135+ $result | Should - BeNullOrEmpty
136+ }
137+ }
138+
139+ Context ' When verifying permission properties' {
140+ BeforeAll {
141+ # Get permissions for a known principal that should have permissions
142+ $script :testPermissions = Get-SqlDscDatabasePermission - ServerObject $script :serverObject - DatabaseName $script :testDatabaseName - Name $script :testUserName
143+ }
144+
145+ It ' Should return DatabasePermissionInfo objects with PermissionState property' {
146+ $script :testPermissions | Should -Not - BeNullOrEmpty
147+
148+ foreach ($permission in $script :testPermissions ) {
149+ $permission.PermissionState | Should - BeIn @ (' Grant' , ' Deny' , ' GrantWithGrant' )
150+ }
151+ }
152+
153+ It ' Should return DatabasePermissionInfo objects with PermissionType property' {
154+ $script :testPermissions | Should -Not - BeNullOrEmpty
155+
156+ foreach ($permission in $script :testPermissions ) {
157+ $permission.PermissionType | Should -Not - BeNullOrEmpty
158+ $permission.PermissionType | Should - BeOfType [Microsoft.SqlServer.Management.Smo.DatabasePermissionSet ]
159+ }
160+ }
161+
162+ It ' Should return DatabasePermissionInfo objects with Grantee property' {
163+ $script :testPermissions | Should -Not - BeNullOrEmpty
164+
165+ foreach ($permission in $script :testPermissions ) {
166+ $permission.Grantee | Should - Be $script :testUserName
167+ }
168+ }
169+ }
170+
171+ Context ' When working with built-in database roles' {
172+ It ' Should return permissions for db_datareader role' {
173+ # Note: The command excludes fixed roles by default, so this should return null or empty
174+ $result = Get-SqlDscDatabasePermission - ServerObject $script :serverObject - DatabaseName $script :testDatabaseName - Name ' db_datareader' - ErrorAction ' SilentlyContinue'
175+
176+ # Fixed roles are excluded by default, so result should be null
177+ $result | Should - BeNullOrEmpty
178+ }
179+
180+ It ' Should work with non-fixed database roles when they exist' {
181+ # Create a custom database role for testing
182+ $customRoleName = ' TestRole_' + (Get-Random )
183+ $createRoleSql = " USE [$ ( $script :testDatabaseName ) ]; CREATE ROLE [$customRoleName ];"
184+ Invoke-SqlDscQuery - ServerObject $script :serverObject - Database $script :testDatabaseName - Query $createRoleSql - ErrorAction ' Stop'
185+
186+ try
187+ {
188+ # Grant a permission to the custom role
189+ $grantRolePermissionSql = " USE [$ ( $script :testDatabaseName ) ]; GRANT CONNECT TO [$customRoleName ];"
190+ Invoke-SqlDscQuery - ServerObject $script :serverObject - Database $script :testDatabaseName - Query $grantRolePermissionSql - ErrorAction ' Stop'
191+
192+ # Test getting permissions for the custom role
193+ $result = Get-SqlDscDatabasePermission - ServerObject $script :serverObject - DatabaseName $script :testDatabaseName - Name $customRoleName
194+
195+ $result | Should -Not - BeNullOrEmpty
196+ $result | Should - BeOfType [Microsoft.SqlServer.Management.Smo.DatabasePermissionInfo ]
197+
198+ # Verify the Connect permission we granted is present
199+ $connectPermission = $result | Where-Object { $_.PermissionType.Connect -eq $true }
200+ $connectPermission | Should -Not - BeNullOrEmpty
201+ $connectPermission.PermissionState | Should - Be ' Grant'
202+ }
203+ finally
204+ {
205+ # Clean up the custom role
206+ $dropRoleSql = " USE [$ ( $script :testDatabaseName ) ]; DROP ROLE [$customRoleName ];"
207+ Invoke-SqlDscQuery - ServerObject $script :serverObject - Database $script :testDatabaseName - Query $dropRoleSql - ErrorAction ' SilentlyContinue'
208+ }
209+ }
210+ }
211+ }
212+ }
0 commit comments