Files
sql-server-samples/samples/manage/sql-assessment-api/notebooks/SQLAssessmentAPITutorialNotebook.ipynb
T
Aaron Nelson cc157bba00 Update SQLAssessmentAPITutorialNotebook.ipynb
Removed unnecessary foreach loop after confirming with Aleksei.
2020-08-20 14:54:55 -04:00

32 KiB

SQL Assessment API Tutorial

You can use this tutorial to understand how to assess your SQL Server configuration for best practices. In this tutorial, you will learn:

  1. How to install PowerShell SqlServer module that includes SQL Assessment API cmdlets.
  2. How to assess your SQL Server and databases
  3. How to save results in a sql table and graph over results
  4. How to customize rules by disabling some rules, adding new ones, and changing thresholds

Supported products and platforms: SQL Server 2012 and up, both on Windows and Linux. Azure SQL DB Managed Instance. More products to come.

Microsoft ruleset (ruleset.json) is published on SQL Assessment API GitHub repo and continuously improved.

Useful links at the bottom of the tutorial.

Quick primer on cmdlets

There are two cmdlets:

  1. Get-SqlAssessmentItem shows a list of available rules for a given object (5 kinds of objects is currently supported as input: Server, RegisteredServer, Database, AvailabilityGroup, Filegroup; the default ruleset contains rules for Server/RegisteredServer and Database only). Every rule has a target that describes what kind of SQL objects this rule applies to: Object Type, Object Name, SQL Server version, SQL Server platform, SQL Server engine edition. So by the availability of a rule, we mean that when you run Get-SqlAssessmentItem or Invoke-SqlAssessment, the API first verifies what rules apply for the given object.

  2. Invoke-SqlAssessment performs an assessment of a passed object and provides the results. It's worthwhile to mention that assessment is invoked for a passed object only, so if you want to assess a SQL Server instance and all its databases, run the cmdlet with the instance object as input and then run it with the databases as input. We'll show you different ways of doing this below.

1. Setup

You need to install PowerShell SqlServer module using the following command. It is a good practice to run Import-Module at the beginning of your session as well. Get-Module will show you the version you have installed. The minimum version you want is 21.1.18206 — it is the version of SqlServer module containing SQL Assessment API GA. You can read more about installing and updating the SqlServer module on docs.

In [2]:
# Uncomment and run Install-Module only the first time 
# Install-Module -Name SqlServer -AllowClobber -Force
Import-Module -Name SqlServer
Get-Module

2. Invoke an assessment for SQL Server instance

There are various ways to run the assessment cmdlet. The following statements give recommendations for a local default instance. Pick whatever style works for your script.

Server and RegisteredServer objects are interchangeable, so you can pass any to the SQL Assessment cmdlets to assess a SQL Server instance.

In [6]:
# Option 1
Get-SqlInstance -ServerInstance 'localhost' | Invoke-SqlAssessment
In [8]:
# Option 2
$serverInstance = Get-SqlInstance -ServerInstance 'localhost'
Invoke-SqlAssessment $serverInstance
In [10]:
# Option 3
Get-Item SQLSERVER:\SQL\localhost\default | Invoke-SqlAssessment
In [12]:
# Option 4
Invoke-SqlAssessment SQLSERVER:\SQL\localhost\default
In [14]:
# Option 5
cd SQLSERVER:\SQL\localhost\default
Invoke-SqlAssessment -Verbose
In [16]:
# Option 6
cd SQLSERVER:\SQL\localhost
Get-Item default | Invoke-SqlAssessment
In [ ]:
# Option 7 - passing registered servers to the cmdlet
Get-ChildItem 'SQLSERVER:\SQLRegistration\Database Engine Server Group' | WHERE { $_.Mode -ne 'D'}  | Invoke-SqlAssessment

3. Invoke an assessment for SQL Server database

You need to run Invoke-SqlAssessment against a database object to get database specific recommendations. Again, there are various ways of accomplishing this. Below are some examples.

In [18]:
# Option 1
$database = Get-SqlDatabase -ServerInstance 'localhost' -Name master
Invoke-SqlAssessment $database -Verbose
In [20]:
# Option 2
Invoke-SqlAssessment SQLSERVER:\SQL\localhost\default\Databases\master -Verbose
In [22]:
# Option 3
cd SQLSERVER:\SQL\localhost\default\Databases\master
Invoke-SqlAssessment
In [26]:
# Get recommendations for all databases on local instance:
Get-SqlDatabase -ServerInstance 'localhost' | Invoke-SqlAssessment

4. Browse applicable rules

The full Microsoft ruleset is in ruleset.json in the GitHub repo. If you want to list the rules that apply to a particular instance or database, you can use Get-SqlAssessmentItem cmdlet. Below are some different ways of listing the rules.

