├── .gitignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── extension_listing.json ├── images ├── checkFRKversion.gif ├── documentation-link.png ├── first-responder-kit-sqlops-extension.png ├── frk_import.gif ├── frk_run.gif ├── insightsTab.png ├── newVersionAvailable.gif └── resources.txt ├── package-lock.json ├── package.json ├── snippets └── snippets.json ├── sql ├── blitzcache.sql ├── blitzfirst.sql ├── waittimes.sql └── waittypes.sql ├── src ├── apiconfig.ts ├── documentationLinking.ts ├── extension.ts ├── getScripts.ts ├── placescript.ts ├── runScripts.ts ├── test │ ├── extension.test.ts │ └── index.ts ├── typings │ └── azdata.proposed.d.ts └── updateCheck.ts ├── tsconfig.json └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | .vscode-test/ 4 | *.vsix 5 | secrets.txt 6 | apiconfig.json 7 | dist 8 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | 6 | // To debug the extension: 7 | // 1. please install the "SQL Operations Studio Debug" extension into VSCode 8 | // 2. Ensure sqlops is added to your path: 9 | // - open SQL Operations Studio 10 | // - run the command "Install 'sqlops' command in PATH" 11 | { 12 | "version": "0.2.0", 13 | "configurations": [ 14 | { 15 | "name": "Extension", 16 | "type": "sqlopsExtensionHost", 17 | "request": "launch", 18 | "runtimeExecutable": "azuredatastudio", 19 | "args": [ 20 | "--extensionDevelopmentPath=${workspaceFolder}" 21 | ], 22 | "outFiles": [ 23 | "${workspaceFolder}/out/**/*.js" 24 | ], 25 | "preLaunchTask": "npm: watch" 26 | }, 27 | { 28 | "name": "Extension Tests", 29 | "type": "sqlopsExtensionHost", 30 | "request": "launch", 31 | "runtimeExecutable": "azuredatastudio", 32 | "args": [ 33 | "--extensionDevelopmentPath=${workspaceFolder}", 34 | "--extensionTestsPath=${workspaceFolder}/dist/test" 35 | ], 36 | "outFiles": [ 37 | "${workspaceFolder}/out/test/**/*.js" 38 | ], 39 | "preLaunchTask": "npm: watch" 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | } 9 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": "$tsc-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | out/**/*.map 5 | src/** 6 | .gitignore 7 | tsconfig.json 8 | vsc-extension-quickstart.md 9 | tslint.json 10 | out 11 | node_modules 12 | images -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to the "First Responder Kit" extension will be documented in this file. 3 | 4 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 5 | 6 | ## 0.1.0 7 | - Initial release -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 DrewSK 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Azure Data Studio - First Responder Kit Extension 2 | 3 | This extension provides immediate access to the current First Responder Kit scripts and introductory execution suggestions. (All credit due to http://firstresponderkit.org/) 4 | 5 | ## Installation 6 | The current release is available to [download as a .vsix file](https://github.com/dzsquared/sqlops-firstresponderkit/releases/download/0.6.0/firstresponderkit-0.6.0.vsix) and can be installed by opening the command palette (`ctrl/command+shift+p`) and selecting `Extensions: Install from VSIX...` 7 | 8 | 9 | ## Features 10 | 11 | ### Import 12 | Import a script from the First Responder Kit to a new editor by opening the command palette (`ctrl/command+shift+p`) and selecting an option under `First Responder Kit: Import `. To import all scripts at once, select `First Responder Kit: Import sp_Blitz and all its friends`. 13 | 14 | 15 | ![Import a Script](https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/main/images/frk_import.gif) 16 | 17 | ### Run 18 | Already have the current scripts loaded to the database? Great! Take the shortcut to execution by opening the command palette (`ctrl/command+shift+p`) and selecting an option under `First Responder Kit: Run `. Several scripts are available in Object Explorer at Server, Database, and Table nodes. 19 | 20 | ![Execute](https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/main/images/frk_run.gif) 21 | 22 | ### Check Your Current Version 23 | Want to check the sp_Blitz version on a server? You can check your current connection or a server in object explorer and find out if you have the current version. 24 | 25 | 26 | ![Check Version](https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/main/images/checkFRKversion.gif) 27 | ![Version Results](https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/main/images/newVersionAvailable.gif) 28 | 29 | ### Documentation Linking in Status Bar 30 | As you work with sp_Blitz and other First Responder Kit scripts, they will be automatically detected in the query editor and a link to documentation is provided in the status bar. 31 | 32 | ![Link to Documentation for sp_BlitzIndex](https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/main/images/documentation-link.png) 33 | 34 | ### Database Dashboard Tab 35 | 36 | Selected elements from the First Responder Kit PowerBI dashboard have been replicated in a dashboard tab. The elements execute against the current database and require the database configured to contain First Responder Kit historical data. For more information on data collection configuration, please see: https://www.brentozar.com/first-aid/first-responder-kit-power-bi-dashboard/ 37 | 38 | 39 | ![Insights Tab](https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/main/images/insightsTab.png) 40 | 41 | ----------------------------------------------------------------------------------------------------------- 42 | 43 | ## Extension Requirements 44 | 45 | Internet connectivity is required for any of the "Import" commands, which connect to GitHub to fetch recent versions of the scripts. A GitHub account is NOT required. 46 | 47 | First Responder Kit scripts require SQL Server 2008 or newer. See current requirements for the scripts at http://firstresponderkit.org/. 48 | 49 | ----------------------------------------------------------------------------------------------------------- 50 | 51 | ## Known Issues 52 | 53 | No open issues at this time. 54 | 55 | ## Unknown Issues 56 | Can be raised here: https://github.com/dzsquared/sqlops-firstresponderkit/issues 57 | 58 | ## Release Notes 59 | 60 | ### 0.6.0 61 | 62 | - Fix for extension unable to pull scripts from GitHub. Change to utilizing `main` branch of First Responder Kit. 63 | - Adds interactive documentation linking to status bar. 64 | 65 | ### 0.5.1 66 | 67 | - Fix for changes to new editor connection changes in Azure Data Studio 1.15.0 68 | - Extension bundled with webpack 69 | 70 | ### 0.5.0 71 | 72 | - Improvement to version check process 73 | - Moves from sqlops to azdata dependency 74 | - Adds dashboard tab with insights widgets 75 | 76 | ### 0.4.0 77 | 78 | - Adds sp_blitzlock and sp_whoisactive 79 | - Adds version check for sp_blitz 80 | - Adds single command to get sp_blitz and all associated scripts 81 | - Adds menu items for object explorer for sp_blitz, sp_blitzindex, sp_blitzfirst, sp_blitzlock, and sp_whoisactive 82 | 83 | ### 0.3.0 84 | 85 | - Adds code snippets for execute scripts 86 | - Corrects sp_blitzindex execute script 87 | 88 | ### 0.2.0 89 | 90 | - Script import and run commands automatically connect to current context 91 | 92 | ### 0.1.1 93 | 94 | - Corrects base URL for scripts from dev to master branch of First Responder Kit 95 | 96 | ### 0.1.0 97 | 98 | - Initial release. 99 | 100 | 101 | ----------------------------------------------------------------------------------------------------------- 102 | 103 | ## Special Thanks 104 | A very important thank you to [Brent Ozar Unlimited](https://www.brentozar.com/) for supporting this extension. 105 | 106 | ## License 107 | 108 | This extension is released under the [MIT License](https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/main/LICENSE). 109 | -------------------------------------------------------------------------------- /extension_listing.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionId": "22", 3 | "extensionName": "firstresponderkit", 4 | "displayName": "First Responder Kit", 5 | "shortDescription": "Access current versions of scripts from the First Responder Kit", 6 | "publisher": { 7 | "displayName":"Drew Skwiers-Koballa", 8 | "publisherId": "drewsk", 9 | "publisherName":"drewsk" 10 | }, 11 | "versions": [ 12 | { 13 | "version": "0.2.0", 14 | "lastUpdated": "9/29/2018", 15 | "assetUri": "", 16 | "fallbackAssetUri": "fallbackAssetUri", 17 | "files": [ 18 | { 19 | "assetType": "Microsoft.SQLOps.DownloadPage", 20 | "source": "https://github.com/dzsquared/sqlops-firstresponderkit/releases/tag/0.2.0" 21 | }, 22 | { 23 | "assetType": "Microsoft.VisualStudio.Services.Icons.Default", 24 | "source": "https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/master/images/first-responder-kit-sqlops-extension.png" 25 | }, 26 | { 27 | "assetType": "Microsoft.VisualStudio.Services.Content.Details", 28 | "source": "https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/master/README.md" 29 | }, 30 | { 31 | "assetType": "Microsoft.VisualStudio.Code.Manifest", 32 | "source": "https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/master/package.json" 33 | }, 34 | { 35 | "assetType": "Microsoft.VisualStudio.Services.Content.License", 36 | "source": "https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/master/LICENSE" 37 | } 38 | ], 39 | "properties": [ 40 | { "key": "Microsoft.VisualStudio.Code.ExtensionDependencies", "value":""}, 41 | { "key": "Microsoft.VisualStudio.Services.Links.Source", "value": "https://github.com/dzsquared/sqlops-firstresponderkit"}, 42 | { "key": "Microsoft.VisualStudio.Code.Engine", "value":"*"} 43 | ] 44 | } 45 | ], 46 | "statistics": [], 47 | "flags": "preview" 48 | } -------------------------------------------------------------------------------- /images/checkFRKversion.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/53fc55355a88c50c68c7f944ddd877e23e02a01f/images/checkFRKversion.gif -------------------------------------------------------------------------------- /images/documentation-link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/53fc55355a88c50c68c7f944ddd877e23e02a01f/images/documentation-link.png -------------------------------------------------------------------------------- /images/first-responder-kit-sqlops-extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/53fc55355a88c50c68c7f944ddd877e23e02a01f/images/first-responder-kit-sqlops-extension.png -------------------------------------------------------------------------------- /images/frk_import.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/53fc55355a88c50c68c7f944ddd877e23e02a01f/images/frk_import.gif -------------------------------------------------------------------------------- /images/frk_run.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/53fc55355a88c50c68c7f944ddd877e23e02a01f/images/frk_run.gif -------------------------------------------------------------------------------- /images/insightsTab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/53fc55355a88c50c68c7f944ddd877e23e02a01f/images/insightsTab.png -------------------------------------------------------------------------------- /images/newVersionAvailable.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dzsquared/sqlops-firstresponderkit/53fc55355a88c50c68c7f944ddd877e23e02a01f/images/newVersionAvailable.gif -------------------------------------------------------------------------------- /images/resources.txt: -------------------------------------------------------------------------------- 1 | http://www.chrisstead.com/archives/1082/visual-studio-code-extensions-editing-the-document/ 2 | 3 | https://code.visualstudio.com/docs/extensionAPI/vscode-api#_commands 4 | 5 | https://stackoverflow.com/questions/45046552/texteditoredit-replace-is-async-how-to-execute-code-when-it-is-finished 6 | 7 | https://stackoverflow.com/questions/45748476/http-request-in-typescript 8 | 9 | https://github.com/egamma/vscode-extension-async/blob/master/src/extension.ts 10 | 11 | https://github.com/patbenatar/vscode-advanced-new-file/blob/master/src/extension.ts 12 | 13 | https://github.com/kevcunnane/HelloConnectedWorld/blob/master/src/extension.ts 14 | https://medium.com/@kevcunnane/extending-sql-operations-studio-hello-connected-world-part-1-of-n-e868542c6157 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firstresponderkit", 3 | "displayName": "First Responder Kit", 4 | "description": "Current Versions of the sp_blitz Scripts", 5 | "version": "0.6.0", 6 | "publisher": "drewsk", 7 | "engines": { 8 | "vscode": "^1.25.0", 9 | "azdata": "^1.21.0" 10 | }, 11 | "categories": [ 12 | "Other" 13 | ], 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/dzsquared/sqlops-firstresponderkit.git" 17 | }, 18 | "activationEvents": [ 19 | "*" 20 | ], 21 | "main": "./dist/extension", 22 | "contributes": { 23 | "commands": [ 24 | { 25 | "command": "extension.sp_blitzversion", 26 | "title": "First Responder Kit: Check sp_Blitz Version" 27 | }, 28 | { 29 | "command": "extension.sp_blitzall", 30 | "title": "First Responder Kit: Import sp_Blitz and all its friends" 31 | }, 32 | { 33 | "command": "extension.sp_blitz", 34 | "title": "First Responder Kit: Import sp_Blitz" 35 | }, 36 | { 37 | "command": "extension.run_sp_blitz", 38 | "title": "First Responder Kit: Run sp_Blitz" 39 | }, 40 | { 41 | "command": "extension.sp_blitzindex", 42 | "title": "First Responder Kit: Import sp_BlitzIndex" 43 | }, 44 | { 45 | "command": "extension.run_sp_blitzindex", 46 | "title": "First Responder Kit: Run sp_BlitzIndex" 47 | }, 48 | { 49 | "command": "extension.sp_blitzwho", 50 | "title": "First Responder Kit: Import sp_BlitzWho" 51 | }, 52 | { 53 | "command": "extension.sp_blitzfirst", 54 | "title": "First Responder Kit: Import sp_BlitzFirst" 55 | }, 56 | { 57 | "command": "extension.run_sp_blitzfirst", 58 | "title": "First Responder Kit: Run sp_BlitzFirst" 59 | }, 60 | { 61 | "command": "extension.sp_blitzcache", 62 | "title": "First Responder Kit: Import sp_BlitzCache" 63 | }, 64 | { 65 | "command": "extension.run_sp_blitzcache", 66 | "title": "First Responder Kit: Run sp_BlitzCache" 67 | }, 68 | { 69 | "command": "extension.run_sp_whoisactive", 70 | "title": "First Responder Kit: Run sp_WhoIsActive" 71 | }, 72 | { 73 | "command": "extension.run_sp_blitzlock", 74 | "title": "First Responder Kit: Run sp_BlitzLock" 75 | } 76 | ], 77 | "snippets": [ 78 | { 79 | "language": "sql", 80 | "path": "./snippets/snippets.json" 81 | } 82 | ], 83 | "menus": { 84 | "objectExplorer/item/context": [ 85 | { 86 | "command": "extension.sp_blitzversion", 87 | "when": "connectionProvider == MSSQL && nodeType && nodeType == Server", 88 | "group": "FRK" 89 | }, 90 | { 91 | "command": "extension.run_sp_whoisactive", 92 | "when": "connectionProvider == MSSQL && nodeType && nodeType == Server", 93 | "group": "FRK" 94 | }, 95 | { 96 | "command": "extension.run_sp_blitzlock", 97 | "when": "connectionProvider == MSSQL && nodeType && nodeType == Server", 98 | "group": "FRK" 99 | }, 100 | { 101 | "command": "extension.run_sp_blitz", 102 | "when": "connectionProvider == MSSQL && nodeType && nodeType == Server", 103 | "group": "FRK" 104 | }, 105 | { 106 | "command": "extension.run_sp_blitzfirst", 107 | "when": "connectionProvider == MSSQL && nodeType && nodeType == Server", 108 | "group": "FRK" 109 | }, 110 | { 111 | "command": "extension.run_sp_blitzlock", 112 | "when": "connectionProvider == MSSQL && nodeType && nodeType == Database", 113 | "group": "FRK" 114 | }, 115 | { 116 | "command": "extension.run_sp_blitzindex", 117 | "when": "connectionProvider == MSSQL && nodeType && nodeType == Database", 118 | "group": "FRK" 119 | }, 120 | { 121 | "command": "extension.run_sp_blitzindex", 122 | "when": "connectionProvider == MSSQL && nodeType && nodeType == Table", 123 | "group": "FRK" 124 | } 125 | ] 126 | }, 127 | "dashboard.insights": [ 128 | { 129 | "id": "sqlops-firstresponderkit.waittypes", 130 | "contrib": { 131 | "queryFile": "./sql/waittypes.sql", 132 | "type": { 133 | "horizontalBar": { 134 | "dataDirection": "vertical", 135 | "columnsAsLabels": true, 136 | "labelFirstColumn": false, 137 | "legendPosition": "top" 138 | } 139 | } 140 | } 141 | }, 142 | { 143 | "id": "sqlops-firstresponderkit.waittimes", 144 | "contrib": { 145 | "queryFile": "./sql/waittimes.sql", 146 | "type": { 147 | "bar": { 148 | "dataDirection": "vertical", 149 | "columnsAsLabels": true, 150 | "labelFirstColumn": false, 151 | "legendPosition": "left", 152 | "yAxisLabel": "Wait Time, Minutes per Minute", 153 | "dataType": "point" 154 | } 155 | } 156 | } 157 | }, 158 | { 159 | "id": "sqlops-firstresponderkit.blitzfirst", 160 | "contrib": { 161 | "queryFile": "./sql/blitzfirst.sql", 162 | "type": { 163 | "table": { 164 | "dataDirection": "horizontal", 165 | "columnsAsLabels": true, 166 | "labelFirstColumn": true, 167 | "legendPosition": "bottom", 168 | "dataType": "number" 169 | } 170 | } 171 | } 172 | }, 173 | { 174 | "id": "sqlops-firstresponderkit.blitzcache", 175 | "contrib": { 176 | "queryFile": "./sql/blitzcache.sql", 177 | "type": { 178 | "table": { 179 | "dataDirection": "horizontal", 180 | "columnsAsLabels": true, 181 | "labelFirstColumn": true, 182 | "legendPosition": "bottom", 183 | "dataType": "number" 184 | } 185 | } 186 | } 187 | } 188 | ], 189 | "dashboard.tabs": [ 190 | { 191 | "id": "sqlops-firstresponderkit.tab", 192 | "title": "First Responder Kit", 193 | "description": "First Responder Kit Dashboard", 194 | "container": { 195 | "widgets-container": [ 196 | { 197 | "name": "Top 3 Wait Times", 198 | "gridItemConfig": { 199 | "sizex": 3, 200 | "sizey": 1 201 | }, 202 | "widget": { 203 | "sqlops-firstresponderkit.waittimes": {} 204 | } 205 | }, 206 | { 207 | "name": "Wait Types", 208 | "gridItemConfig": { 209 | "sizex": 1, 210 | "sizey": 2 211 | }, 212 | "widget": { 213 | "sqlops-firstresponderkit.waittypes": {} 214 | } 215 | }, 216 | { 217 | "name": "Quick Diagnosis from sp_BlitzFirst", 218 | "gridItemConfig": { 219 | "sizex": 2, 220 | "sizey": 2 221 | }, 222 | "widget": { 223 | "sqlops-firstresponderkit.blitzfirst": {} 224 | } 225 | }, 226 | { 227 | "name": "Resource-Intensive Queries from sp_BlitzCache", 228 | "gridItemConfig": { 229 | "sizex": 3, 230 | "sizey": 1 231 | }, 232 | "widget": { 233 | "sqlops-firstresponderkit.blitzcache": {} 234 | } 235 | } 236 | ] 237 | }, 238 | "when": "dashboardContext == 'database'" 239 | } 240 | ] 241 | }, 242 | "scripts": { 243 | "vscode:prepublish": "webpack --mode production", 244 | "webpack": "webpack --mode development", 245 | "webpack-dev": "webpack --mode development --watch", 246 | "compile": "tsc -p ./", 247 | "watch": "tsc -watch -p ./", 248 | "postinstall": "node ./node_modules/vscode/bin/install && node ./node_modules/azdata/bin/install", 249 | "test": "npm run compile && node ./node_modules/vscode/bin/test" 250 | }, 251 | "devDependencies": { 252 | "@types/mocha": "^2.2.42", 253 | "@types/node": "^7.0.43", 254 | "azdata": "^1.0.0", 255 | "ts-loader": "^6.2.1", 256 | "typescript": "^2.6.1", 257 | "vscode": "^1.1.6", 258 | "webpack": "^4.41.6", 259 | "webpack-cli": "^3.3.11" 260 | }, 261 | "dependencies": { 262 | "clipboardy": "^2.2.0", 263 | "request": "^2.87.0", 264 | "request-promise-native": "^1.0.5" 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /snippets/snippets.json: -------------------------------------------------------------------------------- 1 | { 2 | "FRK spBlitz": { 3 | "prefix": "sqlFRKspBlitz", 4 | "body": [ 5 | "EXEC [dbo].[sp_Blitz]", 6 | "@CheckUserDatabaseObjects = 1 ,", 7 | "@CheckProcedureCache = 0 ,", 8 | "@OutputType = 'TABLE' ,", 9 | "@OutputProcedureCache = 0 ,", 10 | "@CheckProcedureCacheFilter = NULL,", 11 | "@CheckServerInfo = 1", 12 | "-- uncomment the following line to write results to an output table", 13 | "--, @OutputDatabaseName = 'DBAtools', @OutputSchemaName = 'dbo', @OutputTableName = 'BlitzResults'", 14 | "-- for more info: https://www.brentozar.com/blitz/" 15 | ], 16 | "description": "sp_blitz execution script" 17 | }, 18 | "FRK spBlitzIndex": { 19 | "prefix": "sqlFRKspBlitzIndex", 20 | "body": [ 21 | "EXEC [dbo].[sp_BlitzIndex]", 22 | "@DatabaseName = '${1:DatabaseName}',", 23 | "--@TableName = '${2:TableName}'", 24 | "--@Mode = 4", 25 | "--0=Diagnose, 1=Summarize, 2=Index Usage Detail, 3=Missing Index Detail, 4=Diagnose Details", 26 | "-- for more info: https://www.brentozar.com/blitzindex/" 27 | ], 28 | "description": "sp_blitzindex execution script" 29 | }, 30 | "FRK spBlitzCache": { 31 | "prefix": "sqlFRKspBlitzCache", 32 | "body": [ 33 | "EXEC [dbo].[sp_BlitzCache]", 34 | "@SortOrder = 'reads',", 35 | " -- CPU, executions, xpm, recent compilations, memory grant, writes, all", 36 | "@Top = 10", 37 | "-- for more info: https://www.brentozar.com/blitzcache/" 38 | ], 39 | "description": "sp_blitzcache execution script" 40 | }, 41 | "FRK spBlitzFirst": { 42 | "prefix": "sqlFRKspBlitzFirst", 43 | "body": [ 44 | "EXEC [dbo].[sp_BlitzFirst]", 45 | "@Seconds = 5,", 46 | "@ShowSleepingSPIDs = 0,", 47 | "@ExpertMode = 0 --1 will also run sp_BlitzWho", 48 | "-- for more info: https://www.brentozar.com/askbrent/" 49 | ], 50 | "description": "sp_blitzfirst execution script" 51 | }, 52 | "FRK spBlitzLock": { 53 | "prefix": "sqlFRKspBlitzLock", 54 | "body": [ 55 | "EXEC [dbo].[sp_BlitzLock]", 56 | "--@DatabaseName = '',", 57 | "@Top = 10", 58 | "-- for more info: https://www.brentozar.com/archive/2017/12/introducing-sp_blitzlock-troubleshooting-sql-server-deadlocks/" 59 | ] 60 | }, 61 | "FRK sp_whoisactive": { 62 | "prefix": "sqlFRKspWhoIsActive", 63 | "body": [ 64 | "EXEC sp_WhoIsActive ", 65 | "@find_block_leaders = 1,", 66 | "@sort_order = '[blocked_session_count] DESC'", 67 | "-- @filter = '',", 68 | "-- @filter_type = 'session', ", 69 | "-- @not_filter = '', ", 70 | "-- @not_filter_type = 'session',", 71 | "-- @show_own_spid = 0, ", 72 | "-- @show_system_spids = 0, ", 73 | "-- @show_sleeping_spids = 1, ", 74 | "-- @get_full_inner_text = 0,", 75 | "-- @get_plans = 0, ", 76 | "-- @get_outer_command = 0, ", 77 | "-- @get_transaction_info = 0, ", 78 | "-- @get_task_info = 1, ", 79 | "-- @get_locks = 0, ", 80 | "-- @get_avg_time = 0, ", 81 | "-- @get_additional_info = 0, ", 82 | "-- @delta_interval = 0, ", 83 | "-- @output_column_list = '[dd%][session_id][sql_text][sql_command][login_name][wait_info][tasks][tran_log%][cpu%][temp%][block%][reads%][writes%][context%][physical%][query_plan][locks][%]', ", 84 | "-- @format_output = 1, ", 85 | "-- @destination_table = '', ", 86 | "-- @return_schema = 0, ", 87 | "-- @help = 0", 88 | "-- for more info: http://whoisactive.com/docs/" 89 | ] 90 | } 91 | } -------------------------------------------------------------------------------- /sql/blitzcache.sql: -------------------------------------------------------------------------------- 1 | SELECT TOP 100 CheckDate 2 | , DatabaseName 3 | , QueryType 4 | , Warnings 5 | , left(QueryText,100) as [QueryText100] 6 | , [Query Hash More Info] 7 | FROM dbo.BlitzCache 8 | ORDER BY CHECKDATE DESC -------------------------------------------------------------------------------- /sql/blitzfirst.sql: -------------------------------------------------------------------------------- 1 | SELECT TOP 100 CheckDate 2 | , replace(replace(Details,'>','>'),'<','<') as Details 3 | , Finding 4 | , FindingsGroup 5 | , PRIORITY 6 | FROM dbo.BlitzFirst 7 | WHERE PRIORITY > 0 8 | ORDER BY CHECKDATE DESC -------------------------------------------------------------------------------- /sql/waittimes.sql: -------------------------------------------------------------------------------- 1 | DECLARE @TOPWAITS NVARCHAR(500) = '' 2 | 3 | SELECT @TOPWAITS += QUOTENAME(wait_type)+ ',' 4 | FROM ( 5 | SELECT top 3 WAIT_TYPE 6 | FROM dbo.BlitzFirst_WaitStats_Deltas 7 | GROUP BY wait_type 8 | ORDER BY SUM([wait_time_minutes_delta]) DESC 9 | )AS WAITS 10 | SET @TOPWAITS = LEFT(@TOPWAITS, LEN(@TOPWAITS)-1) 11 | 12 | DECLARE @WAITQUERY NVARCHAR(MAX) 13 | 14 | SET @WAITQUERY = ' 15 | SELECT * FROM ( 16 | SELECT CheckDate 17 | , wait_type 18 | , wait_time_minutes_per_minute 19 | FROM BlitzFirst_WaitStats_Deltas WAITS 20 | WHERE WAIT_TYPE IN 21 | (SELECT top 3 [wait_type] 22 | FROM dbo.BlitzFirst_WaitStats_Deltas 23 | GROUP BY wait_type 24 | ORDER BY SUM([wait_time_minutes_delta]) DESC) 25 | ) WTS 26 | PIVOT 27 | (SUM(WAIT_TIME_MINUTES_PER_MINUTE) 28 | FOR WAIT_TYPE IN 29 | ('+@TOPWAITS+') 30 | ) AS WAITGRAPH; 31 | ' 32 | 33 | EXECUTE SP_EXECUTESQL @WAITQUERY -------------------------------------------------------------------------------- /sql/waittypes.sql: -------------------------------------------------------------------------------- 1 | SELECT top 10 [wait_type] 2 | , SUM([wait_time_minutes_delta]) AS [Minutes] 3 | FROM dbo.BlitzFirst_WaitStats_Deltas 4 | GROUP BY wait_type 5 | ORDER BY MINUTES DESC -------------------------------------------------------------------------------- /src/apiconfig.ts: -------------------------------------------------------------------------------- 1 | export interface apiconfig 2 | { 3 | token: string; 4 | } -------------------------------------------------------------------------------- /src/documentationLinking.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import * as vscode from 'vscode'; 3 | import * as request from 'request-promise-native'; 4 | import * as clipboardy from 'clipboardy'; 5 | 6 | export async function openDocumentation(baseUrl: string, scriptName: string) { 7 | let fileName = "README.md"; 8 | var options = { 9 | uri: baseUrl + fileName, 10 | }; 11 | const scriptText = await request.get(options); 12 | 13 | // find ## sp_blitz: 14 | let docIndex = scriptText.indexOf('## '+scriptName +':'); 15 | let newLineIndex = scriptText.indexOf('\n', docIndex) 16 | 17 | // parse full line 18 | let bookmarkLine: string = scriptText.substring(docIndex+3, newLineIndex+1); 19 | 20 | // convert to link 21 | let docsUrlArray:string[] = Array.from(bookmarkLine); 22 | let docsUrl = "https://github.com/BrentOzarULTD/SQL-Server-First-Responder-Kit#"; 23 | docsUrlArray.forEach(c => { 24 | if (c != ':' && c != ' ') { 25 | docsUrl += c; 26 | } else if ( c == ' ') { 27 | docsUrl += '-'; 28 | } 29 | }); 30 | 31 | // add to help menu as a FirstResponderKit section 32 | 33 | 34 | // present window with options to copy to clipboard or open in browser 35 | var buttonName = await vscode.window.showInformationMessage( 36 | docsUrl, 37 | {modal: false}, 38 | "Copy", 39 | "Open in Browser" 40 | ); 41 | if (buttonName) { 42 | if (buttonName == 'Open in Browser') { 43 | vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(docsUrl)); 44 | } else if (buttonName == 'Copy') { 45 | await clipboardy.write(docsUrl); 46 | } 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import * as vscode from 'vscode'; 3 | import * as request from 'request-promise-native'; 4 | import * as sqlops from 'azdata'; 5 | import {placeScript} from './placescript'; 6 | import {disposable_spblitzversion} from './updateCheck'; 7 | import {openDocumentation} from './documentationLinking'; 8 | import * as getScripts from './getScripts'; 9 | import * as runScripts from './runScripts'; 10 | 11 | export function activate(context: vscode.ExtensionContext) { 12 | const baseUrl = "https://raw.githubusercontent.com/BrentOzarULTD/SQL-Server-First-Responder-Kit/main/"; 13 | 14 | // documentation help link 15 | let currentBlitz: string = 'sp_Blitz'; 16 | let timeout: NodeJS.Timer | null = null; 17 | var docsspblitz = () => { 18 | openDocumentation(baseUrl, currentBlitz); 19 | }; 20 | var disposable_docsspblitz = vscode.commands.registerCommand('extension.docs_sp_blitz', docsspblitz); 21 | context.subscriptions.push(disposable_docsspblitz); 22 | let docsStatusBar: vscode.StatusBarItem; 23 | docsStatusBar = vscode.window.createStatusBarItem(); 24 | docsStatusBar.command = 'extension.docs_sp_blitz'; 25 | context.subscriptions.push(docsStatusBar); 26 | 27 | function checkSpBlitzType() : void { 28 | let blitzes: string[] = ['sp_Blitz', 'sp_BlitzIndex', 'sp_BlitzCache', 'sp_BlitzWho', 'sp_BlitzFirst', 'sp_BlitzLock', 'sp_Blitz\'']; 29 | let blitzLabel: string = ""; 30 | if (vscode.window.activeTextEditor) { 31 | let editorText: string = vscode.window.activeTextEditor.document.getText(); 32 | blitzes.forEach( blitz => { 33 | if (editorText.toLowerCase().includes(blitz.toLowerCase())) { 34 | blitzLabel = blitz.replace('\'',''); 35 | } 36 | }); 37 | } 38 | if (blitzLabel != "") { 39 | docsStatusBar.text = '$(question) ' + blitzLabel + ' Documentation'; 40 | docsStatusBar.show(); 41 | } else { 42 | docsStatusBar.hide(); 43 | } 44 | currentBlitz = blitzLabel; 45 | } 46 | 47 | function triggerUpdateDocLink() { 48 | if (timeout) { 49 | clearTimeout(timeout); 50 | } 51 | timeout = setTimeout(checkSpBlitzType, 1000); // wait a second to avoid hammering 52 | } 53 | 54 | context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(triggerUpdateDocLink)); 55 | context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(triggerUpdateDocLink)); 56 | context.subscriptions.push(vscode.window.onDidChangeVisibleTextEditors(triggerUpdateDocLink)); 57 | 58 | context.subscriptions.push(disposable_spblitzversion); 59 | 60 | context.subscriptions.push(getScripts.disposable_spblitzall); 61 | context.subscriptions.push(getScripts.disposable_spblitz); 62 | context.subscriptions.push(getScripts.disposable_spblitzcache); 63 | context.subscriptions.push(getScripts.disposable_spblitzfirst); 64 | context.subscriptions.push(getScripts.disposable_spblitzwho); 65 | context.subscriptions.push(getScripts.disposable_spblitzindex); 66 | 67 | context.subscriptions.push(runScripts.disposable_runspblitz); 68 | context.subscriptions.push(runScripts.disposable_runspblitzindex); 69 | context.subscriptions.push(runScripts.disposable_runspblitzcache); 70 | context.subscriptions.push(runScripts.disposable_runspblitzfirst); 71 | context.subscriptions.push(runScripts.disposable_runspblitzlock); 72 | context.subscriptions.push(runScripts.disposable_runspwhoisactive); 73 | } 74 | 75 | export function deactivate() { 76 | 77 | } 78 | 79 | -------------------------------------------------------------------------------- /src/getScripts.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import * as vscode from 'vscode'; 3 | import * as sqlops from 'azdata'; 4 | import * as request from 'request-promise-native'; 5 | import {placeScript} from './placescript'; 6 | 7 | const baseUrl = "https://raw.githubusercontent.com/BrentOzarULTD/SQL-Server-First-Responder-Kit/main/"; 8 | 9 | async function spblitzscript(baseUrl: string, fileName: string, context?: sqlops.ObjectExplorerContext) { 10 | let options = { 11 | uri: baseUrl + fileName, 12 | }; 13 | console.log('Bringing in the first responder kit from the mothership.'); 14 | const scriptText = await request.get(options); 15 | new placeScript().placescript(fileName, scriptText, context); 16 | } 17 | 18 | //importing all first responder kit scripts 19 | export let getblitzall = async (context?: sqlops.ObjectExplorerContext) => { 20 | await spblitzscript(baseUrl, "Install-All-Scripts.sql", context); 21 | }; 22 | export let disposable_spblitzall = vscode.commands.registerCommand('extension.sp_blitzall', getblitzall); 23 | 24 | //importing spblitz script 25 | let getblitz = async () => { 26 | await spblitzscript(baseUrl,"sp_Blitz.sql"); 27 | }; 28 | export let disposable_spblitz = vscode.commands.registerCommand('extension.sp_blitz', getblitz); 29 | 30 | 31 | //importing spblitzcache script 32 | let getblitzcache = async () => { 33 | await spblitzscript(baseUrl, "sp_BlitzCache.sql"); 34 | }; 35 | export let disposable_spblitzcache = vscode.commands.registerCommand('extension.sp_blitzcache', getblitzcache); 36 | 37 | //importing spblitzfirst script 38 | let getblitzfirst = async () => { 39 | await spblitzscript(baseUrl, "sp_BlitzFirst.sql"); 40 | }; 41 | export let disposable_spblitzfirst = vscode.commands.registerCommand('extension.sp_blitzfirst', getblitzfirst); 42 | 43 | //importing spblitzwho script 44 | let getblitzwho = async () => { 45 | await spblitzscript(baseUrl, "sp_BlitzWho.sql"); 46 | }; 47 | export let disposable_spblitzwho = vscode.commands.registerCommand('extension.sp_blitzwho', getblitzwho); 48 | 49 | //importing spblitzindex script 50 | let getblitzindex = async () => { 51 | await spblitzscript(baseUrl, "sp_BlitzIndex.sql"); 52 | }; 53 | export let disposable_spblitzindex = vscode.commands.registerCommand('extension.sp_blitzindex', getblitzindex); -------------------------------------------------------------------------------- /src/placescript.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as sqlops from 'azdata'; 4 | import * as vscode from 'vscode'; 5 | 6 | export class placeScript { 7 | 8 | private connectionId: string = ''; 9 | private dbName: string = ''; 10 | // places scriptText into fileName editor with current connection 11 | public async placescript(fileName, scriptText, context?: sqlops.ObjectExplorerContext) { 12 | try { 13 | let connection; 14 | if (context) { 15 | let connection = context.connectionProfile; 16 | this.connectionId = connection.id; 17 | this.dbName = context.connectionProfile.databaseName; 18 | await vscode.commands.executeCommand('explorer.query', context.connectionProfile); 19 | } else { 20 | await vscode.commands.executeCommand('newQuery'); 21 | } 22 | 23 | let editor = vscode.window.activeTextEditor; 24 | let doc = editor.document; 25 | editor.edit(edit => { 26 | edit.insert(new vscode.Position(0, 0), scriptText); 27 | }); 28 | 29 | if (context && this.dbName) { 30 | let providerName = context.connectionProfile.providerName; 31 | let dProvider = await sqlops.dataprotocol.getProvider(providerName, sqlops.DataProviderType.ConnectionProvider); 32 | let connectionUri = await sqlops.connection.getUriForConnection(this.connectionId); 33 | await dProvider.changeDatabase(connectionUri,this.dbName); 34 | await sqlops.queryeditor.connect(doc.uri.toString(), this.connectionId); 35 | } 36 | } catch (err) { 37 | vscode.window.showErrorMessage(err); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/runScripts.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import * as vscode from 'vscode'; 3 | import * as sqlops from 'azdata'; 4 | import {placeScript} from './placescript'; 5 | 6 | let runspblitz = async (context?: sqlops.ObjectExplorerContext) => { 7 | console.log('Preparing sample run script.'); 8 | let fileName = "exec_sp_blitz.sql"; 9 | const scriptText = `EXEC [dbo].[sp_Blitz] 10 | @CheckUserDatabaseObjects = 1 , 11 | @CheckProcedureCache = 0 , 12 | @OutputType = 'TABLE' , 13 | @OutputProcedureCache = 0 , 14 | @CheckProcedureCacheFilter = NULL, 15 | @CheckServerInfo = 1 16 | -- uncomment the following line to write results to an output table 17 | --, @OutputDatabaseName = 'DBAtools', @OutputSchemaName = 'dbo', @OutputTableName = 'BlitzResults' 18 | 19 | -- for more info: https://www.brentozar.com/blitz/ 20 | `; 21 | var setting: vscode.Uri = vscode.Uri.parse("untitled:" + fileName); 22 | new placeScript().placescript(fileName,scriptText,context); 23 | }; 24 | export let disposable_runspblitz = vscode.commands.registerCommand('extension.run_sp_blitz', runspblitz); 25 | 26 | let runspblitzindex = async (context?: sqlops.ObjectExplorerContext) => { 27 | console.log('Preparing sample run script.'); 28 | let fileName = "exec_sp_blitzindex.sql"; 29 | let scriptText = ''; 30 | if (context) { 31 | let scriptType = context.nodeInfo.nodeType; 32 | fileName = context.nodeInfo.label + '-' + fileName; 33 | let dbName = context.connectionProfile.databaseName; 34 | switch (scriptType) { 35 | case "Database": { 36 | scriptText = `EXEC [dbo].[sp_BlitzIndex] 37 | @DatabaseName = '${dbName}', 38 | --@TableName = '', 39 | @Mode = 4 40 | --0=Diagnose, 1=Summarize, 2=Index Usage Detail, 3=Missing Index Detail, 4=Diagnose Details`; 41 | break; 42 | } 43 | case "Table": { 44 | let schName: string = context.nodeInfo.metadata.schema; 45 | let tblName: string = context.nodeInfo.metadata.name; 46 | scriptText = `EXEC [dbo].[sp_BlitzIndex] 47 | @DatabaseName = '${dbName}', 48 | @SchemaName = '${schName}', 49 | @TableName = '${tblName}' 50 | `; 51 | break; 52 | } 53 | default: { 54 | scriptText = `EXEC [dbo].[sp_BlitzIndex] 55 | @DatabaseName = '', 56 | --@TableName = '', 57 | @Mode = 4 58 | --0=Diagnose, 1=Summarize, 2=Index Usage Detail, 3=Missing Index Detail, 4=Diagnose Details`; 59 | break; 60 | } 61 | } 62 | } else { 63 | scriptText = `EXEC [dbo].[sp_BlitzIndex] 64 | @DatabaseName = '', 65 | --@TableName = '', 66 | @Mode = 4 67 | --0=Diagnose, 1=Summarize, 2=Index Usage Detail, 3=Missing Index Detail, 4=Diagnose Details`; 68 | } 69 | scriptText += ` 70 | -- for more info: https://www.brentozar.com/blitzindex/ 71 | `; 72 | new placeScript().placescript(fileName,scriptText,context); 73 | 74 | }; 75 | export let disposable_runspblitzindex = vscode.commands.registerCommand('extension.run_sp_blitzindex', runspblitzindex); 76 | 77 | //creating the quickrun script for blitzcache 78 | let runspblitzcache = async () => { 79 | let fileName = "exec_sp_blitzcache.sql"; 80 | console.log('Preparing sample run script.'); 81 | const scriptText = `EXEC [dbo].[sp_BlitzCache] 82 | @SortOrder = 'reads', 83 | -- CPU, executions, xpm, recent compilations, memory grant, writes, all 84 | @Top = 10 85 | 86 | -- for more info: https://www.brentozar.com/blitzcache/ 87 | `; 88 | new placeScript().placescript(fileName,scriptText); 89 | }; 90 | export let disposable_runspblitzcache = vscode.commands.registerCommand('extension.run_sp_blitzcache',runspblitzcache); 91 | 92 | //creating the quickrun script for blitzfirst 93 | let runspblitzfirst = async (context?: sqlops.ObjectExplorerContext) => { 94 | let fileName = "exec_sp_blitzfirst.sql"; 95 | console.log('Preparing sample run script.'); 96 | const scriptText = `EXEC [dbo].[sp_BlitzFirst] 97 | @Seconds = 5, 98 | @ShowSleepingSPIDs = 0, 99 | @ExpertMode = 0 --1 will also run sp_BlitzWho 100 | 101 | -- for more info: https://www.brentozar.com/askbrent/ 102 | `; 103 | new placeScript().placescript(fileName,scriptText,context); 104 | }; 105 | export let disposable_runspblitzfirst = vscode.commands.registerCommand('extension.run_sp_blitzfirst',runspblitzfirst); 106 | 107 | //creating the quickrun script for blitzlock 108 | let runspblitzlock = async (context?: sqlops.ObjectExplorerContext) => { 109 | let fileName = "exec_sp_blitzlock.sql"; 110 | let scriptText = ''; 111 | if (context && context.nodeInfo) { 112 | let scriptType = context.nodeInfo.nodeType; 113 | fileName = context.nodeInfo.label + '-' + fileName; 114 | var nodeBreakdown = context.nodeInfo.nodePath.split("/"); 115 | let dbName = nodeBreakdown[2]; 116 | switch (scriptType) { 117 | case "Database": { 118 | scriptText = `EXEC [dbo].[sp_BlitzLock] 119 | @DatabaseName = '${dbName}', 120 | @Top = 10`; 121 | break; 122 | } 123 | default: { 124 | scriptText = `EXEC [dbo].[sp_BlitzLock] 125 | @Top = 10`; 126 | break; 127 | } 128 | } 129 | } else { 130 | scriptText = `EXEC [dbo].[sp_BlitzLock] 131 | @Top = 10 132 | --@DatabaseName = '',`; 133 | } 134 | scriptText += ` 135 | -- for more info: https://www.brentozar.com/archive/2017/12/introducing-sp_blitzlock-troubleshooting-sql-server-deadlocks/ 136 | `; 137 | new placeScript().placescript(fileName,scriptText,context); 138 | }; 139 | export let disposable_runspblitzlock = vscode.commands.registerCommand('extension.run_sp_blitzlock',runspblitzlock); 140 | 141 | 142 | //creating the quickrun script for whoisactive 143 | let runspwhoisactive = async (context?: sqlops.ObjectExplorerContext) => { 144 | let fileName = "exec_sp_whoisactive.sql"; 145 | console.log('Preparing sample run script.'); 146 | const scriptText = `EXEC sp_WhoIsActive 147 | @find_block_leaders = 1, 148 | @sort_order = '[blocked_session_count] DESC' 149 | -- @filter = '', 150 | -- @filter_type = 'session', 151 | -- @not_filter = '', 152 | -- @not_filter_type = 'session', 153 | -- @show_own_spid = 0, 154 | -- @show_system_spids = 0, 155 | -- @show_sleeping_spids = 1, 156 | -- @get_full_inner_text = 0, 157 | -- @get_plans = 0, 158 | -- @get_outer_command = 0, 159 | -- @get_transaction_info = 0, 160 | -- @get_task_info = 1, 161 | -- @get_locks = 0, 162 | -- @get_avg_time = 0, 163 | -- @get_additional_info = 0, 164 | -- @delta_interval = 0, 165 | -- @output_column_list = '[dd%][session_id][sql_text][sql_command][login_name][wait_info][tasks][tran_log%][cpu%][temp%][block%][reads%][writes%][context%][physical%][query_plan][locks][%]', 166 | -- @format_output = 1, 167 | -- @destination_table = '', 168 | -- @return_schema = 0, 169 | -- @help = 0 170 | 171 | -- for more info: http://whoisactive.com/docs/ 172 | `; 173 | new placeScript().placescript(fileName,scriptText,context); 174 | }; 175 | export let disposable_runspwhoisactive = vscode.commands.registerCommand('extension.run_sp_whoisactive',runspwhoisactive); 176 | -------------------------------------------------------------------------------- /src/test/extension.test.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Note: This example test is leveraging the Mocha test framework. 3 | // Please refer to their documentation on https://mochajs.org/ for help. 4 | // 5 | 6 | // The module 'assert' provides assertion methods from node 7 | import * as assert from 'assert'; 8 | 9 | // You can import and use all API from the 'vscode' module 10 | // as well as import your extension to test it 11 | // import * as vscode from 'vscode'; 12 | // import * as myExtension from '../extension'; 13 | 14 | // Defines a Mocha test suite to group tests of similar kind together 15 | suite("Extension Tests", function () { 16 | 17 | // Defines a Mocha unit test 18 | test("Something 1", function() { 19 | assert.equal(-1, [1, 2, 3].indexOf(5)); 20 | assert.equal(-1, [1, 2, 3].indexOf(0)); 21 | }); 22 | }); -------------------------------------------------------------------------------- /src/test/index.ts: -------------------------------------------------------------------------------- 1 | // 2 | // PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING 3 | // 4 | // This file is providing the test runner to use when running extension tests. 5 | // By default the test runner in use is Mocha based. 6 | // 7 | // You can provide your own test runner if you want to override it by exporting 8 | // a function run(testRoot: string, clb: (error:Error) => void) that the extension 9 | // host can call to run the tests. The test runner is expected to use console.log 10 | // to report the results back to the caller. When the tests are finished, return 11 | // a possible error to the callback or null if none. 12 | 13 | import * as testRunner from 'vscode/lib/testrunner'; 14 | 15 | // You can directly control Mocha options by uncommenting the following lines 16 | // See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info 17 | testRunner.configure({ 18 | ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.) 19 | useColors: true // colored output from test results 20 | }); 21 | 22 | module.exports = testRunner; -------------------------------------------------------------------------------- /src/typings/azdata.proposed.d.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the Source EULA. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | // This is the place for API experiments and proposal. 7 | 8 | import * as vscode from 'vscode'; 9 | 10 | declare module 'azdata' { 11 | /** 12 | * Namespace for connection management 13 | */ 14 | export namespace connection { 15 | export type ConnectionEventType = 16 | | 'onConnect' 17 | | 'onDisconnect' 18 | | 'onConnectionChanged'; 19 | 20 | export interface ConnectionEventListener { 21 | onConnectionEvent(type: ConnectionEventType, ownerUri: string, args: IConnectionProfile): void; 22 | } 23 | 24 | /** 25 | * Register a connection event listener 26 | */ 27 | export function registerConnectionEventListener(listener: connection.ConnectionEventListener): void; 28 | } 29 | 30 | 31 | export type SqlDbType = 'BigInt' | 'Binary' | 'Bit' | 'Char' | 'DateTime' | 'Decimal' 32 | | 'Float' | 'Image' | 'Int' | 'Money' | 'NChar' | 'NText' | 'NVarChar' | 'Real' 33 | | 'UniqueIdentifier' | 'SmallDateTime' | 'SmallInt' | 'SmallMoney' | 'Text' | 'Timestamp' 34 | | 'TinyInt' | 'VarBinary' | 'VarChar' | 'Variant' | 'Xml' | 'Udt' | 'Structured' | 'Date' 35 | | 'Time' | 'DateTime2' | 'DateTimeOffset'; 36 | 37 | export interface SimpleColumnInfo { 38 | name: string; 39 | /** 40 | * This is expected to match the SqlDbTypes for serialization purposes 41 | */ 42 | dataTypeName: SqlDbType; 43 | } 44 | export interface SerializeDataStartRequestParams { 45 | /** 46 | * 'csv', 'json', 'excel', 'xml' 47 | */ 48 | saveFormat: string; 49 | filePath: string; 50 | isLastBatch: boolean; 51 | rows: DbCellValue[][]; 52 | columns: SimpleColumnInfo[]; 53 | includeHeaders?: boolean; 54 | delimiter?: string; 55 | lineSeperator?: string; 56 | textIdentifier?: string; 57 | encoding?: string; 58 | formatted?: boolean; 59 | } 60 | 61 | export interface SerializeDataContinueRequestParams { 62 | filePath: string; 63 | isLastBatch: boolean; 64 | rows: DbCellValue[][]; 65 | } 66 | 67 | export interface SerializeDataResult { 68 | messages: string; 69 | succeeded: boolean; 70 | } 71 | 72 | export interface SerializationProvider extends DataProvider { 73 | startSerialization(requestParams: SerializeDataStartRequestParams): Thenable; 74 | continueSerialization(requestParams: SerializeDataContinueRequestParams): Thenable; 75 | } 76 | 77 | 78 | export namespace dataprotocol { 79 | export function registerSerializationProvider(provider: SerializationProvider): vscode.Disposable; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/updateCheck.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import * as sqlops from 'azdata'; 4 | import * as vscode from 'vscode'; 5 | import * as request from 'request-promise-native'; 6 | import { getblitzall } from './getScripts'; 7 | import * as apiConfig from './apiconfig'; 8 | let apiconfig: apiConfig.apiconfig = require('../apiconfig.json'); 9 | 10 | // checking spblitz versioning 11 | let getblitzversion = async (context?: sqlops.ObjectExplorerContext) => { 12 | let updateReturn = await checkForUpdates(context); 13 | if (updateReturn) { 14 | if (updateReturn == 'update') { 15 | if (context) { 16 | getblitzall(context); 17 | } else { 18 | getblitzall(); 19 | } 20 | } else if (updateReturn != '') { 21 | let versionURL = 'https://github.com/BrentOzarULTD/SQL-Server-First-Responder-Kit/releases/tag/' + updateReturn; 22 | vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(versionURL)); 23 | } 24 | } 25 | }; 26 | export let disposable_spblitzversion = vscode.commands.registerCommand('extension.sp_blitzversion', getblitzversion); 27 | 28 | async function checkForUpdates(context?: sqlops.ObjectExplorerContext): Promise { 29 | let baseUrl = "https://api.github.com/repos/BrentOzarULTD/SQL-Server-First-Responder-Kit/releases/latest"; 30 | let apitoken = 'token ' + apiconfig.token; 31 | 32 | try { 33 | var connectId; 34 | if (context) { 35 | let connection = context.connectionProfile; 36 | connectId = connection.id; 37 | let connectionMaybe = await sqlops.connection.getCurrentConnection(); 38 | if (!connectionMaybe) { 39 | throw("Connect to server before checking First Responder Kit version."); 40 | } 41 | } else { 42 | let connection = await sqlops.connection.getCurrentConnection(); 43 | if (!connection) { 44 | throw("Connect to server before checking First Responder Kit version."); 45 | } 46 | connectId = connection.connectionId; 47 | } 48 | vscode.window.showInformationMessage("Checking First Responder Kit for Updates"); 49 | 50 | let query = `declare @versionno datetime 51 | DECLARE @VERSION VARCHAR(30) 52 | 53 | IF OBJECT_ID('dbo.sp_Blitz') IS NULL 54 | set @versionno = '1/1/1900' 55 | ELSE 56 | BEGIN 57 | BEGIN TRY 58 | exec sp_blitz @VERSIONCHECKMODE = 1, @VERSION = @VERSION OUTPUT, @versiondate = @versionno output; 59 | END TRY 60 | BEGIN CATCH 61 | exec sp_blitz @help = 1, @versiondate = @versionno output 62 | END CATCH 63 | END 64 | 65 | select convert(varchar(10),@versionno,112) as versionno`; 66 | 67 | let connectionUri = await sqlops.connection.getUriForConnection(connectId); 68 | let queryProvider = sqlops.dataprotocol.getProvider(context.connectionProfile.providerName, sqlops.DataProviderType.QueryProvider); 69 | let results = await queryProvider.runQueryAndReturn(connectionUri, query); 70 | let cell = results.rows[0][0]; 71 | let currentVersion = cell.displayValue; 72 | 73 | //get live most recent version from github 74 | var options = { 75 | uri: baseUrl, 76 | headers: { 77 | 'Authorization': apitoken, 78 | 'User-Agent': 'Request-Promise' 79 | }, 80 | json: true, 81 | simple: false 82 | }; 83 | var scriptText = await request.get(options); 84 | let recentVersion = scriptText.tag_name; 85 | 86 | //compare against db version 87 | if (currentVersion == '19000101') { 88 | let updateMsg = 'First Responder Kit not detected on this server. Current version of First Responder Kit is ' + recentVersion + '.' 89 | var buttonName = await vscode.window.showInformationMessage(updateMsg, {modal:false}, "Get It Now", "Tell Me More"); 90 | if (buttonName){ 91 | if (buttonName == "Get It Now") { 92 | return 'update'; 93 | } else if (buttonName == "Tell Me More") { 94 | return recentVersion; 95 | } 96 | } else { 97 | return ''; 98 | } 99 | } 100 | else if (recentVersion > currentVersion) { 101 | let updateMsg = 'New Version of First Responder Kit available (' + recentVersion + '). You have version ' + currentVersion +'.' 102 | var buttonName = await vscode.window.showInformationMessage(updateMsg, {modal:false}, "Get It Now", "Tell Me More"); 103 | if (buttonName){ 104 | if (buttonName == "Get It Now") { 105 | return 'update'; 106 | } else if (buttonName == "Tell Me More") { 107 | return recentVersion; 108 | } 109 | } else { 110 | return ''; 111 | } 112 | } else { 113 | vscode.window.showInformationMessage("You're up to date!", {modal:false}, "Close"); 114 | return ''; 115 | } 116 | 117 | } catch (e) { 118 | vscode.window.showErrorMessage(e); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | /* Strict Type-Checking Option */ 12 | "strict": false, /* enable all strict type-checking options */ 13 | /* Additional Checks */ 14 | "noUnusedLocals": false /* Report errors on unused locals. */ 15 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 16 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 17 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 18 | }, 19 | "exclude": [ 20 | "node_modules", 21 | ".vscode-test" 22 | ] 23 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | 5 | /**@type {import('webpack').Configuration}*/ 6 | const config = { 7 | target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ 8 | 9 | entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ 10 | output: { 11 | // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ 12 | path: path.resolve(__dirname, 'dist'), 13 | filename: 'extension.js', 14 | libraryTarget: 'commonjs2', 15 | devtoolModuleFilenameTemplate: '../[resource-path]' 16 | }, 17 | devtool: 'source-map', 18 | externals: { 19 | vscode: 'vscode', // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ 20 | azdata: 'azdata' 21 | }, 22 | resolve: { 23 | // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader 24 | extensions: ['.ts', '.js'] 25 | }, 26 | module: { 27 | rules: [ 28 | { 29 | test: /\.ts$/, 30 | exclude: /node_modules/, 31 | use: [ 32 | { 33 | loader: 'ts-loader' 34 | } 35 | ] 36 | } 37 | ] 38 | } 39 | }; 40 | module.exports = config; --------------------------------------------------------------------------------