-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSqlSafe.sql
More file actions
780 lines (698 loc) · 24 KB
/
SqlSafe.sql
File metadata and controls
780 lines (698 loc) · 24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
/******************************************************************************
* SQL Server Security Assessment - Community Edition
* Logic & Engine by Andreas Wolter (MCSM)
* Version: 2026.2
* Scope: High-Level Security Indicators
* License: Sarpedon Community License (See LICENSE.md)
* Resources: https://www.SarpedonQualityLab.US/resources
* * DESCRIPTION:
* This script collects metadata and executes core security checks to identify
* high-level indicators of risk. It is a foundational baseline designed for
* community and internal organizational use.
*
* DISCLAIMER:
* This tool is provided "as is" for informational purposes only. It identifies
* high-level indicators of risk and does not constitute a comprehensive security
* audit, legal advice, or a guarantee of security. The author and Sarpedon
* Quality Lab LLC assume no liability for any inaccuracies, system impacts,
* or security incidents occurring after its use. Use at your own risk.
*
* --- DO NOT EDIT !
* --- The Assessment will be blocked if the file has been manipulated !
* ---
******************************************************************************/
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET NOCOUNT ON;
SELECT
'002' AS [Check ID],
'Authentication Mode' AS [Check Name],
CASE SERVERPROPERTY('IsIntegratedSecurityOnly')
WHEN 1 THEN 'Windows Authentication'
WHEN 0 THEN 'Windows and SQL Server Authentication (Mixed Mode)'
ELSE 'Unknown'
END AS Result1,
SERVERPROPERTY('IsIntegratedSecurityOnly')AS Result2,
(
SELECT SERVERPROPERTY('IsExternalAuthenticationOnly') AS IsExternalAuthenticationOnly
, SERVERPROPERTY('IsExternalGovernanceEnabled') AS IsExternalGovernanceEnabled
FOR XML PATH('AdditionalInfo'), TYPE
) AS AdditionalInfo
;
GO
WITH Connections AS
(
SELECT *
FROM sys.dm_exec_connections
WHERE protocol_type <> 'Database Mirroring'
AND net_transport <> 'Shared memory'
)
SELECT
'003' AS [Check ID],
'SQL Authentication usage' AS [Check Name],
SUM(CASE WHEN auth_scheme = 'SQL' THEN 1 ELSE 0 END) AS Result1,
CAST(
100.0 * SUM(CASE WHEN auth_scheme = 'SQL' THEN 1 ELSE 0 END)
/ NULLIF(COUNT(*), 0)
AS DECIMAL(5,2)
) AS Result2
FROM Connections;
GO
WITH Connections AS
(
SELECT *
FROM sys.dm_exec_connections
WHERE protocol_type <> 'Database Mirroring'
AND net_transport <> 'Shared memory'
)
SELECT
'004' AS [Check ID],
'NTLM Authentication usage' AS [Check Name],
SUM(CASE WHEN auth_scheme = 'NTLM' THEN 1 ELSE 0 END) AS Result1,
CAST(
100.0 * SUM(CASE WHEN auth_scheme = 'NTLM' THEN 1 ELSE 0 END)
/ NULLIF(COUNT(*), 0)
AS DECIMAL(5,2)
) AS Result2
FROM Connections;
GO
SELECT
'008' AS [Check ID],
'SA Login Name' AS [Check Name],
name AS Result1,
modify_date AS Result2
FROM sys.server_principals
WHERE sid = 0x01;
GO
SELECT
'010' AS [Check ID],
'Sysadmin-members individual accounts' AS [Check Name],
server_principals.type_desc AS Result1,
name AS Result2,
(
SELECT
is_disabled,
create_date
FOR XML PATH('AdditionalInfo'), TYPE
) AS AdditionalInfo
FROM sys.server_role_members AS server_role_members
JOIN sys.server_principals AS server_principals
ON server_role_members.member_principal_id = server_principals.principal_id
WHERE server_role_members.role_principal_id = SUSER_ID('sysadmin')
AND server_principals.name <> SUSER_SNAME(0x01)
AND server_principals.name NOT IN ('NT SERVICE\SQLWriter', 'NT SERVICE\Winmgmt')
AND server_principals.type NOT IN ('G', 'C', 'K', 'X')
ORDER BY server_principals.type_desc;
GO
SELECT
'015' AS [Check ID],
'Powerful server role membership' AS [Check Name],
serverrole.name AS Result1,
rolemember.name AS Result2,
(
SELECT
rolemember.type_desc AS MemberType,
rolemember.create_date,
rolemember.modify_date,
rolemember.is_disabled
FOR XML PATH('AdditionalInfo'), TYPE
) AS AdditionalInfo
FROM sys.server_role_members AS rm
INNER JOIN sys.server_principals AS serverrole
ON rm.role_principal_id = serverrole.principal_id
INNER JOIN sys.server_principals AS rolemember
ON rm.member_principal_id = rolemember.principal_id
WHERE serverrole.name IN (
N'serveradmin',
N'securityadmin',
N'processadmin',
N'setupadmin',
N'bulkadmin',
N'diskadmin',
N'dbcreator'
)
ORDER BY serverrole.name, rolemember.name;
GO
SELECT
'026' AS [Check ID],
'Server permissions granted to Logins' AS [Check Name],
server_principals.name AS Result1,
server_permissions.permission_name AS Result2,
(
SELECT
server_principals.is_disabled,
server_principals.type_desc AS LoginType,
server_permissions.state_desc,
grantor.name AS grantor_name,
server_permissions.class_desc,
server_permissions.major_id,
dm_server_services.service_account
FOR XML PATH('AdditionalInfo'), TYPE
) AS AdditionalInfo
FROM sys.server_permissions AS server_permissions
INNER JOIN sys.server_principals AS server_principals
ON server_permissions.grantee_principal_id = server_principals.principal_id
INNER JOIN sys.server_principals AS grantor
ON server_permissions.grantor_principal_id = grantor.principal_id
LEFT JOIN sys.dm_server_services AS dm_server_services
ON dm_server_services.service_account = server_principals.name
WHERE
NOT (
server_permissions.class_desc = 'ENDPOINT'
AND server_permissions.major_id = 5
AND server_permissions.permission_name = 'CONNECT'
)
AND dm_server_services.service_account IS NULL
AND server_principals.is_disabled = 0
AND NOT (
(server_principals.name = N'NT SERVICE\SQLWriter' AND server_permissions.permission_name = N'CONNECT SQL')
OR (server_principals.name = N'NT SERVICE\Winmgmt' AND server_permissions.permission_name = N'CONNECT SQL')
OR (server_principals.name = N'public' AND server_permissions.permission_name = N'CONNECT')
OR (server_principals.name = N'##MS_AgentSigningCertificate##' AND server_permissions.permission_name = N'CONNECT SQL')
OR (server_principals.name = N'##MS_PolicyEventProcessingLogin##' AND server_permissions.permission_name = N'CONNECT SQL')
OR (server_principals.name = N'##MS_PolicySigningCertificate##' AND server_permissions.permission_name = N'CONTROL SERVER')
OR (server_principals.name = N'##MS_PolicySigningCertificate##' AND server_permissions.permission_name = N'VIEW ANY DEFINITION')
OR (server_principals.name = N'##MS_PolicyTsqlExecutionLogin##' AND server_permissions.permission_name = N'CONNECT SQL')
OR (server_principals.name = N'##MS_PolicyTsqlExecutionLogin##' AND server_permissions.permission_name = N'VIEW ANY DEFINITION')
OR (server_principals.name = N'##MS_PolicyTsqlExecutionLogin##' AND server_permissions.permission_name = N'VIEW SERVER STATE')
OR (server_principals.name = N'##MS_SmoExtendedSigningCertificate##' AND server_permissions.permission_name = N'VIEW ANY DEFINITION')
OR (server_principals.name = N'##MS_SQLAuthenticatorCertificate##' AND server_permissions.permission_name = N'AUTHENTICATE SERVER')
OR (server_principals.name = N'##MS_SQLReplicationSigningCertificate##' AND server_permissions.permission_name = N'AUTHENTICATE SERVER')
OR (server_principals.name = N'##MS_SQLReplicationSigningCertificate##' AND server_permissions.permission_name = N'VIEW ANY DEFINITION')
OR (server_principals.name = N'##MS_SQLReplicationSigningCertificate##' AND server_permissions.permission_name = N'VIEW SERVER STATE')
OR (server_principals.name = N'##MS_SQLResourceSigningCertificate##' AND server_permissions.permission_name = N'VIEW ANY DEFINITION')
)
ORDER BY server_principals.name, server_permissions.permission_name;
GO
SELECT
'027' AS [Check ID],
'Custom server roles without members' AS [Check Name],
name AS Result1,
principal_id AS Result2,
(
SELECT
create_date,
modify_date
FOR XML PATH('AdditionalInfo'), TYPE
) AS AdditionalInfo
FROM sys.server_principals
WHERE
type_desc = 'SERVER_ROLE'
AND is_fixed_role = 0
AND name <> 'public'
AND NOT EXISTS (
SELECT 1
FROM sys.server_role_members AS rm
WHERE rm.role_principal_id = principal_id
)
ORDER BY name;
GO
SELECT
'028' AS [Check ID],
'Databases with Trustworthy property set' AS [Check Name],
name AS Result1,
is_trustworthy_on AS Result2,
(
SELECT
state_desc AS State,
create_date,
database_id
FOR XML PATH('AdditionalInfo'), TYPE
) AS AdditionalInfo
FROM sys.databases
WHERE is_trustworthy_on = 1
AND name <> 'msdb'
ORDER BY name;
GO
SELECT
'031' AS [Check ID],
'Cross Database ownership chaining setting' AS [Check Name],
name Result1,
CAST(is_db_chaining_on AS INT) AS Result2,
(
SELECT
state_desc AS State,
create_date,
database_id
FOR XML PATH('AdditionalInfo'), TYPE
) AS AdditionalInfo
FROM sys.databases
WHERE is_db_chaining_on = 1
AND name NOT IN ('master', 'msdb', 'tempdb')
ORDER BY name;
GO
SELECT
'034' AS [Check ID],
'XP_cmdshell setting' AS [Check Name],
value AS Result1,
value_in_use AS Result2
FROM sys.configurations
WHERE name = 'xp_cmdshell'
AND (value = 1 OR value_in_use = 1)
;
GO
SELECT
'036' AS [Check ID],
'Ad Hoc distributed queries setting' AS [Check Name],
name AS Result1,
value AS Result2,
(
SELECT
value_in_use AS RunningValue,
description
FOR XML PATH('AdditionalInfo'), TYPE
) AS AdditionalInfo
FROM sys.configurations
WHERE name = 'Ad Hoc Distributed Queries'
AND (value = 1 OR value_in_use = 1)
;
GO
SELECT
'038' AS [Check ID],
'OLE Automation Procedures setting' AS [Check Name],
name AS Result1,
value AS Result2,
(
SELECT
value_in_use AS RunningValue,
description
FOR XML PATH('AdditionalInfo'), TYPE
) AS AdditionalInfo
FROM sys.configurations
WHERE name = 'Ole Automation Procedures'
AND (value = 1 OR value_in_use = 1)
;
GO
DECLARE @ValidateLogins TABLE
(
SID varbinary(85),
OrphanedUser SYSNAME
);
INSERT INTO @ValidateLogins
EXEC sp_validatelogins;
SELECT
'046' AS [Check ID],
'Orphaned Windows Logins' AS [Check Name],
SID AS Result1,
OrphanedUser AS Result2
FROM @ValidateLogins;
GO
DECLARE @NumberOfErrorLogs INT = NULL;
DECLARE @RegReadResult INT = NULL;
BEGIN TRY
EXEC @RegReadResult = master.dbo.xp_instance_regread
@rootkey = 'HKEY_LOCAL_MACHINE',
@key = N'Software\Microsoft\MSSQLServer\MSSQLServer',
@value_name = 'NumberOfErrorLogs',
@value = @NumberOfErrorLogs OUTPUT;
END TRY
BEGIN CATCH
SET @RegReadResult = -1;
SET @NumberOfErrorLogs = NULL;
END CATCH;
SELECT
'050' AS [Check ID],
'Number of Error Logs kept' AS [Check Name],
CASE
WHEN @RegReadResult <> 0 OR @NumberOfErrorLogs IS NULL THEN 'Not set. Using default.'
ELSE 'custom'
END AS Result1,
CASE
WHEN @RegReadResult <> 0 OR @NumberOfErrorLogs IS NULL THEN 7
ELSE @NumberOfErrorLogs
END AS Result2;
GO
IF CAST(LEFT(CAST(SERVERPROPERTY('ProductVersion') AS varchar(50)),
CHARINDEX('.', CAST(SERVERPROPERTY('ProductVersion') AS varchar(50))) - 1) AS int) >= 10
BEGIN
DECLARE @sql nvarchar(max) = N'
;WITH AllAuditActions AS
(
SELECT ''AUDIT_CHANGE_GROUP'' AS AuditActionName UNION ALL
SELECT ''DBCC_GROUP'' UNION ALL
SELECT ''EXTGOV_OPERATION_GROUP'' UNION ALL
SELECT ''SERVER_OBJECT_CHANGE_GROUP'' UNION ALL
SELECT ''SERVER_OBJECT_OWNERSHIP_CHANGE_GROUP'' UNION ALL
SELECT ''SERVER_OBJECT_PERMISSION_CHANGE_GROUP'' UNION ALL
SELECT ''SERVER_OPERATION_GROUP'' UNION ALL
SELECT ''SERVER_PERMISSION_CHANGE_GROUP'' UNION ALL
SELECT ''SERVER_PRINCIPAL_CHANGE_GROUP'' UNION ALL
SELECT ''SERVER_PRINCIPAL_IMPERSONATION_GROUP'' UNION ALL
SELECT ''SERVER_ROLE_MEMBER_CHANGE_GROUP'' UNION ALL
SELECT ''SERVER_STATE_CHANGE_GROUP'' UNION ALL
SELECT ''LOGIN_CHANGE_PASSWORD_GROUP'' UNION ALL
SELECT ''FAILED_LOGIN_GROUP'' UNION ALL
SELECT ''SUCCESSFUL_LOGIN_GROUP'' UNION ALL
SELECT ''FAILED_DATABASE_AUTHENTICATION_GROUP'' UNION ALL
SELECT ''DATABASE_CHANGE_GROUP'' UNION ALL
SELECT ''DATABASE_OWNERSHIP_CHANGE_GROUP'' UNION ALL
SELECT ''DATABASE_OBJECT_OWNERSHIP_CHANGE_GROUP'' UNION ALL
SELECT ''DATABASE_OBJECT_PERMISSION_CHANGE_GROUP'' UNION ALL
SELECT ''DATABASE_ROLE_MEMBER_CHANGE_GROUP'' UNION ALL
SELECT ''DATABASE_PRINCIPAL_CHANGE_GROUP'' UNION ALL
SELECT ''DATABASE_PRINCIPAL_IMPERSONATION_GROUP'' UNION ALL
SELECT ''APPLICATION_ROLE_CHANGE_PASSWORD_GROUP''
),
ConfiguredAuditDetails AS
(
SELECT
sa.name AS AuditName,
sa.is_state_enabled AS AuditEnabled,
sas.name AS AuditSpecificationName,
sas.is_state_enabled AS SpecificationEnabled,
sasd.audit_action_name AS AuditActionName
FROM sys.server_audit_specifications AS sas
JOIN sys.server_audits AS sa
ON sas.audit_guid = sa.audit_guid
JOIN sys.server_audit_specification_details AS sasd
ON sas.server_specification_id = sasd.server_specification_id
)
SELECT
''059'' AS [Check ID],
''Security Auditing minimal setup'' AS [Check Name],
aaa.AuditActionName AS Result1,
CASE
WHEN cad.AuditActionName IS NULL THEN ''Not Covered''
WHEN cad.AuditEnabled = 0 AND cad.SpecificationEnabled = 0 THEN ''Covered but Audit AND Specification Disabled''
WHEN cad.AuditEnabled = 0 THEN ''Covered but Audit Disabled''
WHEN cad.SpecificationEnabled = 0 THEN ''Covered but Specification Disabled''
END AS Result2,
(
SELECT
cad.AuditName,
cad.AuditEnabled,
cad.AuditSpecificationName,
cad.SpecificationEnabled
FOR XML PATH(''AdditionalInfo''), TYPE
) AS AdditionalInfo
FROM AllAuditActions AS aaa
LEFT JOIN ConfiguredAuditDetails AS cad
ON aaa.AuditActionName = cad.AuditActionName
WHERE cad.AuditActionName IS NULL
OR cad.AuditEnabled = 0
OR cad.SpecificationEnabled = 0
ORDER BY aaa.AuditActionName;
';
EXEC sys.sp_executesql @sql;
END;
GO
DECLARE @InstanceName NVARCHAR(128);
DECLARE @RegPath NVARCHAR(400);
DECLARE @AuditLevel INT;
SET @InstanceName = CAST(SERVERPROPERTY('InstanceName') AS NVARCHAR(128));
SET @RegPath = N'SOFTWARE\Microsoft\MSSQLServer\MSSQLServer';
EXEC master.dbo.xp_instance_regread
@rootkey = 'HKEY_LOCAL_MACHINE',
@key = @RegPath,
@value_name = 'AuditLevel',
@value = @AuditLevel OUTPUT;
SELECT
'069' AS [Check ID],
'Basic Login-Failure logging status' AS [Check Name],
@AuditLevel AS Result1,
CASE @AuditLevel
WHEN 0 THEN 'None'
WHEN 2 THEN 'Failed logins only'
WHEN 1 THEN 'Successful logins only'
WHEN 3 THEN 'Both successful and failed logins'
ELSE 'Unknown'
END AS Result2
;
GO
DECLARE @DatabaseOwners TABLE
(
dbname sysname NOT NULL
, matched_owner nvarchar(128) NULL
);
DECLARE @PreparedOwners TABLE
(
database_id int NULL
, dbname sysname NOT NULL
, principal_id int NULL
, principal_name sysname NULL
, matched_owner nvarchar(128) NULL
, server_principal_type nvarchar(60) NULL
, db_owner_valid varchar(20) NOT NULL
, powerful_server_role_membership varchar(30) NULL
);
INSERT INTO @DatabaseOwners
EXEC sp_MSforeachdb '
SELECT
''?'' AS dbname
, SUSER_SNAME(database_principals.sid) AS matched_owner
FROM [?].sys.database_principals
WHERE database_principals.name = ''dbo''
';
INSERT INTO @PreparedOwners
(
database_id
, dbname
, principal_id
, principal_name
, matched_owner
, server_principal_type
, db_owner_valid
, powerful_server_role_membership
)
SELECT
d.database_id
, dbo_src.dbname
, sp.principal_id
, sp.name AS principal_name
, dbo_src.matched_owner
, sp.type_desc AS server_principal_type
, CASE
WHEN dbo_src.matched_owner IS NULL THEN 'not valid (!)'
ELSE 'valid'
END AS db_owner_valid
, CASE
WHEN srm.role_principal_id = 3 THEN 'sysadmin'
WHEN srm.role_principal_id = 4 THEN 'securityadmin'
WHEN srm.role_principal_id = 5 THEN 'serveradmin'
WHEN srm.role_principal_id = 6 THEN 'setupadmin'
WHEN srm.role_principal_id = 7 THEN 'processadmin'
WHEN srm.role_principal_id = 8 THEN 'diskadmin'
WHEN srm.role_principal_id = 9 THEN 'dbcreator'
WHEN srm.role_principal_id = 10 THEN 'bulkadmin'
ELSE NULL
END AS powerful_server_role_membership
FROM @DatabaseOwners AS dbo_src
LEFT JOIN sys.databases AS d
ON dbo_src.dbname COLLATE SQL_Latin1_General_CP1_CI_AS
= d.name COLLATE SQL_Latin1_General_CP1_CI_AS
LEFT JOIN sys.server_principals AS sp
ON d.owner_sid = sp.sid
LEFT JOIN sys.server_role_members AS srm
ON sp.principal_id = srm.member_principal_id;
SELECT
'072' AS [Check ID]
, 'Database Owner sysadmin' AS [Check Name]
, dbname AS Result1
, principal_name AS Result2
, (
SELECT
server_principal_type AS [Principal_Type],
db_owner_valid,
powerful_server_role_membership
FOR XML PATH('AdditionalInfo'), TYPE
) AS AdditionalInfo
FROM @PreparedOwners
WHERE powerful_server_role_membership = 'sysadmin'
AND dbname NOT IN ('master', 'msdb', 'tempdb', 'model')
ORDER BY database_id ASC;
SELECT
'078' AS [Check ID]
, 'Database Owner Windows Account' AS [Check Name]
, dbname AS Result1
, principal_name AS Result2
, (
SELECT
server_principal_type AS [Principal_Type],
db_owner_valid,
powerful_server_role_membership
FOR XML PATH('AdditionalInfo'), TYPE
) AS AdditionalInfo
FROM @PreparedOwners
WHERE server_principal_type = 'WINDOWS_LOGIN'
ORDER BY database_id ASC;
SELECT
'155' AS [Check ID],
'Invalid database owner' AS [Check Name],
dbname AS Result1,
matched_owner AS Result2,
(
SELECT
server_principal_type AS [Principal_Type],
db_owner_valid,
powerful_server_role_membership
FOR XML PATH('AdditionalInfo'), TYPE
) AS AdditionalInfo
FROM @PreparedOwners
WHERE db_owner_valid = 'not valid (!)'
ORDER BY database_id ASC;
GO
SELECT
'079' AS [Check ID],
'SA Login State' AS [Check Name],
name AS Result1,
is_disabled AS Result2,
(
SELECT
modify_date
FOR XML PATH('AdditionalInfo'), TYPE
) AS AdditionalInfo
FROM sys.server_principals
WHERE sid = 0x01;
GO
DECLARE @Check113 TABLE
(
[Check ID] varchar(10)
, [Check Name] nvarchar(200)
, Result1 sysname
, Result2 int
, AdditionalInfo xml
);
DECLARE @DatabaseName113 sysname;
DECLARE @Sql113 nvarchar(max);
DECLARE db_cursor_113 CURSOR LOCAL FAST_FORWARD FOR
SELECT name
FROM sys.databases
WHERE database_id > 4
AND state_desc = 'ONLINE';
OPEN db_cursor_113;
FETCH NEXT FROM db_cursor_113 INTO @DatabaseName113;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @Sql113 = N'
SELECT
''113''
, ''Custom database roles without members''
, roles.name
, roles.principal_id
, (
SELECT
''' + REPLACE(@DatabaseName113, '''', '''''') + ''' AS DatabaseName
, roles.create_date
, roles.owning_principal_id
, owners.name
FOR XML PATH(''AdditionalInfo''), TYPE
)
FROM ' + QUOTENAME(@DatabaseName113) + N'.sys.database_principals AS roles
LEFT JOIN ' + QUOTENAME(@DatabaseName113) + N'.sys.database_role_members AS members
ON roles.principal_id = members.role_principal_id
LEFT JOIN ' + QUOTENAME(@DatabaseName113) + N'.sys.database_principals AS owners
ON roles.owning_principal_id = owners.principal_id
WHERE roles.type = ''R''
AND members.member_principal_id IS NULL
AND roles.is_fixed_role = 0
AND roles.name <> ''public'';';
INSERT INTO @Check113
EXEC sys.sp_executesql @Sql113;
FETCH NEXT FROM db_cursor_113 INTO @DatabaseName113;
END
CLOSE db_cursor_113;
DEALLOCATE db_cursor_113;
SELECT * FROM @Check113;
GO
DECLARE @Check129 TABLE
(
[Check ID] varchar(10)
, [Check Name] nvarchar(200)
, Result1 sysname
, Result2 nvarchar(60)
, AdditionalInfo xml
);
DECLARE @DatabaseName129 sysname;
DECLARE @Sql129 nvarchar(max);
DECLARE db_cursor_129 CURSOR LOCAL FAST_FORWARD FOR
SELECT name
FROM sys.databases
WHERE database_id > 4
AND state_desc = 'ONLINE'
ORDER BY name;
OPEN db_cursor_129;
FETCH NEXT FROM db_cursor_129 INTO @DatabaseName129;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @Sql129 = N'
SELECT
''129'' AS [Check ID]
, ''Orphaned Database Users'' AS [Check Name]
, database_principals.name AS Result1
, database_principals.type_desc AS Result2
, (
SELECT
' + QUOTENAME(@DatabaseName129,'''') + N' AS DatabaseName
, database_principals.authentication_type_desc AS AuthType
, database_principals.create_date
, database_principals.modify_date
FOR XML PATH(''AdditionalInfo''), TYPE
) AS AdditionalInfo
FROM ' + QUOTENAME(@DatabaseName129) + N'.sys.database_principals AS database_principals
LEFT JOIN sys.server_principals AS server_principals
ON database_principals.sid = server_principals.sid
WHERE server_principals.sid IS NULL
AND database_principals.type IN (''S'', ''U'', ''G'')
AND database_principals.authentication_type <> 0
AND database_principals.name NOT IN (''dbo'', ''guest'', ''INFORMATION_SCHEMA'', ''sys'');';
INSERT INTO @Check129
EXEC sys.sp_executesql @Sql129;
FETCH NEXT FROM db_cursor_129 INTO @DatabaseName129;
END
CLOSE db_cursor_129;
DEALLOCATE db_cursor_129;
SELECT
[Check ID]
, [Check Name]
, Result1
, Result2
, AdditionalInfo
FROM @Check129
ORDER BY
AdditionalInfo.value('(/AdditionalInfo/DatabaseName/text())[1]', 'sysname'),
Result1;
GO
SELECT
'123' AS [Check ID],
'Databases with AUTO_CLOSE setting on' AS [Check Name],
name AS Result1,
is_auto_close_on AS Result2,
(
SELECT
state_desc AS State,
create_date,
database_id
FOR XML PATH('AdditionalInfo'), TYPE
) AS AdditionalInfo
FROM sys.databases
WHERE is_auto_close_on = 1
ORDER BY name;
GO
IF CAST(LEFT(CAST(SERVERPROPERTY('ProductVersion') AS varchar(50)),
CHARINDEX('.', CAST(SERVERPROPERTY('ProductVersion') AS varchar(50))) - 1) AS int) >= 16
BEGIN
DECLARE @sql nvarchar(max) = N'
SELECT
''802'' AS [Check ID],
''Contained Availability Groups'' AS [Check Name]
, COUNT(*) AS Result1
FROM sys.availability_groups WHERE is_contained = 1
GROUP BY is_contained
'
EXEC sys.sp_executesql @sql;
END
GO
SELECT
'806' AS [Check ID],
'Outstanding configuration changes' AS [Check Name],
name AS Result1,
value AS Result2,
(
SELECT
value_in_use AS RunningValue,
description
FOR XML PATH('AdditionalInfo'), TYPE
) AS AdditionalInfo
FROM sys.configurations
WHERE value_in_use <> value
AND name NOT LIKE '%server memory (MB)%';
GO