In [28]:
# Get all rules available for an object:
$serverInstance = Get-SqlInstance -ServerInstance 'localhost'
Get-SqlAssessmentItem $serverInstance | Select Id, Description
In [30]:
# Get all rules by a specific tag
$serverInstance = Get-SqlInstance -ServerInstance 'localhost'
Get-SqlAssessmentItem $serverInstance -Check TraceFlag

5. Run a specific rule

If you want to check a particular rule (maybe after you fixed it), you can run it by its name. You can also specify several rules in the -Check parameter, just delimit them by commas.

Every rule in the default ruleset has tags to group them into logical sets. In the example below, we look for backup related issues only. Backup value used for the -Check parameter is a tag. You can use both rule names and tags at the same time in a comma delimited list.

In [32]:
# Run a rule by its name
$serverInstance = Get-SqlInstance -ServerInstance 'localhost'
Invoke-SqlAssessment $serverInstance -Check TF634
In [36]:
# Run a group of rules using their tag
$database = Get-SqlDatabase -ServerInstance 'localhost' 
Invoke-SqlAssessment $database -Check Backup

6. Store results in a table

You probably want to save the results of an assessment to analyze and process later on. You can pipe the results of Invoke-SqlAssessment cmdlet into a table using Write-SqlTableData cmdlet. If the table doesn't exist, it creates the table and then inserts the results. If the table exists (subsequent runs), it appends the results to the table. Just remember to use -FlattenOutput parameter as it makes the Invoke-SqlAssessment output sutiable for Write-SqlTableData.

In [38]:
Get-SqlInstance -ServerInstance 'localhost' | Invoke-SqlAssessment -FlattenOutput |
Write-SqlTableData -ServerInstance 'localhost' -DatabaseName SQLAssessmentDemo -SchemaName Assessment -TableName Results -Force

7. Scaling up your Checks

Running checks across multiple machines and writng their results back to the same table in SQL Server. You can keep you list of SQL Servers to check anywhere you want, in a text file, in an Excel spreadsheet, in a table you maintain yourself, the options are endless.

Two options are shown below show features availabile that can be managed from SSMS or Azure Data Studio, and can accessed via the SQLSERVER:\ Provider, which is part of the SqlServer module.

  1. Registered Servers is feature of SSMS and stores a list of SQL Server instances in a local XML file.
  2. Central Management Server relise on a SQL Server to maintain the list of SQL Server instances (instead of a local XML file) and is available in both SSMS & Azure Data Studio.
In [ ]:
# This approach leverages the Registered Servers feature of SSMS to obtain a list of SQL Servers, and run checks against them.
Get-ChildItem 'SQLSERVER:\SQLRegistration\Database Engine Server Group' | 
Where-Object { $_.mode -ne 'd'} | 
Invoke-SqlAssessment -FlattenOutput |
Write-SqlTableData -ServerInstance localhost -DatabaseName SQLAssessmentDemo -SchemaName Assessment -TableName Results -Force
In [ ]:
<# This approach leverages the Central Management Server feature to obtain a list of SQL Servers #>
Get-ChildItem 'SQLSERVER:\SQLRegistration\Central Management Server Group' -Recurse | 
Where-Object { $_.mode -ne 'd'} | 
Invoke-SqlAssessment -FlattenOutput |
Write-SqlTableData -ServerInstance localhost -DatabaseName SQLAssessmentDemo -SchemaName Assessment -TableName Results -Force

Customization

In this section you will learn how to customize existing rules and create new ones.

As a prerequisite, make sure to grab the JSON files in the CustomizationSamples folder and place them in an accessible path and then edit the first script below to point at the right path and server instance for your environment. By default, we use in this notebook the following parameters:

  • SQL Instance to assess is "localhost"
  • JSON samples and DLLs are available by path "C:\SQLAsmnt\CustomizationSamples"

The final code block in this notebook has its own prerequisites, please complete them prior to running it:

We encourage you to look into every JSON sample so you can understand better the making of customizations for SQL Assessment.

Disabling/Enabling rules

In [2]:
#Setup three parameters that are used in all the customization examples below
#$samplesPath='<replace this with the path to customization json files, e.g. "C:\SQLAsmnt\CustomizationSamples">' 
$samplesPath='C:\SQLAsmnt\CustomizationSamples'
$samplesPath

#$serverInstance = Get-SqlInstance -ServerInstance 'localhost'
$serverInstance = Get-SqlInstance -ServerInstance '.\sql2017express'
$serverInstance

$sqlDbMaster = $serverInstance | Get-SqlDatabase -Name master
$sqlDbMaster
In [4]:
# Disable a single rule using its ID (TF634)
# To see this in action, make sure you have trace flag 634 turned on in the instance you are testing. Otherwise this rule will not fire even when enabled.
# You will see that TF634 is not enabled (On=False)
Get-SqlAssessmentItem $serverInstance -Configuration $(join-path $samplesPath "DisableTF634.json")
In [6]:
# Disable all Trace Flag rules using a tag
# You will see that all TF rules are set to False (disabled)
Get-SqlAssessmentItem $serverInstance -Configuration $(join-path $samplesPath "DisableAllTF.json")
In [8]:
# Combine configurations
# This example disables all trace flag rules except for performance-related ones using tags. 
# The order of json files is important. First we disable all TF rules, then enable performance rules which re-enables performance-related TF rules.
Get-SqlAssessmentItem $serverInstance -Configuration $(join-path $samplesPath "DisableAllTF.json"), $(join-path $samplesPath "EnablePerformance.json")

Creating a new rule

The rules are defined in json files. In this example, we are creating a rule that checks for available database space. Go ahead and examine CustomRuleTSQLProbe.json.

A rule has many components such as which ruleset it belongs to, what type of objects, editions, versions, platforms it targets as well as more obvious components such as id, name, description, etc.

Condition is what gets evaluated. When an expression in Condition returns false, it means that the rule is violated and the user gets a recommendation from this rule.

Probe is what gets the data to be evaluated in the condition. Probes can be SQL or CLR. SQL probe is a T-SQL query to pull the required data right out of SQL Server. CLR probe is a reference to a .NET or Core assembly with a call to a method inside the library.

In [10]:
# Create a new rule with TSQL probe
# This rule applies to databases and uses a TSQL statement to get the data for the rule. 
Invoke-SqlAssessment $sqlDbMaster -configuration $(join-path $samplesPath "CustomRuleTSQLProbe.json")
In [13]:
# Override threshold parameter
# CustomRuleThresholdChange.json defines a new threshold value for DBSpaceAvailable rule created above
Invoke-SqlAssessment $sqlDbMaster -configuration $(join-path $samplesPath "CustomRuleTSQLProbe.json"),$(join-path $samplesPath "CustomRuleThresholdChange.json")

Probe types

CmdShell

Create a new rule with CmdShell probe. CmdShell probe executes a CMD.EXE shell command and returns lines of text in variable @stdout. Use 'CMDSHELL' instead of 'SQL' in probe definition to load a .cmd file. Use Regex parser transformation to extract data from @stdout

In [ ]:
#Create new rule with cmd probe type. It runs 'dir' cmd command and checks that resulted list is'n empty.
#Make sure that xp_cmdshell is enabled
Invoke-SqlAssessment $serverInstance -configuration $(join-path $samplesPath "CustomRuleCmdShellProbe.json")

PowerShell

PowerShell probe executes a command in PowerShell on target machine and returns pipeline output in @Output variable. Use $ (dollar) sign to access probe parameters passed from checks. Use . (dot) to access properties of the output object. For example, if a returned object is string, then @Output.Length returns its length.

In [ ]:
#Create new rule with Powershell probe type.
#It runs query to get major PS version
#Make sure that xp_cmdshell is enabled and PS execution policy is RemoteSigned or Unrestricted.
Invoke-SqlAssessment $serverInstance -configuration $(join-path $samplesPath "CustomRulePowerShellProbe.json")

Registry

Registry probe obtains data from target machine's registry. The key name will be returned in @RegistryKeyName. Use * (asterisk) symbol to enumerate all keys.

In [ ]:
#Create new rule with Registry probe
#Make sure that xp_cmdshell is enabled
Invoke-SqlAssessment $serverInstance -configuration $(join-path $samplesPath "CustomRuleRegistryProbe.json")

WMI

WMI probe runs a WMI query and returns results in @Output variable in the same way as a PowerShell probe does. Use $ (dollar) sign to access probe parameters passed from checks.

In [ ]:
#Create new rule with WMI probe
#Make sure that xp_cmdshell is enabled.
Invoke-SqlAssessment $serverInstance -configuration $(join-path $samplesPath "CustomRuleWmiProbe.json")

Managed code probe

For CLR probe use "External" probe type.

In [ ]:
# Create a new rule with CLR probe. CustomRuleCLRProbe.json, in addition to a check with a CLR probe, contains an ovveride to disable all the rules of the DefaultRuleset.
# !!! Complete the prerequisites below before running this block.
# !!! There are 2 dlls in CustomizationSamples folder. Make sure that they both are not blocked: https://stackoverflow.com/questions/34400546/could-not-load-file-or-assembly-operation-is-not-supported-exception-from-hres/45221477
# !!! Then open CustomRuleCLRProbe.json in the same folder and make sure that assembly key contains the right path to TestsProbeLibrary.dll, double slashes are required.
# !!! You're all set. Run this block
Invoke-SqlAssessment $serverInstance -configuration $(join-path $samplesPath "CustomRuleCLRProbe.json")