Repository: sqlcollaborative/dbachecks Branch: main Commit: 948f90f82fcd Files: 184 Total size: 1.9 MB Directory structure: gitextract_bzjyocov/ ├── .devcontainer/ │ ├── codespaces/ │ │ ├── codespaces-docker-compose.yml │ │ └── devcontainer.json │ ├── devcontainer.json │ └── docker-compose.yml ├── .gitattributes ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── feature_request.md │ │ └── question.md │ ├── Pull_Request_Template.md │ ├── issue_template.md │ └── workflows/ │ ├── PR-PesterTest.yml │ ├── PR.yml │ ├── deploy-module.yml │ └── docker-image.yml ├── .gitignore ├── .markdownlint.json ├── .vscode/ │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── GitVersion.yml ├── LICENSE ├── PSScriptAnalyzerSettings.psd1 ├── RELEASE.md ├── RequiredModules.psd1 ├── Resolve-Dependency.ps1 ├── Resolve-Dependency.psd1 ├── SECURITY.md ├── azure-pipelines.yml ├── build.ps1 ├── build.yaml ├── builddocs.ps1 ├── codecov.yml ├── containers/ │ ├── JessAndBeard.psm1 │ ├── base/ │ │ ├── dockerfile │ │ └── profile.ps1 │ ├── second/ │ │ └── dockerfile │ └── third/ │ └── dockerfile ├── dbachecksdevcontainer.code-workspace ├── developing/ │ ├── Archive/ │ │ ├── Get-AllInstanceInfo testing.ps1 │ │ ├── Perf Testing pesterv5.ps1 │ │ ├── PerfAndValidate-Checks.ps1 │ │ ├── Validate v4 adn v5.ps1 │ │ ├── initfields.ps1 │ │ ├── originalGet-AllInstanceInfo.ps1 │ │ ├── pesterv5testing.ps1 │ │ └── tests/ │ │ ├── Help.Exceptions.ps1 │ │ ├── InModule.Help.Exceptions.ps1 │ │ ├── InModule.Help.Tests.ps1 │ │ ├── Integration/ │ │ │ ├── DockerTests.ps1 │ │ │ └── docker-compose.yml │ │ ├── Project.Tests.ps1 │ │ ├── Reset-DbcConfig.Tests.ps1 │ │ ├── Test-SingleFile.ps1 │ │ ├── Unit.Tests.ps1 │ │ ├── build/ │ │ │ ├── Initialize-VstsAgentOnWindowsServerCoreContainer.ps1 │ │ │ ├── Install-VstsAgentOnWindowsServerCoreContainer.ps1 │ │ │ └── Remove-VstsAgentOnWindowsServerCoreContainer.ps1 │ │ ├── checks/ │ │ │ ├── AgentChecks.Tests.ps1 │ │ │ ├── DatabaseChecks.Tests.ps1 │ │ │ ├── InstanceChecks.Tests.ps1 │ │ │ └── ServerChecks.Tests.ps1 │ │ ├── constants.ps1 │ │ ├── functions/ │ │ │ ├── Export-DbcConfig.Tests.ps1 │ │ │ ├── Get-CheckFile.Tests.ps1 │ │ │ ├── Get-CheckInformation.tests.ps1 │ │ │ ├── Get-DatabaseDetail.Tests.ps1 │ │ │ ├── Get-DbcCheck.Tests.ps1 │ │ │ ├── Get-DbcConfig.Tests.ps1 │ │ │ ├── Get-DbcConfigValue.Tests.ps1 │ │ │ ├── Get-DbcTagCollection.Tests.ps1 │ │ │ ├── Import-DbcConfig.Tests.ps1 │ │ │ ├── Invoke-DbcCheck.Tests.ps1 │ │ │ ├── Invoke-DbcConfigFile.Tests.ps1 │ │ │ ├── Set-DbcConfig.Tests.ps1 │ │ │ ├── Set-DbcFile.Tests.ps1 │ │ │ ├── get-check.json │ │ │ └── results.json │ │ └── readme.md │ ├── Howto.md │ ├── Oslo Demo.ps1 │ ├── PSConfEU demo.md │ ├── Robs-Instance.ps1 │ ├── Setting up for Sampler.ps1 │ └── settingupfor2022.ps1 ├── docs/ │ ├── RELEASE.md │ ├── functions/ │ │ ├── Clear-DbcPowerBiDataSource.md │ │ ├── Convert-DbcResult.md │ │ ├── Export-DbcConfig.md │ │ ├── Get-DbcCheck.md │ │ ├── Get-DbcConfig.md │ │ ├── Get-DbcConfigValue.md │ │ ├── Get-DbcReleaseNote.md │ │ ├── Get-DbcTagCollection.md │ │ ├── Import-DbcConfig.md │ │ ├── Invoke-DbcCheck.md │ │ ├── Invoke-DbcConfigFile.md │ │ ├── Reset-DbcConfig.md │ │ ├── Save-DbcRequiredModules.md │ │ ├── Set-DbcCisConfig.md │ │ ├── Set-DbcConfig.md │ │ ├── Set-DbcFile.md │ │ ├── Start-DbcPowerBi.md │ │ ├── Update-DbcPowerBiDataSource.md │ │ ├── Update-DbcRequiredModules.md │ │ └── Write-DbcTable.md │ └── index.md ├── header-mkdocs.yml ├── mkdocs.yml ├── readme.md ├── source/ │ ├── bin/ │ │ ├── dbachecks-FromDatabase.pbit │ │ ├── dbachecks.pbit │ │ └── dbachecks.pbix │ ├── checks/ │ │ ├── Agent.Tests.ps1 │ │ ├── Agentv5.Tests.ps1 │ │ ├── Database.Tests.ps1 │ │ ├── Databasev5.Tests.ps1 │ │ ├── Domain.Tests.ps1 │ │ ├── HADR.Tests.ps1 │ │ ├── Instance.Tests.ps1 │ │ ├── Instancev5.Tests.ps1 │ │ ├── LogShipping.Tests.ps1 │ │ ├── MaintenanceSolution.Tests.ps1 │ │ └── Server.Tests.ps1 │ ├── dbachecks.psd1 │ ├── dbachecks.psm1 │ ├── functions/ │ │ ├── Clear-DbcPowerBiDataSource.ps1 │ │ ├── Convert-DbcResult.ps1 │ │ ├── Export-DbcConfig.ps1 │ │ ├── Get-DbcCheck.ps1 │ │ ├── Get-DbcConfig.ps1 │ │ ├── Get-DbcConfigValue.ps1 │ │ ├── Get-DbcReleaseNote.ps1 │ │ ├── Get-DbcTagCollection.ps1 │ │ ├── Import-DbcConfig.ps1 │ │ ├── Invoke-DbcCheck.ps1 │ │ ├── Invoke-DbcConfigFile.ps1 │ │ ├── Reset-DbcConfig.ps1 │ │ ├── Save-DbcRequiredModules.ps1 │ │ ├── Set-DbcCisConfig.ps1 │ │ ├── Set-DbcConfig.ps1 │ │ ├── Set-DbcFile.ps1 │ │ ├── Start-DbcPowerBi.ps1 │ │ ├── Update-DbcPowerBiDataSource.ps1 │ │ ├── Update-DbcRequiredModules.ps1 │ │ └── Write-DbcTable.ps1 │ ├── internal/ │ │ ├── assertions/ │ │ │ ├── Agent.Assertions.ps1 │ │ │ ├── Database.Assertions.ps1 │ │ │ ├── Instance.Assertions.ps1 │ │ │ └── Server.Assertions.ps1 │ │ ├── configurations/ │ │ │ ├── DbcCheckDescriptions.json │ │ │ └── configuration.ps1 │ │ ├── functions/ │ │ │ ├── Get-AllAgentInfo.ps1 │ │ │ ├── Get-AllDatabaseInfo.ps1 │ │ │ ├── Get-CheckFile.ps1 │ │ │ ├── Get-CheckInformation.ps1 │ │ │ ├── Get-CheckRepo.ps1 │ │ │ ├── Get-ComputerName.ps1 │ │ │ ├── Get-DatabaseDetail.ps1 │ │ │ ├── Get-SqlInstance.ps1 │ │ │ ├── Get-Version.ps1 │ │ │ ├── Get-v5Checks.ps1 │ │ │ ├── Invoke-ConfigurationScript.ps1 │ │ │ ├── Invoke-DbcCheckv4.ps1 │ │ │ ├── Invoke-DbcCheckv5.ps1 │ │ │ ├── New-Json.ps1 │ │ │ ├── NewGet-AllInstanceInfo.ps1 │ │ │ ├── Select-DefaultView.ps1 │ │ │ └── Set-DatabaseForIntegrationTesting.ps1 │ │ ├── scripts/ │ │ │ ├── postimport.ps1 │ │ │ └── preimport.ps1 │ │ └── tepp/ │ │ └── autocomplete.ps1 │ └── xml/ │ └── dbachecks.Format.ps1xml ├── tests/ │ ├── Project.Tests.ps1 │ ├── QA/ │ │ └── module.tests.ps1 │ ├── Unit/ │ │ ├── Private/ │ │ │ └── Get-PrivateFunction.tests.ps1 │ │ └── Public/ │ │ ├── Export-DbcConfig.Tests.ps1 │ │ └── Get-Something.tests.ps1 │ ├── Unit.Tests.ps1 │ └── readme.md └── xml/ └── dbachecks.Format.ps1xml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .devcontainer/codespaces/codespaces-docker-compose.yml ================================================ version: "3" # because it crashes the integrated terminal in codespaces we need an additional devcontainer.json config. Hopefully this will work as expected. # hidden away in the docs :-( https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/introduction-to-dev-containers#devcontainerjson services: dbachecks1: image: sqldbawithabeard/dbachecks1:v2.1.0-beta.1 volumes: - mydata:/var/opt/backups - shared:/shared # Update this to wherever you want VS Code to mount the folder of your project - ..:/workspace:cached ports: - "7401:1433" container_name: dbachecks1 hostname: dbachecks1 dbachecks2: image: sqldbawithabeard/dbachecks2:v2.1.0-beta.1 volumes: - mydata:/var/opt/backups - shared:/shared # Update this to wherever you want VS Code to mount the folder of your project # So that the second container is rebuilt everytime as well - ..:/somewhereweirdworkspace:cached ports: - "7402:1433" container_name: dbachecks2 hostname: dbachecks2 volumes: mydata: shared: ================================================ FILE: .devcontainer/codespaces/devcontainer.json ================================================ { "name": "dbachecks", "workspaceFolder": "/workspace", "dockerComposeFile": [ "codespaces-docker-compose.yml" ], "remoteEnv": { "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}", "MY_SERVER": "dbachecks1" }, "service": "dbachecks1", "settings": { "editor.renderWhitespace": "all", "editor.bracketPairColorization.enabled": true, "editor.guides.bracketPairs": true, "editor.inlineSuggest.enabled": true, "editor.mouseWheelZoom": true, "editor.rulers": [ 100 ], "editor.wordWrapColumn": 100, "editor.wordWrap": "bounded", "files.defaultLanguage": "powershell", "git.autofetch": true, "powershell.scriptAnalysis.settingsPath": "PSScriptAnalyzerSettings.psd1", "powershell.integratedConsole.focusConsoleOnExecute": true, "powershell.codeFormatting.preset": "OTBS", "powershell.codeFormatting.trimWhitespaceAroundPipe": true, "powershell.codeFormatting.useCorrectCasing": true, "powershell.codeFormatting.newLineAfterCloseBrace": true, "powershell.codeFormatting.newLineAfterOpenBrace": true, "powershell.codeFormatting.whitespaceAroundOperator": true, "powershell.codeFormatting.addWhitespaceAroundPipe": true, "#terminal.integrated.profiles.linux#": { "pwsh": { "path": "pwsh", "icon": "terminal-powershell" } }, "terminal.integrated.defaultProfile.linux": "pwsh" }, "extensions": [ "ms-vscode.powershell", "github.vscode-pull-request-github", "2gua.rainbow-brackets", "oderwat.indent-rainbow", "mhutchie.git-graph", "usernamehw.errorlens", "GitHub.copilot", "eamodio.gitlens", "TylerLeonhardt.vscode-inline-values-powershell", "cschleiden.vscode-github-actions", "ms-mssql.mssql", "Gruntfuggly.todo-tree" ], "shutdownAction": "stopCompose", "remoteUser": "root" // not ideal - prob need to setup a non-root user and use that instead. permissions issue without this! } ================================================ FILE: .devcontainer/devcontainer.json ================================================ { "name": "dbachecks", "workspaceFolder": "/workspace", "dockerComposeFile": [ "docker-compose.yml" ], "remoteEnv": { "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}", "MY_SERVER": "dbachecks1" }, "service": "dbachecks1", "shutdownAction": "stopCompose", "remoteUser": "root", // not ideal - prob need to setup a non-root ,user and use that instead. permissions issue without this! "customizations": { "vscode": { "extensions": [ "ms-vscode.powershell", "github.vscode-pull-request-github", "oderwat.indent-rainbow", "mhutchie.git-graph", "usernamehw.errorlens", "GitHub.copilot", "eamodio.gitlens", "TylerLeonhardt.vscode-inline-values-powershell", "cschleiden.vscode-github-actions", "ms-mssql.mssql", "Gruntfuggly.todo-tree", "streetsidesoftware.code-spell-checker" ], "settings": { "editor.renderWhitespace": "all", "editor.bracketPairColorization.enabled": true, "editor.guides.bracketPairs": true, "editor.inlineSuggest.enabled": true, "editor.mouseWheelZoom": true, "editor.rulers": [ 100 ], "editor.wordWrapColumn": 100, "editor.wordWrap": "bounded", "files.defaultLanguage": "powershell", "git.autofetch": true, "powershell.developer.bundledModulesPath": "${cwd}/output/RequiredModules", "powershell.scriptAnalysis.settingsPath": "PSScriptAnalyzerSettings.psd1", "powershell.integratedConsole.focusConsoleOnExecute": true, "powershell.codeFormatting.preset": "OTBS", "powershell.codeFormatting.trimWhitespaceAroundPipe": true, "powershell.codeFormatting.useCorrectCasing": true, "powershell.codeFormatting.newLineAfterCloseBrace": true, "powershell.codeFormatting.newLineAfterOpenBrace": true, "powershell.codeFormatting.whitespaceBeforeOpenBrace": true, "powershell.codeFormatting.whitespaceBeforeOpenParen": true, "powershell.codeFormatting.whitespaceAroundOperator": true, "powershell.codeFormatting.whitespaceAfterSeparator": true, "powershell.codeFormatting.addWhitespaceAroundPipe": true, "powershell.codeFormatting.openBraceOnSameLine": true, "powershell.codeFormatting.ignoreOneLineBlock": true, "powershell.codeFormatting.pipelineIndentationStyle": "IncreaseIndentationAfterEveryPipeline", "powershell.codeFormatting.alignPropertyValuePairs": true, "powershell.codeFormatting.blankLinesAroundCommentHelpBlock": true, "powershell.codeFormatting.blankLinesAroundFunctionDefinitionBody": true, "powershell.codeFormatting.blankLinesAroundPipeline": true, "powershell.codeFormatting.blankLinesAroundRegion": true, "powershell.codeFormatting.blankLinesBeforeCloseBrace": true, "powershell.codeFormatting.blankLinesBeforeFirstLine": true, "powershell.codeFormatting.blankLinesBeforeOpenBrace": true, "powershell.codeFormatting.blankLinesBetweenMemberDefinition": true, "powershell.codeFormatting.blankLinesBetweenUsings": true, "powershell.codeFormatting.collapseBracesToIndentation": true, "powershell.codeFormatting.collapsePipeline": true, "powershell.codeFormatting.newLineAfterCloseBraceInBlock": true, "powershell.codeFormatting.newLineAfterCloseBraceInElse": true, "powershell.codeFormatting.newLineAfterCloseBraceInFunction": true, "powershell.codeFormatting.newLineAfterCloseBraceInIf": true, "powershell.codeFormatting.newLineAfterCloseBraceInSwitch": true, "powershell.codeFormatting.newLineAfterCloseBraceInTry": true, "powershell.codeFormatting.newLineAfterCloseBraceInWhile": true, "powershell.codeFormatting.newLineAfterColonInHashtable": true, "powershell.codeFormatting.newLineAfterComma": true, "powershell.codeFormatting.newLineAfterDoWhile": true, "powershell.codeFormatting.newLineAfterFor": true, "powershell.codeFormatting.newLineAfterForEach": true, "powershell.codeFormatting.newLineAfterIf": true, "powershell.codeFormatting.newLineAfterOpenBraceInBlock": true, "powershell.codeFormatting.newLineAfterOpenBraceInElse": true, "powershell.codeFormatting.newLineAfterOpenBraceInFunction": true, "powershell.codeFormatting.newLineAfterOpenBraceInIf": true, "powershell.codeFormatting.newLineAfterOpenBraceInSwitch": true, "powershell.codeFormatting.newLineAfterOpenBraceInTry": true, "powershell.codeFormatting.newLineAfterOpenBraceInWhile": true, "powershell.codeFormatting.newLineAfterSwitch": true, "powershell.codeFormatting.newLineAfterTry": true, "powershell.codeFormatting.newLineAfterWhile": true, "powershell.codeFormatting.newLineBeforeCloseBrace": true, "powershell.codeFormatting.newLineBeforeElse": true, "powershell.codeFormatting.newLineBeforeElseIf": true, "powershell.codeFormatting.newLineBeforeCatch": true, "powershell.codeFormatting.newLineBeforeFinally": true, "powershell.codeFormatting.newLineBetweenTypeDefinitionMembers": true, "powershell.codeFormatting.pipelineIndentation": 4, "powershell.codeFormatting.spaceAfterComma": true, "powershell.codeFormatting.spaceAfterSemicolon": true, "powershell.codeFormatting.spaceAroundOperator": true, "powershell.codeFormatting.spaceBeforeComma": true, "powershell.codeFormatting.spaceBeforeSemicolon": true, "powershell.codeFormatting.spaceBetweenEmptyBraces": true, "powershell.codeFormatting.spaceBetweenEmptyParenthesis": true, "powershell.codeFormatting.useConsistentIndentation": true, "powershell.codeFormatting.useCorrectCasingForCommand": true, "powershell.codeFormatting.useCorrectCasingForParameter": true, "powershell.codeFormatting.useCorrectCasingForKeyword": true, "powershell.codeFormatting.useCorrectCasingForType": true, "powershell.codeFormatting.useCorrectCasingForVariable": true, "powershell.codeFormatting.useConsistentWhitespace": true, "powershell.codeFormatting.useCorrectCasingForAttribute": true, "powershell.codeFormatting.useCorrectCasingForProperty": true, "powershell.codeFormatting.useCorrectCasingForEnum": true, "powershell.codeFormatting.useCorrectCasingForMethod": true, "powershell.codeFormatting.useCorrectCasingForFunction": true, "powershell.codeFormatting.useCorrectCasingForClass": true, "powershell.codeFormatting.useCorrectCasingForInterface": true, "powershell.codeFormatting.useCorrectCasingForNamespace": true, "powershell.codeFormatting.useCorrectCasingForModule": true, "powershell.codeFormatting.useCorrectCasingForWorkflow": true, "powershell.codeFormatting.useCorrectCasingForParameterSet": true, "powershell.codeFormatting.useCorrectCasingForVariableInForLoop": true, "powershell.codeFormatting.useCorrectCasingForDSCResource": true, "powershell.codeFormatting.useCorrectCasingForDSCResourceParameter": true, "powershell.codeFormatting.useCorrectCasingForEnumMember": true, "powershell.codeFormatting.useCorrectCasingForCommentHelp": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpParameter": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpKeyword": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpParameterSet": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpType": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpFunction": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpWorkflow": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpModule": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpClass": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpInterface": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpEnum": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpDSCResource": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpExample": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpInputs": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpOutputs": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpNotes": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpLink": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpComponent": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpRole": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpFunctionality": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpForwardHelpCategory": true, "powershell.codeFormatting.useCorrectCasingForCommentHelpForwardHelpTargetName": true, "powershell.codeFormatting.autoCorrectAliases": true, "powershell.codeFormatting.avoidSemicolonsAsLineTerminators": true, // "powershell.codeFormatting.useConstantStrings": true, "powershell.codeFormatting.whitespaceBetweenParameters": true, "powershell.codeFormatting.whitespaceInsideBrace": true, "powershell.codeFolding.enable": true, "powershell.codeFolding.showLastLine": true, "powershell.enableReferencesCodeLens": true, "editor.formatOnSave": true, "editor.formatOnSaveMode": "file", "editor.formatOnPaste": true, "editor.formatOnType": true, "editor.autoClosingBrackets": "always", "#terminal.integrated.profiles.linux#": { "pwsh": { "path": "pwsh", "icon": "terminal-powershell" } }, "terminal.integrated.defaultProfile.linux": "pwsh" } } }, "postCreateCommand": "" } ================================================ FILE: .devcontainer/docker-compose.yml ================================================ version: "3" services: dbachecks1: image: dbachecks/sqlinstance1:v2.38.0 volumes: - mydata:/var/opt/backups - shared:/shared # Update this to wherever you want VS Code to mount the folder of your project - ..:/workspace:cached ports: - "7401:1433" container_name: dbachecks1 hostname: dbachecks1 dbachecks2: image: dbachecks/sqlinstance2:v2.38.0 volumes: - mydata:/var/opt/backups - shared:/shared # Update this to wherever you want VS Code to mount the folder of your project # So that the second container is rebuilt everytime as well - ..:/somewhereweirdworkspace:cached ports: - "7402:1433" container_name: dbachecks2 hostname: dbachecks2 # This is our SQL2022 container dbachecks3: image: dbachecks/sqlinstance3:v2.38.0 volumes: - mydata:/var/opt/backups - shared:/shared # Update this to wherever you want VS Code to mount the folder of your project # So that the second container is rebuilt everytime as well - ..:/somewhereweirdworkspace:cached ports: - "7403:1433" container_name: dbachecks3 hostname: dbachecks3 volumes: mydata: shared: ================================================ FILE: .gitattributes ================================================ # Auto detect text files and perform LF normalization * text=auto # Custom for Visual Studio *.cs diff=csharp # Standard to msysgit *.doc diff=astextplain *.DOC diff=astextplain *.docx diff=astextplain *.DOCX diff=astextplain *.dot diff=astextplain *.DOT diff=astextplain *.pdf diff=astextplain *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: [sqldbawithabeard, jpomfret, ClaudioESSilva, potatoqualitee] ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve --- ## Bug Report ### General Troubleshooting steps - [ ] Verified running the latest release of dbachecks? Does `(Find-Module dbachecks).Version match (Get-Module dbachecks).Version.ToString()` ![image](https://user-images.githubusercontent.com/6729780/37113488-60e5e172-21fa-11e8-8115-814edfbfabb6.png) - [ ] Verified errors are not related to permissions? - [ ] Can duplicate in new/clean PowerShell session (clean = `powershell -NoProfile`)? ### Version Information - Operating System (Name|Version): - PowerShell Version: - SQL Server (Edition|Version): ### Steps to Reproduce <-- PLEASE include as much information as possible if this is a bug report. The more you include the faster we can identify the problem and get it fixed --> - [ ] Attach any screenshots (if possible/allowed) - [ ] Attach output from PowerShell console (if possible/allowed) ### Description of Bug <-- PLEASE include as much information as possible if this is a bug Explain what it does that you would like it not to do or What it doesnt do that you would like it to do :-) --> ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project --- ## Feature Request <-- Simply answer the question - What would you like dbachecks to do that it doesn't? --> ## New Check ### What would you like to check? ### What should be configurable for the results of the check ? <-- A value, a set of properties (like FULL, SIMPLE, BULKLOGGED) --> <-- Should there be any default values for the configs? --> ### What should be able to be excluded from being tested ? <-- Could be databases, Could be Availability Groups etc --> <-- This would not be instances --> ## Additional information ================================================ FILE: .github/ISSUE_TEMPLATE/question.md ================================================ --- name: Question about: Ask a question --- ### Question Feel free to ask a question using this template :-) ================================================ FILE: .github/Pull_Request_Template.md ================================================ # A New PR THANK YOU - We love to get PR's and really appreciate your time and help to improve this module ## Accepting a PR Before we accept the PR - please confirm that you have run the tests locally to avoid our automated build and release process failing. You can see how to do that in our wiki https://github.com/sqlcollaborative/dbachecks/wiki ## Please confirm you have 0 failing Pester Tests [] There are 0 failing Pester tests ## Changes this PR brings Please add below the changes that this PR covers. It doesnt need an essay just the bullet points :-) ================================================ FILE: .github/issue_template.md ================================================ ## Issue This is a bug or unexpected behaviour/feature request/new check/question (delete as applicable) ## Bug Report ### General Troubleshooting steps - [ ] Verified running the latest release of dbachecks? Does `(Find-Module dbachecks).Version match (Get-Module dbachecks).Version.ToString()` ![image](https://user-images.githubusercontent.com/6729780/37113488-60e5e172-21fa-11e8-8115-814edfbfabb6.png) - [ ] Verified errors are not related to permissions? - [ ] Can duplicate in new/clean PowerShell session (clean = `powershell -NoProfile`)? ### Version Information - Operating System (Name|Version): - PowerShell Version: - SQL Server (Edition|Version): ### Steps to Reproduce <-- PLEASE include as much information as possible if this is a bug report. The more you include the faster we can identify the problem and get it fixed --> - [ ] Attach any screenshots (if possible/allowed) - [ ] Attach output from PowerShell console (if possible/allowed) ## Feature Request <-- Simply answer the question - What would you like dbachecks to do that it doesn't? --> ## New Check ### What would you like to check? ### What should be configurable for the results of the check ? <-- A value, a set of properties (like FULL, SIMPLE, BULKLOGGED) --> <-- Should there be any default values for the configs? --> ### What should be able to be excluded from being tested ? <-- Could be databases, Could be Availability Groups etc --> <-- This would not be instances --> ## Additional information ================================================ FILE: .github/workflows/PR-PesterTest.yml ================================================ name: PR-Pester on: pull_request: branches: - development jobs: build: runs-on: windows-latest steps: - name: Checkout code Install and run Pester annoyingly on Windows PowerShell https://github.com/pester/Pester/issues/1295 uses: actions/checkout@v2.1.0 - run: | pwd $manifest = Import-PowershellDataFile -Path .\dbachecks.psd1 $PSFrameworkVersion = $manifest.RequiredModules.Where{$_.ModuleName -eq 'PSFramework'}.ModuleVersion $dbatoolsVersion = $manifest.RequiredModules.Where{$_.ModuleName -eq 'dbatools'}.ModuleVersion Install-Module Pester -RequiredVersion 4.10.0 -Force Install-Module dbatools -RequiredVersion $dbatoolsVersion -Force Install-Module PSFramework -RequiredVersion $PsFrameworkVersion -Force Import-Module .\dbachecks.psd1 -Verbose $PesterResults = Invoke-Pester .\tests -ExcludeTag Integration -Show Fails -PassThru If($PesterResults.FailedCount -ne 0){ Write-Warning "Some Tests Failed - See results above" [System.Environment]::Exit(1) } shell: powershell ================================================ FILE: .github/workflows/PR.yml ================================================ on: pull_request: branches: - main paths-ignore: - CHANGELOG.md tags: - '**' - '!*preview*' env: buildFolderName: output buildArtifactName: output testResultFolderName: testResults jobs: Build_Stage_Package_Module: name: Package Module runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v3 with: ref: ${{github.event.pull_request.head.ref}} repository: ${{github.event.pull_request.head.repo.full_name}} # checkout the correct branch name fetch-depth: 0 - name: Install GitVersion uses: gittools/actions/gitversion/setup@v0.9.15 with: versionSpec: 5.x - name: Evaluate Next Version uses: gittools/actions/gitversion/execute@v0.9.15 with: configFilePath: GitVersion.yml - name: Build & Package Module shell: pwsh run: ./build.ps1 -ResolveDependency -tasks pack -Verbose env: ModuleVersion: ${{ env.gitVersion.NuGetVersionV2 }} - name: Publish Build Artifact uses: actions/upload-artifact@v4 with: name: ${{ env.buildArtifactName }} path: ${{ env.buildFolderName }}/ Test_Stage_test_linux: name: Linux runs-on: ubuntu-latest needs: - Build_Stage_Package_Module steps: - name: Checkout Code uses: actions/checkout@v3 with: ref: ${{github.event.pull_request.head.ref}} repository: ${{github.event.pull_request.head.repo.full_name}} # checkout the correct branch name fetch-depth: 0 - name: Download Build Artifact uses: actions/download-artifact@v4 with: name: ${{ env.buildArtifactName }} path: ${{ env.buildFolderName }} - name: Run Tests shell: pwsh run: ./build.ps1 -tasks noop ; ./build.ps1 -tasks test # to get around dbatools failing to load XE.core.dll if - name: Publish Test Artifact uses: actions/upload-artifact@v4 with: path: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/ name: CodeCoverageLinux if: success() || failure() Test_Stage_test_windows_core: name: Windows (PowerShell) runs-on: windows-2019 needs: - Build_Stage_Package_Module steps: - name: Checkout Code uses: actions/checkout@v3 with: ref: ${{github.event.pull_request.head.ref}} repository: ${{github.event.pull_request.head.repo.full_name}} # checkout the correct branch name fetch-depth: 0 - name: Download Build Artifact uses: actions/download-artifact@v4 with: name: ${{ env.buildArtifactName }} path: ${{ env.buildFolderName }} - name: Run Tests shell: pwsh run: ./build.ps1 -tasks noop; ipmo dbatools ; ./build.ps1 -tasks test # to get around dbatools failing to load XE.core.dll if - name: Publish Test Artifact uses: actions/upload-artifact@v4 with: path: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/ name: CodeCoverageWinPS7 if: success() || failure() Test_Stage_test_windows_ps: name: Windows (Windows PowerShell) runs-on: windows-2019 needs: - Build_Stage_Package_Module steps: - name: Checkout Code uses: actions/checkout@v3 with: ref: ${{github.event.pull_request.head.ref}} repository: ${{github.event.pull_request.head.repo.full_name}} # checkout the correct branch name fetch-depth: 0 - name: Download Build Artifact uses: actions/download-artifact@v4 with: name: ${{ env.buildArtifactName }} path: ${{ env.buildFolderName }} - name: Run Tests shell: pwsh run: ./build.ps1 -ResolveDependency -tasks test - name: Publish Test Artifact uses: actions/upload-artifact@v4 with: path: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/ name: CodeCoverageWinPS51 if: success() || failure() Test_Stage_Code_Coverage: name: Publish Code Coverage if: success() || failure() runs-on: ubuntu-latest needs: - Build_Stage_Package_Module - Test_Stage_test_linux - Test_Stage_test_windows_core - Test_Stage_test_windows_ps steps: - name: Checkout Code uses: actions/checkout@v3 with: ref: ${{github.event.pull_request.head.ref}} # checkout the correct branch name repository: ${{github.event.pull_request.head.repo.full_name}} # checkout the correct branch name fetch-depth: 0 - name: Download Test Artifact Linux uses: actions/download-artifact@v4 with: name: CodeCoverageLinux path: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/CodeCoverageLinux/ - name: Download Test Artifact Windows (PS 5.1) uses: actions/download-artifact@v4 with: name: CodeCoverageWinPS51 path: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/CodeCoverageWinPS51/ - name: Download Test Artifact Windows (PS7) uses: actions/download-artifact@v4 with: name: CodeCoverageWinPS7 path: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/CodeCoverageWinPS7/ - name: Publish Linux Test Results id: linux-test-results uses: EnricoMi/publish-unit-test-result-action@v2 if: always() with: nunit_files: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/CodeCoverageLinux/NUnit*.xml check_name: Linux Test Results - name: Publish WinPS51 Test Results id: winps51-test-results uses: EnricoMi/publish-unit-test-result-action@v2 if: always() with: nunit_files: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/CodeCoverageWinPS51/NUnit*.xml check_name: WinPS51 Test Results - name: Publish WinPS71 Test Results id: winps71-test-results uses: EnricoMi/publish-unit-test-result-action@v2 if: always() with: nunit_files: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/CodeCoverageWinPS7/NUnit*.xml check_name: WinPS71 Test Results ================================================ FILE: .github/workflows/deploy-module.yml ================================================ on: push: branches: - main paths-ignore: - CHANGELOG.md - containers/** - .github/** tags: - '**' - '!*preview*' env: buildFolderName: output buildArtifactName: output testResultFolderName: testResults jobs: Build_Stage_Package_Module: name: Package Module runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v3 with: ref: ${{ github.head_ref }} # checkout the correct branch name fetch-depth: 0 - name: Install GitVersion uses: gittools/actions/gitversion/setup@v0.9.15 with: versionSpec: 5.x - name: Evaluate Next Version uses: gittools/actions/gitversion/execute@v0.9.15 with: configFilePath: GitVersion.yml - name: Build & Package Module shell: pwsh run: ./build.ps1 -ResolveDependency -tasks pack -Verbose env: ModuleVersion: ${{ env.gitVersion.NuGetVersionV2 }} - name: Publish Build Artifact uses: actions/upload-artifact@v4 with: name: ${{ env.buildArtifactName }} path: ${{ env.buildFolderName }}/ Test_Stage_test_linux: name: Linux runs-on: ubuntu-latest needs: - Build_Stage_Package_Module steps: - name: Checkout Code uses: actions/checkout@v3 with: ref: ${{ github.head_ref }} # checkout the correct branch name fetch-depth: 0 - name: Download Build Artifact uses: actions/download-artifact@v4 with: name: ${{ env.buildArtifactName }} path: ${{ env.buildFolderName }} - name: Run Tests shell: pwsh run: ./build.ps1 -tasks noop; ipmo dbatools ; ./build.ps1 -tasks test # to get around dbatools failing to load XE.core.dll if - name: Publish Test Artifact uses: actions/upload-artifact@v4 with: path: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/ name: CodeCoverageLinux if: success() || failure() Test_Stage_test_windows_core: name: Windows (PowerShell) runs-on: windows-2019 needs: - Build_Stage_Package_Module steps: - name: Checkout Code uses: actions/checkout@v3 with: ref: ${{ github.head_ref }} # checkout the correct branch name fetch-depth: 0 - name: Download Build Artifact uses: actions/download-artifact@v4 with: name: ${{ env.buildArtifactName }} path: ${{ env.buildFolderName }} - name: Run Tests shell: pwsh run: ./build.ps1 -tasks noop; ipmo dbatools ; ./build.ps1 -tasks test # to get around dbatools failing to load XE.core.dll if - name: Publish Test Artifact uses: actions/upload-artifact@v4 with: path: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/ name: CodeCoverageWinPS7 if: success() || failure() Test_Stage_test_windows_ps: name: Windows (Windows PowerShell) runs-on: windows-2019 needs: - Build_Stage_Package_Module steps: - name: Checkout Code uses: actions/checkout@v3 with: ref: ${{ github.head_ref }} # checkout the correct branch name fetch-depth: 0 - name: Download Build Artifact uses: actions/download-artifact@v4 with: name: ${{ env.buildArtifactName }} path: ${{ env.buildFolderName }} - name: Run Tests shell: pwsh run: ./build.ps1 -ResolveDependency -tasks test - name: Publish Test Artifact uses: actions/upload-artifact@v4 with: path: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/ name: CodeCoverageWinPS51 if: success() || failure() # Test_Stage_test_macos: # name: macOS # runs-on: macos-latest # needs: # - Build_Stage_Package_Module # steps: # - name: Checkout Code # uses: actions/checkout@v3 # with: # ref: ${{ github.head_ref }} # checkout the correct branch name # fetch-depth: 0 # - name: Download Build Artifact # uses: actions/download-artifact@v4 # with: # name: ${{ env.buildArtifactName }} # path: ${{ env.buildFolderName }} # - name: Run Tests # shell: pwsh # run: ./build.ps1 -tasks noop; ipmo dbatools ; ./build.ps1 -tasks test # to get # around dbatools failing to load XE.core.dll if # # - name: Publish Test Artifact # uses: actions/upload-artifact@v4 # with: # path: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/ # name: CodeCoverageMacOS # if: success() || failure() Test_Stage_Code_Coverage: name: Publish Code Coverage if: success() || failure() runs-on: ubuntu-latest needs: - Build_Stage_Package_Module # - Test_Stage_test_macos - Test_Stage_test_linux - Test_Stage_test_windows_core - Test_Stage_test_windows_ps steps: - name: Checkout Code uses: actions/checkout@v3 with: ref: ${{ github.head_ref }} # checkout the correct branch name fetch-depth: 0 # - name: Download Test Artifact macOS # uses: actions/download-artifact@v4 # with: # name: CodeCoverageMacOS # path: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/CodeCoverageMacOS/ - name: Download Test Artifact Linux uses: actions/download-artifact@v4 with: name: CodeCoverageLinux path: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/CodeCoverageLinux/ - name: Download Test Artifact Windows (PS 5.1) uses: actions/download-artifact@v4 with: name: CodeCoverageWinPS51 path: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/CodeCoverageWinPS51/ - name: Download Test Artifact Windows (PS7) uses: actions/download-artifact@v4 with: name: CodeCoverageWinPS7 path: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/CodeCoverageWinPS7/ # - name: Publish MacOs Test Results # id: macos-test-results # uses: EnricoMi/publish-unit-test-result-action@v2 # if: always() # with: # nunit_files: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/#CodeCoverageMacOS/NUnit*.xml # check_name: MacOs Test Results - name: Publish Linux Test Results id: linux-test-results uses: EnricoMi/publish-unit-test-result-action@v2 if: always() with: nunit_files: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/CodeCoverageLinux/NUnit*.xml check_name: Linux Test Results - name: Publish WinPS51 Test Results id: winps51-test-results uses: EnricoMi/publish-unit-test-result-action@v2 if: always() with: nunit_files: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/CodeCoverageWinPS51/NUnit*.xml check_name: WinPS51 Test Results - name: Publish WinPS71 Test Results id: winps71-test-results uses: EnricoMi/publish-unit-test-result-action@v2 if: always() with: nunit_files: ${{ env.buildFolderName }}/${{ env.testResultFolderName }}/CodeCoverageWinPS7/NUnit*.xml check_name: WinPS71 Test Results # - name: Set Macos badge color # shell: bash # run: | # case ${{ fromJSON( steps.macos-test-results.outputs.json ).conclusion }} in # success) # echo "MACOSBADGE_COLOR=31c653" >> $GITHUB_ENV # ;; # failure) # echo "MACOSBADGE_COLOR=800000" >> $GITHUB_ENV # ;; # neutral) # echo "MACOSBADGE_COLOR=696969" >> $GITHUB_ENV # ;; # esac # - name: Create Macos badge # uses: emibcn/badge-action@v1.2.1 # with: # label: Tests # status: '${{ fromJSON( steps.macos-test-results.outputs.json ).formatted.stats.#tests }} tests, ${{ fromJSON( steps.macos-test-results.outputs.json ).formatted.#stats.runs }} runs: ${{ fromJSON( steps.macos-test-results.outputs.json ).#conclusion }}' # color: ${{ env.MACOSBADGE_COLOR }} # path: macos-badge.svg # - name: Upload MacOs badge to Gist # # Upload only for main branch # if: > # github.event_name == 'workflow_run' && github.event.workflow_run.head_branch == #'main' || # github.event_name != 'workflow_run' && github.ref == 'refs/heads/main' # uses: andymckay/append-gist-action@1fbfbbce708a39bd45846f0955ed5521f2099c6d # with: # token: ${{ secrets.GIST_TOKEN }} # gistURL: https://gist.githubusercontent.com/SQLDBAWithABeard/#7a5d2837e29654202f22392187c75fec # file: macos-badge.svg - name: Set Linux badge color shell: bash run: | case ${{ fromJSON( steps.linux-test-results.outputs.json ).conclusion }} in success) echo "LINUXBADGE_COLOR=31c653" >> $GITHUB_ENV ;; failure) echo "LINUXBADGE_COLOR=800000" >> $GITHUB_ENV ;; neutral) echo "LINUXBADGE_COLOR=696969" >> $GITHUB_ENV ;; esac - name: Create Linux badge uses: emibcn/badge-action@v1.2.1 with: label: Tests status: '${{ fromJSON( steps.linux-test-results.outputs.json ).formatted.stats.tests }} tests, ${{ fromJSON( steps.linux-test-results.outputs.json ).formatted.stats.runs }} runs: ${{ fromJSON( steps.linux-test-results.outputs.json ).conclusion }}' color: ${{ env.LINUXBADGE_COLOR }} path: linux-badge.svg - name: Upload Linux badge to Gist # Upload only for main branch if: > github.event_name == 'workflow_run' && github.event.workflow_run.head_branch == 'main' || github.event_name != 'workflow_run' && github.ref == 'refs/heads/main' uses: andymckay/append-gist-action@1fbfbbce708a39bd45846f0955ed5521f2099c6d with: token: ${{ secrets.GIST_TOKEN }} gistURL: https://gist.githubusercontent.com/SQLDBAWithABeard/7a5d2837e29654202f22392187c75fec file: linux-badge.svg - name: Set WinPS51 badge color shell: bash run: | case ${{ fromJSON( steps.winps51-test-results.outputs.json ).conclusion }} in success) echo "WINPS51BADGE_COLOR=31c653" >> $GITHUB_ENV ;; failure) echo "WINPS51BADGE_COLOR=800000" >> $GITHUB_ENV ;; neutral) echo "WINPS51BADGE_COLOR=696969" >> $GITHUB_ENV ;; esac - name: Create WINPS51 badge uses: emibcn/badge-action@v1.2.1 with: label: Tests status: '${{ fromJSON( steps.winps51-test-results.outputs.json ).formatted.stats.tests }} tests, ${{ fromJSON( steps.winps51-test-results.outputs.json ).formatted.stats.runs }} runs: ${{ fromJSON( steps.winps51-test-results.outputs.json ).conclusion }}' color: ${{ env.WINPS51BADGE_COLOR }} path: winps51-badge.svg - name: Upload WINPS51 badge to Gist # Upload only for main branch if: > github.event_name == 'workflow_run' && github.event.workflow_run.head_branch == 'main' || github.event_name != 'workflow_run' && github.ref == 'refs/heads/main' uses: andymckay/append-gist-action@1fbfbbce708a39bd45846f0955ed5521f2099c6d with: token: ${{ secrets.GIST_TOKEN }} gistURL: https://gist.githubusercontent.com/SQLDBAWithABeard/7a5d2837e29654202f22392187c75fec file: winps51-badge.svg - name: Set WinPS7 badge color shell: bash run: | case ${{ fromJSON( steps.winps71-test-results.outputs.json ).conclusion }} in success) echo "WINPS7BADGE_COLOR=31c653" >> $GITHUB_ENV ;; failure) echo "WINPS7BADGE_COLOR=800000" >> $GITHUB_ENV ;; neutral) echo "WINPS7BADGE_COLOR=696969" >> $GITHUB_ENV ;; esac - name: Create WinPS7 badge uses: emibcn/badge-action@v1.2.1 with: label: Tests status: '${{ fromJSON( steps.winps71-test-results.outputs.json ).formatted.stats.tests }} tests, ${{ fromJSON( steps.winps71-test-results.outputs.json ).formatted.stats.runs }} runs: ${{ fromJSON( steps.winps71-test-results.outputs.json ).conclusion }}' color: ${{ env.WINPS7BADGE_COLOR }} path: winps7-badge.svg - name: Upload WINPS7 badge to Gist # Upload only for main branch if: > github.event_name == 'workflow_run' && github.event.workflow_run.head_branch == 'main' || github.event_name != 'workflow_run' && github.ref == 'refs/heads/main' uses: andymckay/append-gist-action@1fbfbbce708a39bd45846f0955ed5521f2099c6d with: token: ${{ secrets.GIST_TOKEN }} gistURL: https://gist.githubusercontent.com/SQLDBAWithABeard/7a5d2837e29654202f22392187c75fec file: winps7-badge.svg Deploy_Stage_Deploy_Module: name: Deploy Module runs-on: ubuntu-latest needs: - Build_Stage_Package_Module - Test_Stage_test_linux - Test_Stage_test_windows_core - Test_Stage_test_windows_ps # - Test_Stage_test_macos - Test_Stage_Code_Coverage if: ${{ success() && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) }} steps: - name: Checkout Code uses: actions/checkout@v3 with: ref: ${{ github.head_ref }} # checkout the correct branch name fetch-depth: 0 - name: Download Build Artifact uses: actions/download-artifact@v4 with: name: ${{ env.buildArtifactName }} path: ${{ env.buildFolderName }} - name: Publish Release shell: pwsh # run: Import-Module ./output/RequiredModules/PowerShellForGitHub/0.16.1/PowerShellForGitHub.psd1 ; ./build.ps1 -tasks publish run: ./build.ps1 -tasks publish env: GitHubToken: ${{ secrets.GitHubToken }} GalleryApiToken: ${{ secrets.GalleryApiToken }} - name: Send Changelog PR shell: pwsh run: Get-Module -Name PowerShellForGitHub -ListAvailable ;./build.ps1 -tasks Create_ChangeLog_GitHub_PR env: GitHubToken: ${{ secrets.GitHubToken }} - name: Merge main -> containers uses: devmasx/merge-branch@1.4.0 with: type: now from_branch: main target_branch: containers github_token: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/docker-image.yml ================================================ name: Docker Image CI on: push: branches: [ containers ] paths: - ".devcontainer/devcontainer.json" - ".devcontainer/docker-compose.yml" - ".devcontainer/codespaces/devcontainer.json" - ".devcontainer/codespaces/codespaces-docker-compose.yml" - containers/** workflow_dispatch: jobs: docker: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 with: fetch-depth: '0' - name: Bump version and push tag id: bump uses: anothrNick/github-tag-action@1.52.0 env: DEFAULT_BUMP: minor GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} WITH_V: true RELEASE_BRANCHES: main, containers - name: Set up QEMU uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Login to DockerHub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push First Container uses: docker/build-push-action@v3 with: push: true context: containers/base/ tags: dbachecks/sqlinstance1:${{ steps.bump.outputs.new_tag }},dbachecks/sqlinstance1:latest - name: Build and push second Container uses: docker/build-push-action@v3 with: push: true context: containers/second/ tags: dbachecks/sqlinstance2:${{ steps.bump.outputs.new_tag }},dbachecks/sqlinstance2:latest - name: Build and push third Container uses: docker/build-push-action@v3 with: push: true context: containers/third/ tags: dbachecks/sqlinstance3:${{ steps.bump.outputs.new_tag }},dbachecks/sqlinstance3:latest - name: Find and Replace uses: jacobtomlinson/gha-find-replace@v2 with: find: "dbachecks/sqlinstance1:.*" replace: "dbachecks/sqlinstance1:${{ steps.bump.outputs.new_tag }}" include: "**docker-compose.yml" - name: Find and Replace Instance2 uses: jacobtomlinson/gha-find-replace@v2 with: find: "dbachecks/sqlinstance2:.*" replace: "dbachecks/sqlinstance2:${{ steps.bump.outputs.new_tag }}" include: "**docker-compose.yml" - name: Find and Replace Instance3 uses: jacobtomlinson/gha-find-replace@v2 with: find: "dbachecks/sqlinstance3:.*" replace: "dbachecks/sqlinstance3:${{ steps.bump.outputs.new_tag }}" include: "**docker-compose.yml" - name: Add & Commit uses: EndBug/add-and-commit@v9 with: author_name: Beardy McBeardFace author_email: mrrobsewell@outlook.com message: 'The Beard says we have another container - This is an automated message' - name: create pull request run: gh pr create -B main -H containers --title 'Merge containers into main [skip ci]' --body 'Created by Github action' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .gitignore ================================================ *.psproj dbachecks.psprojs config.json output/ **.bak *.local.* !**/README.md .kitchen/ *.nupkg *.suo *.user *.coverage .vs .psproj .sln markdownissues.txt node_modules package-lock.json ================================================ FILE: .markdownlint.json ================================================ { "default": true, "MD029": { "style": "one" }, "MD013": true, "MD024": false, "MD034": false, "no-hard-tabs": true } ================================================ FILE: .vscode/launch.json ================================================ { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "PowerShell: Launch Current File", "type": "PowerShell", "request": "launch", "script": "${file}", "cwd": "${file}" } ] } ================================================ FILE: .vscode/settings.json ================================================ { "cSpell.words": [ "auto", "autogrowth", "Boggiano", "checkdb", "count", "cpu", "datafile", "dbachecks", "dbcconfig", "djfcc", "dstrait", "errorlogentries", "errorvar", "failover", "filegroup", "fkck", "growth", "HADR", "Imenes", "kerberos", "logfile", "longrunningjob", "longrunningjobs", "niphod", "notcontactable", "notcontains", "Olas", "pingable", "prioritisation", "prioritised", "Psitem", "Remoting", "sadisabled", "Schenk", "skipall", "SOZDBA", "spns", "synchronised", "tboggiano", "Tempdb", "trusted", "type", "whoisactive", "whoisactivedatabase" ], "[markdown]": { "editor.trimAutoWhitespace": false, "files.trimTrailingWhitespace": false }, "cSpell.enableFiletypes": [ "powershell" ] } ================================================ FILE: .vscode/tasks.json ================================================ { "version": "2.0.0", "_runner": "terminal", "windows": { "options": { "shell": { "executable": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", "args": [ "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command" ] } } }, "linux": { "options": { "shell": { "executable": "/usr/bin/pwsh", "args": [ "-NoProfile", "-Command" ] } } }, "osx": { "options": { "shell": { "executable": "/usr/local/bin/pwsh", "args": [ "-NoProfile", "-Command" ] } } }, "tasks": [ { "label": "build", "type": "shell", "command": "&${cwd}/build.ps1", "args": [], "presentation": { "echo": true, "reveal": "always", "focus": true, "panel": "new", "clear": false }, "runOptions": { "runOn": "default" }, "problemMatcher": [ { "owner": "powershell", "fileLocation": [ "absolute" ], "severity": "error", "pattern": [ { "regexp": "^\\s*(\\[-\\]\\s*.*?)(\\d+)ms\\s*$", "message": 1 }, { "regexp": "(.*)", "code": 1 }, { "regexp": "" }, { "regexp": "^.*,\\s*(.*):\\s*line\\s*(\\d+).*", "file": 1, "line": 2 } ] } ] }, { "label": "test", "type": "shell", "command": "&${cwd}/build.ps1", "args": ["-AutoRestore","-Tasks","test"], "presentation": { "echo": true, "reveal": "always", "focus": true, "panel": "dedicated", "showReuseMessage": true, "clear": false }, "problemMatcher": [ { "owner": "powershell", "fileLocation": [ "absolute" ], "severity": "error", "pattern": [ { "regexp": "^\\s*(\\[-\\]\\s*.*?)(\\d+)ms\\s*$", "message": 1 }, { "regexp": "(.*)", "code": 1 }, { "regexp": "" }, { "regexp": "^.*,\\s*(.*):\\s*line\\s*(\\d+).*", "file": 1, "line": 2 } ] } ] } ] } ================================================ FILE: CHANGELOG.md ================================================ # Changelog for workspace The format is based on and uses the types of changes according to [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] - fixed typo in Invoke-PerfAndValidateCheck so we know which version we're looking at - Updated HADR checks to use dbatools new outputs ## [3.0.2] - 2025-03-10 ### Added - added pester tests to check that changelog is edited. - and a space for the demos ### Changed - Fix to Invoke-DbcCheck so that tests that have not been converted to v5 produce warning messages. ## [3.0.1-preview0026] - 2023-08-28 ### Added - Pester v5 support for agent checks. ## [3.0.1-preview0025] - 2023-08-28 ### Added - PageVerify check converted to V5 functionality. ### Changed - For changes in existing functionality. ### Deprecated - For soon-to-be removed features. ### Removed - For now removed features. ### Fixed - For any bug fix. ### Security - In case of vulnerabilities. ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing ## Welcome Before we go any further, thanks for being here. Thanks for using dbachecks and especially thanks for being here and looking into how you can help! ## Important resources - docs - bugs - communicate with the team - slack - github discussions? - presentations\blogs? ## Running the Tests If want to know how to run this module's tests you can look at the [Testing Guidelines](https://dsccommunity.org/guidelines/testing-guidelines/#running-tests) ## Environment details We strongly believe that 'every repo should have a devcontainer' and therefore we've built one for this project that includes 3 SQL Servers and everything you need to develop and build the dbachecks module. It's magic! ### Prerequisites: In order to use the devcontainer there are a few things you need to get started. - [Docker](https://www.docker.com/get-started) - [git](https://git-scm.com/downloads) - [VSCode](https://code.visualstudio.com/download) - [Remote Development Extension for VSCode](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) ### Setup Once the prerequisites are in place follow these steps to download the repo and start up the devcontainer. The first time you build the devcontainer it will need to pull down the images so that could take a hot second depending on your internet speeds. 1. Download the repo from GitHub ```PowerShell # change directory to where you'd like the repo to go cd C:\GitHub\ # clone the repo from GitHub git clone https://github.com/dataplat/dbachecks # move into the folder cd .\dbachecks\ # open VSCode code . ``` 754662. Once code opens, there should be a toast in the bottom right that suggests you 'ReOpen in Container'. 1. The first time you do this it may take a little, and you'll need an internet connection, as it'll download the container images used in our demos ### Develop & Build We are using the [Sampler](https://github.com/gaelcolas/Sampler) Powershell Module to structure our module. This makes it easier to develop and test the module locally. The workflow for using this and developing the code - for example to add a new Database level check you could follow this guide. 1. Download the repo locally and create a new branch to develop on ```PowerShell git checkout -b newStuff # give it a proper name! ``` 1. Develop in the source repository, to add a check you need to add the following code: - add check code to `source/checks/DatabaseV5.Tests.ps1` - add required configurations to `source/internal/configurations/configuration.ps1` - `skip.database.checkName` - `policy.database.checkNameExcludeDb` - add required properties to object info to `source/internal/functions/Get-AllDatabaseInfo.ps1` 1. Build the module ```PowerShell ./build.ps1 -Tasks build ``` 1. Sampler automatically adds the new version to your path you can prove that with the following code: ```PowerShell get-module dbachecks -ListAvailable | Select-Object Name, ModuleBase ``` 1. Import new version of the module ```PowerShell Import-Module dbachecks -force ``` 1. Test out the new code ```PowerShell # save the password to make for easy connections $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $show = 'All' $checks = 'RecoveryModel' # <-- change this to your new check name $sqlinstances = 'localhost,7401', 'localhost,7402', 'localhost,7403' #$sqlinstances = 'dbachecks1', 'dbachecks2', 'dbachecks3' # need client aliases for this to work New-DbaClientAlias # Run v5 checks $v5code = Invoke-DbcCheck -SqlInstance $Sqlinstances -SqlCredential $cred -Check $Checks -legacy $false -Show $show -PassThru -Verbose ``` 1. If you are working on the v4 --> v5 upgrade you can also confirm your v5 test results match v4 with the following ```PowerShell # save the password to make for easy connections $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $show = 'All' $checks = 'RecoveryModel' # <-- change this to your new check name $sqlinstances = 'localhost,7401', 'localhost,7402', 'localhost,7403' #$sqlinstances = 'dbachecks1', 'dbachecks2', 'dbachecks3' # need client aliases for this to work New-DbaClientAlias # Check results of the tests - are we testing the same things with the same results for v4 & v5 Invoke-PerfAndValidateCheck -SQLInstances $sqlinstances -Checks $Checks # Include the specific details for the perf testing Invoke-PerfAndValidateCheck -SQLInstances $sqlinstances -Checks $Checks -PerfDetail # Include the test results - this helps troubleshooting if your tests aren't the same Invoke-PerfAndValidateCheck -SQLInstances $sqlinstances -Checks $Checks -showTestResults ``` 1. Once you are happy with your code, push your branch to GitHub and create a PR against the dbachecks repo. 1. Thanks! ### Rebuild your devcontainer The only way to properly rebuild to ensure that all volumes etc are removed is to open up a console or PowerShell window outside of the devcontainer and run the following: ```PowerShell cd \path-of-dbachecks-folder\.devcontainer docker-compose -f "docker-compose.yml" -p "bitsdbatools_devcontainer" down ``` ## How to submit changes: TODO: Pull Request protocol etc. You might also include what response they'll get back from the team on submission, or any caveats about the speed of response. ## How to report a bug: TODO: Bugs are problems in code, in the functionality of an application or in its UI design; you can submit them through "bug trackers" and most projects invite you to do so, so that they may "debug" with more efficiency and the input of a contributor. Take a look at Atom's example for how to teach people to report bugs to your project. ## Templates: TODO: in this section of your file, you might also want to link to a bug report "template" like this one here which contributors can copy and add context to; this will keep your bugs tidy and relevant. ## Style Guide TODO: include extensions and vscode settings we use to keep things neat ## Code of Conduct TODO: maybe beef this out - stolen from data sat repo for now. We expect and demand that you follow some basic rules. Nothing dramatic here. There will be a proper code of conduct for the websites added soon, but in this repository BE EXCELLENT TO EACH OTHER Do I need to say more? If your behaviour or communication does not fit into this statement, we do not wish for you to help us. ================================================ FILE: GitVersion.yml ================================================ mode: ContinuousDelivery next-version: 3.0.0 major-version-bump-message: '(breaking\schange|breaking|major)\b' minor-version-bump-message: '(adds?|features?|minor)\b' patch-version-bump-message: '\s?(fix|patch)' no-bump-message: '\+semver:\s?(none|skip)' assembly-informational-format: '{NuGetVersionV2}+Sha.{Sha}.Date.{CommitDate}' branches: master: tag: preview regex: ^main$ pull-request: tag: PR feature: tag: useBranchName increment: Minor regex: f(eature(s)?)?[\/-] source-branches: ['master'] hotfix: tag: fix increment: Patch regex: (hot)?fix(es)?[\/-] source-branches: ['master'] ignore: sha: [] merge-message-formats: {} # feature: # tag: useBranchName # increment: Minor # regex: f(eature(s)?)?[/-] # source-branches: ['master'] # hotfix: # tag: fix # increment: Patch # regex: (hot)?fix(es)?[/-] # source-branches: ['master'] ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2017 Chrissy LeMaire Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: PSScriptAnalyzerSettings.psd1 ================================================ # PSScriptAnalyzerSettings.psd1 # Settings for PSScriptAnalyzer invocation. @{ Rules = @{ PSUseCompatibleCommands = @{ # Turns the rule on Enable = $true # Lists the PowerShell platforms we want to check compatibility with TargetProfiles = @( 'win-8_x64_10.0.17763.0_7.0.0_x64_3.1.2_core.json', 'ubuntu_x64_18.04_7.0.0_x64_3.1.2_core.json', 'win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework' # 'win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework' ) # You can specify commands to not check like this, which also will ignore its parameters: IgnoreCommands = @( 'It', # Because Pester! 'Should', # Because Pester! 'Context', # Because Pester! 'BeforeAll', # Because Pester! 'AfterAll', # Because Pester! 'Describe' # Because Pester! 'Invoke-Pester' #Because Pester! 'InModuleScope' #Because Pester! 'Mock' #Because Pester! 'Assert-MockCalled' #Because Pester! 'Get-LocalGroupMember' # Because we handle it ) } PSUseCompatibleSyntax = @{ # This turns the rule on (setting it to false will turn it off) Enable = $true # Simply list the targeted versions of PowerShell here TargetVersions = @( '5.1' '6.1', '6.2', '7.0' ) } } # Do not analyze the following rules. Use ExcludeRules when you have # commented out the IncludeRules settings above and want to include all # the default rules except for those you exclude below. # Note: if a rule is in both c and ExcludeRules, the rule # will be excluded. ExcludeRules = @('PSAvoidAssignmentToAutomaticVariable') } ================================================ FILE: RELEASE.md ================================================ ## 23rd August 2021 Fixed bug where custom tests left an empty DbcResult #846 Added feature to overwrite config file if it already exists for Export-DbcConfig #844 Enabled ping latency testing in PowerShell Core ##Latest ## 23rd August 2021 Removed the Verbose for the Pester load - Apologies, this was Rob! Thank you [@MikeyBronowski](https://www.github.com/MikeyBronowski) Get the file at the end so Export-DbcConfig can be used with Invoke-Item addresses #843 #845 Thank you [@MikeyBronowski](https://www.github.com/MikeyBronowski) spelling and full stops #842 Thank you [ashdar](https://github.com/ashdar) Check for existence in the Tag list before adding a Tag to the Tag list #853 Thank you [ashdar](https://github.com/ashdar) Updated PowerPlan Assertion #850 Thank you [tboggiano](https://github.com/tboggiano) CIS check for SQL Mail XPS for SQL Server 2008 and below (was) #779 Thank you [tboggiano](https://github.com/tboggiano) Added function to set CIS config (was) #776 Thank you [tboggiano](https://github.com/tboggiano) CIS check for TCP IP Protocols (was) #775 ## April 7th 2021 Thank you [@mikedavem](https://www.github.com/mikedavem) Fixed rogue verbose when importing [#834](https://github.com/sqlcollaborative/dbachecks/issues/834) Thank you [@mikedavem](https://www.github.com/mikedavem) Test NetBios Over TCP/IP should be disabled for cluster network interface [#833](https://github.com/sqlcollaborative/dbachecks/issues/833) Thank you [@conseilit](https://www.github.com/conseilit) Add LogfilePercentUsed check. Log might fill even if simple recovery model or full recovery model + Tlog backup in case of replication, CDC, HADR issues. [#831](https://github.com/sqlcollaborative/dbachecks/issues/831) [#832](https://github.com/sqlcollaborative/dbachecks/issues/832) Thank you [@conseilit](https://www.github.com/conseilit) Getting SQL Server instance DateTime prevent Log Backup checks to fail if the instance is not in the same timezone than the computer running dbaChecks scripts. [#830](https://github.com/sqlcollaborative/dbachecks/issues/830) Thank you [@MikeyBronowski](https://www.github.com/MikeyBronowski) Get-DbcConfig Adding support to multiple names [#829](https://github.com/sqlcollaborative/dbachecks/issues/829) Thank you [@MikeyBronowski](https://www.github.com/MikeyBronowski) Spellings [#827](https://github.com/sqlcollaborative/dbachecks/issues/827) Thank you [@TheAntGreen](https://www.github.com/TheAntGreen) updated variables to make errors obvious [#825](https://github.com/sqlcollaborative/dbachecks/issues/825) Thank you [@MrBlueSky](https://www.github.com/MrBlueSky) - add info to suggest using Duplicate index command [#807](https://github.com/sqlcollaborative/dbachecks/issues/807) Thank you [@PsPsam](https://www.github.com/PsPsam) - Ping check to work on core and 5.1 [#763](https://github.com/sqlcollaborative/dbachecks/issues/763) Thank you [@zikato](https://www.github.com/zikato) - certificate expiration gives two failures if in the past [#785](https://github.com/sqlcollaborative/dbachecks/issues/785) Thank you [@mikedavem](https://www.github.com/mikedavem) - allow more than 99 days for retention for Olas jobs [#835](https://github.com/sqlcollaborative/dbachecks/issues/835) Thank you [@Shashtsoh](https://www.github.com/Shashtsoh) - Remove aliases to work in core [#837](https://github.com/sqlcollaborative/dbachecks/issues/837) Thank you [@a4ic6n](https://www.github.com/a4ic6n) - Max Memory check false succeeds [#836](https://github.com/sqlcollaborative/dbachecks/issues/836) ## December 14th 2020 Thank you tboggiano Browser check altered for instance count #758 Thank you zikato - Fixing datafile auto growth #786 Thank you fatherjack Typos #767 Thank you tboggiano Query Store enabled and disabled test improvements #791 Thank you relsna fixed issue with error log window #814 Thank you @TheAntGreen Typos #815 Thank you @TheAntGreen Add additional filter to filter out negative run_durations #816 Thank you @TheAntGreen Add policy for additional excluded dbs from the SAFE CLR check #817 Thank you @MikeyBronowski Fix the check for enabled alerts #819 Thank you @MikeyBronowski Updating the link in documentation #820 Thank you @mikedavem Updated HADR checks with additional checks #822 Thank you @mikedavem Database backup diff check - fix issue #812 #824 ## Date November 23rd 2020 Finally Rob gets around to working on PRs - Really sorry it has taken so long Fixes for bug 780 & 783 #784 - Thank you @TheAntGreen Fix local windows groups, additional filter needed on the object filter #789 - Thank you @TheAntGreen $null check for anything running SQL2008R2 or below as containment doesnt exist in those versions. #790 - Thank you @TheAntGreen Fix for IsClustered checks for service startup types #792 - Thank you @TheAntGreen CertCheck took ages to run, was still checking excluded DB's then filtering, change to not query the excluded DBs #793 - Thank you @TheAntGreen Fixed few typos in docs #799 - Thank you @jpomfret Fixed few typos in docs #799 - Thank you @TheAntGreen DuplicateIndex Check - Added new configuration option to allow people to filter out databases, as SSRS DB's have duplicate indexes and names are configuration in older versions, defaults to ReportServer & ReportServerTempDB GuestUserConnect - Changes method to Get-Database instead of InstanceSMO so its easier to filter out none accessable databases as the check would report false positives for offline or restoring databases NotExpectedTraceFlag - added a filter to filter out any trace flags which WHERE expected to prevent false positive alerts #801 - Thank you @TheAntGreen Add policy to exclude databases on the trustworthy check #806 - Thank you @TheAntGreen Unused Index Check wasn't executing correctly #808 - Thank you @TheAntGreen #803 Addition of the date filter for File Autogrowth detection #809 - Thank you @TheAntGreen New Check - Agent Mail Profile #811 - Thank you @TheAntGreen Scan for startup procs, use config option to override the value in use #813 - Thank you @TheAntGreen ##Latest ## Date September 22nd 2020 Only Importing Pester v4 and lower to reduce Pester v5 errors ## Date July 13th 2020 Thank you jpomfret Added skip.backup.readonly config #777 Thank you jpomfret typos #771 Thank you jpomfret Added MSDB suspect pages table check #768 Thank you markaugust Added instance name to Agent Service ACcount checks #766 Thank you tboggiano fixed Agent Run time calculation #746 ## Date 9th May 2020 UPDATED TO VERSION 2 New Commands Convert-DbcResult - To parse results and add Label, ComputerName, Instance and Database Set-DbcFile - To save the parsed results to a file json, csv or xml Write-DbcTable - to add results to a database New Parameter -FromDatabase on Star-DbcPowerBi - to open new Power Bi template file New PowerBi template file for reporting on results from the database Improved Spelling Updated Unit Tests for Checks to enabled results to be parsed Improved Check Titles Configuration for Max history days for Job duration Stop trying to check inaccessible databases for checks Improved Query Store checks Ensure long running agent jobs ignores durations longer than 24 hours Ignore jobs that never stop from the duration check ##Latest ## Date 29th March 2020 UPDATED MINIMUM POWERSHELL VERSION Updated Required versions of Pester, dbatools and PSFramework modules Thank you @dstrait Fix variable for SaDisabled check #750 Fix errant braces in SQL Browser Service Check #751 Fix PingComputer Check #752 Thank you markaugust Fix to ensure AG Name is in HADR checks #755 Thank you Tracey Boggiano Added Contained Database auth check and Query Store Enabled Checks #756 Thank you Rob Added exclude database config for Query store checks Version check for Query Store Checks Some spellings! ##Latest ## Date 18th March 2020 Thank you Tracey tboggiano New CIS user-defined CLRs to be set to SAFE_ACCESS #734 CIS tests for if service accounts are local admins #736 Thank you Rob Getting service accounts tests to pass if no service Made long running jobs check work as expected Improved Database Mail check Made sure disk allocations dont run on Core Thank you mikedavem Fixed bug in disk allocation check exclusions Added multiple ags to the HADR check #742 ## Date 14th March 2020 Thank you Tracey tboggiano New CIS Check Hide Instance #728 New CIS Check Symmetric Key #732 New CIS Check Agent Proxy not have access to public Role #732 ## Date 8th January 2020 Thank you Tracey tboggiano New CIS Check Guest Account connect permissions #725 New CIS Check BuiltIn Admins login #726 New CIS Check public role permissions #729 New CIS Check local windows groups do not have logins #731 Update sa login check #730 Thank you Rob Added Tag parameter to Get-DbcCheck Updated tests to work with PowerShell 7 ## Date 22nd December Thank you Tracey tboggiano Two New CIS Checks Contained databases should be auto-closed #721 sa login disabled and should not exist #719 Thank you Rob Fix bug in Agent Tests #723 ## Date 28th November Thank you Tracey tboggiano Added new CIS Check for the latest SQL build #716 Thank you Rob Making the SQL Engine Service Check configurable #706 ## Date 26th November Thank you Tracey @tboggiano Added new CIS Check for OLE AUtomation Procedures to be disabled #707 Moving the Cross DB Ownership Chaining check into the AllInstance check to help speed up checks #708 Thank you Rob Fixing the Tags so that they are picked up by AllInstanceInfo Fixes #715 ## Date 16th November Thank you Matt @matt2005 Removed rogue else from Agents Tests #713 ## Date 17th October Thank you Shane @SOZDBA Improved Documentation Thank you Gareth NewMan Added New Check - Default File Path ## Date 1st October 2019 Thank you Rob Fixed some merge issues with a load of code :-( Created GitHub Action to run Pester Checks on PR Thank you @TracyBoggiano Added New Checks RemoteAccessDisabled ScanForStartUpProcedures Thank you Gareth Newman Improved wording in tests #700 , #697 Fix incorrect calculation in last agent run time #696 #698 Fixed bug in AllInstanceInfo Thank you Richard Imenes Fixed dead links in readme #702 Thank you Benjamin Schenk Fixed Send-MailMessage in readme #705 ## Date 30th July 2019 Thank you Rob ;-) Added two new checks #239 LastJobRunTime and LongRunningJob Added four new configs skip.agent.longrunningjobs skip.agent.lastjobruntime agent.longrunningjob.percentage agent.lastjobruntime.percentage ## Date 29th July 2019 Thank you @TracyBoggiano Added tags for checks that will be part of CIS checks #642 CIS project started Added check for default trace enabled #684 ## Date 23rd July 2019 Thank you @dstrait, @Sozdba Fix tests that use time to work if client and instance are in different time zones #610 Fixed Maintenance Solution clean up time test #633 Improved Run time #635 Improved Error Log warning window honouring #637 Ignore SQL 2005 for some tests #630,629,#628 Skip TF1118 test if SQL2016 or above ## Date 8th July 2019 Thanks to Chuck for notifying of error Fixed Update-DbcPowerBiDataSource ## Date 2nd July 2019 dbachecks works with PowerShell Core #620 dbachecks works with dbatools v1 #624 Minimum PowerShell Now 5.0 #568 Prettier output in test names for @cl because she is ace #495 Fixes for none-readable secondaries causing tests to fail #611 Added ability to exclude disks from disk allocation check #561 Added ability to exclude cancelled jobs from failed job check #552 Added max job history for failed jobs #552 Some extra tags added ## Date 22nd May 2019 at Techorama in Room 12 Thank You @SOZDBA, @djfcc, @wsmelton Improved validation for IP addresses in clusters Ignored Off-line databases for Pseudo Recovery Checks Some internal testing changes ## Date 05/02/2019 Thank you Chrissy! @cl added default environment #596 altered configuration validation for mail to stop errors Ensured database status check doesnt fail as readonly for snapshots ## Date 31/01/2019 Thank you Chrissy! add support for inline config file, fixes #501 #594 ## Date 29/01/2019 Added skip for authentication scheme #587 Added WhatIf to Update-DbcPowerBiDataSource Thank you @shaneis #590 $null to the left Thank you @jwmoss #588 ## Date 19/01/2019 Thank you Claudio Added extra check for Job History Settings #582 Added extra check for Error Log Count #583 Added integration test code and docker compose file ##Latest ## Date 22/11/2018 Spelling - Thanks RonaldHensbergen Fix for #576 When calling just Invoke-DbcCheck without a Check it fails to run the Server Tests correctly ## Date 12/11/2018 Added more information to the output - thanks @ClaudioESSilva Spelling - Thanks ChrisTuckerNM Fix for #564 - Error Importing DbcConfig in PowerShell 4 - Thanks @niphod ## Date 29/10/2018 Fixed #435 Page verify on SQL 2000 and SQL2005 Reduced number of calls to the instance for database checks improving performance ## Date 27/10/2018 Fixed #435 Page verify on SQL 2000 and SQL2005 Reduced number of calls to the instance for database checks improving performance ## Date 17/10/2018 Spelling and Because added - Thank you @LowlyDBA New Check for XPCmdShell enabled added ## Date 11/10/2018 Added Check for CLR Enabled Added Check for Cross Database Ownership Chaining Added Check for Database Mail XPs Added Check for Ad Hoc Distributed Queries Added Tag for security Demo CI/CD at Polar Conf ## Date 24/09/2018 Moved the Instance Connection Check to the Instance Tests Fixed bug with Set-DbcConfig not adding none-arrays! New Check for Expected Trace Flags New Check for Not Expected TraceFlags Stopped dbatools chatty messages polluting the test results ## Date 07/09/2018 Updated dbatools required module to 0.9.410 Renamed all dbatools commands to new naming convention Fixed Bug with JSON file naming Improved Server Checks to remove Red and improve speed for none contactable servers Altered all server checks to use assertions and added pester Tests Removed left over ogv entry ## Date 05/09/2018 New Check for 2 digit cut off thanks @CláudioESSilva https://claudioessilva.eu/2018/09/04/dont-cutoff-yourself-when-dealing-with-dates-in-t-sql-did-you-know/ Fixed bug with adding NoneContactable Instances to variable Improved error handling for HADR checks ## Date 28/08/2018 Added MaxBehind to SupportedBuild Tests - Thank you @LowlyDBA Ensured the Database parameter checks only the specified Databases - Thank you @jpomfret Updated Set-DbcConfig to allow Append to append arrays to arrays closes #535 Altered json filename creation to avoid max characters error Altered PowerBi to display information correctly with filename changes ## Date 24/08/2017 Fixed Error with using Credential and stopped changing path when running checks from custom repos - Thank you @sammyxx ## Date 23/08/2017 Update to the help message for clusters by @LowlyDBA Potential Breaking Change - Removed Tags from names of json files so that PowerBi will correctly show Environment names ## Date 15/08/2018 Fixed issue 521 ExcludeDatabase parameter doesn't work - THANK YOU @jpomfret THANK YOU @jpomfret - Issue 509 -Database should only check databases listed and exclude all others Further update to Update-DbcPowerBiDataSource to allow Environment as well as specify filename Improved performance of the Server checks Improved performance of the Instance checks Improved performance of the Database checks Improved performance of the ErrorLog checks Removed Send-DbcSendMailMessage until it can be re-coded ## Date 13/08/2018 Fixed #504 by enabling FileName parameter on Update-PowerBiDataSource Added in new function to begin to reduce the number of calls to each instance Reduced required Pester version to 4.3.1 Further PowerShell V4 improvements ## Date 06/08/2018 Added New Check for tempdb data file sizes to be the same - Thank you @garethnewman #512 Altered Services Check so that clustered instances start mode is checked correctly thank you @kylejdoyle #516 Skip PowerPlan test if no connection thanks @cl #490 Fixed bug with XESession and PSv4 thank you @kylejdoyle #517 Error silently on failing Service check (thanks Rob ;-) ) Fixed dbatools command names Fixed PSv4 support for importing the module also ## Date 31/07/2018 Added check for Database Exists - Thanks @sqldbawithbeard Added excluded databases config to each Database Check and wrote Pester Test for that #506 Added msdb to exclusion fro duplicate index #506 Fixed offline install bug #484 ## Date 30/07/2018 Updated Required Module versions - Thank you @cl Updated Agent Checks to fail a test on no connection rather than throw all the PowerShell errors - Thanks @sqldbawithbeard Updated HADR Checks for PS4 compatibility Issue #513 ## Date 28/06/2018 Don't check versions before 2008 for AdHocWorkloads Thank you John McCall @LowlyDBA More Spelling! Thank you John McCall @LowlyDBA Updated required version and dbatools error log command name Thank you Our Glorious Chrissy @cl ## Date 30/05/2018 New Release Notes command added Spelling ## Date 29/05/2012 ================================================ FILE: RequiredModules.psd1 ================================================ @{ PSDependOptions = @{ AddToPath = $true Target = 'output\RequiredModules' Parameters = @{ Repository = 'PSGallery' } } 'dbatools.library' = 'latest' InvokeBuild = 'latest' PSScriptAnalyzer = 'latest' Pester = 'latest' Plaster = 'latest' ModuleBuilder = 'latest' ChangelogManagement = 'latest' Sampler = 'latest' 'Sampler.GitHubTasks' = 'latest' MarkdownLinkCheck = 'latest' dbatools = 'latest' PSFramework = 'latest' } ================================================ FILE: Resolve-Dependency.ps1 ================================================ <# .DESCRIPTION Bootstrap script for PSDepend. .PARAMETER DependencyFile Specifies the configuration file for the this script. The default value is 'RequiredModules.psd1' relative to this script's path. .PARAMETER PSDependTarget Path for PSDepend to be bootstrapped and save other dependencies. Can also be CurrentUser or AllUsers if you wish to install the modules in such scope. The default value is 'output/RequiredModules' relative to this script's path. .PARAMETER Proxy Specifies the URI to use for Proxy when attempting to bootstrap PackageProvider and PowerShellGet. .PARAMETER ProxyCredential Specifies the credential to contact the Proxy when provided. .PARAMETER Scope Specifies the scope to bootstrap the PackageProvider and PSGet if not available. THe default value is 'CurrentUser'. .PARAMETER Gallery Specifies the gallery to use when bootstrapping PackageProvider, PSGet and when calling PSDepend (can be overridden in Dependency files). The default value is 'PSGallery'. .PARAMETER GalleryCredential Specifies the credentials to use with the Gallery specified above. .PARAMETER AllowOldPowerShellGetModule Allow you to use a locally installed version of PowerShellGet older than 1.6.0 (not recommended). Default it will install the latest PowerShellGet if an older version than 2.0 is detected. .PARAMETER MinimumPSDependVersion Allow you to specify a minimum version fo PSDepend, if you're after specific features. .PARAMETER AllowPrerelease Not yet written. .PARAMETER WithYAML Not yet written. .NOTES Load defaults for parameters values from Resolve-Dependency.psd1 if not provided as parameter. #> [CmdletBinding()] param ( [Parameter()] [System.String] $DependencyFile = 'RequiredModules.psd1', [Parameter()] [System.String] $PSDependTarget = (Join-Path -Path $PSScriptRoot -ChildPath 'output/RequiredModules'), [Parameter()] [System.Uri] $Proxy, [Parameter()] [System.Management.Automation.PSCredential] $ProxyCredential, [Parameter()] [ValidateSet('CurrentUser', 'AllUsers')] [System.String] $Scope = 'CurrentUser', [Parameter()] [System.String] $Gallery = 'PSGallery', [Parameter()] [System.Management.Automation.PSCredential] $GalleryCredential, [Parameter()] [System.Management.Automation.SwitchParameter] $AllowOldPowerShellGetModule, [Parameter()] [System.String] $MinimumPSDependVersion, [Parameter()] [System.Management.Automation.SwitchParameter] $AllowPrerelease, [Parameter()] [System.Management.Automation.SwitchParameter] $WithYAML, [Parameter()] [System.Collections.Hashtable] $RegisterGallery ) try { if ($PSVersionTable.PSVersion.Major -le 5) { if (-not (Get-Command -Name 'Import-PowerShellDataFile' -ErrorAction 'SilentlyContinue')) { Import-Module -Name Microsoft.PowerShell.Utility -RequiredVersion '3.1.0.0' } <# Making sure the imported PackageManagement module is not from PS7 module path. The VSCode PS extension is changing the $env:PSModulePath and prioritize the PS7 path. This is an issue with PowerShellGet because it loads an old version if available (or fail to load latest). #> Get-Module -ListAvailable PackageManagement | Where-Object -Property 'ModuleBase' -NotMatch 'powershell.7' | Select-Object -First 1 | Import-Module -Force } Write-Verbose -Message 'Importing Bootstrap default parameters from ''$PSScriptRoot/Resolve-Dependency.psd1''.' $resolveDependencyConfigPath = Join-Path -Path $PSScriptRoot -ChildPath '.\Resolve-Dependency.psd1' -Resolve -ErrorAction 'Stop' $resolveDependencyDefaults = Import-PowerShellDataFile -Path $resolveDependencyConfigPath $parameterToDefault = $MyInvocation.MyCommand.ParameterSets.Where{ $_.Name -eq $PSCmdlet.ParameterSetName }.Parameters.Keys if ($parameterToDefault.Count -eq 0) { $parameterToDefault = $MyInvocation.MyCommand.Parameters.Keys } # Set the parameters available in the Parameter Set, or it's not possible to choose yet, so all parameters are an option. foreach ($parameterName in $parameterToDefault) { if (-not $PSBoundParameters.Keys.Contains($parameterName) -and $resolveDependencyDefaults.ContainsKey($parameterName)) { Write-Verbose -Message "Setting parameter '$parameterName' to value '$($resolveDependencyDefaults[$parameterName])'." try { $variableValue = $resolveDependencyDefaults[$parameterName] if ($variableValue -is [System.String]) { $variableValue = $ExecutionContext.InvokeCommand.ExpandString($variableValue) } $PSBoundParameters.Add($parameterName, $variableValue) Set-Variable -Name $parameterName -value $variableValue -Force -ErrorAction 'SilentlyContinue' } catch { Write-Verbose -Message "Error adding default for $parameterName : $($_.Exception.Message)." } } } } catch { Write-Warning -Message "Error attempting to import Bootstrap's default parameters from '$resolveDependencyConfigPath': $($_.Exception.Message)." } Write-Progress -Activity 'Bootstrap:' -PercentComplete 0 -CurrentOperation 'NuGet Bootstrap' # TODO: This should handle the parameter $AllowOldPowerShellGetModule. $powerShellGetModule = Import-Module -Name 'PowerShellGet' -MinimumVersion '2.0' -ErrorAction 'SilentlyContinue' -PassThru # Install the package provider if it is not available. $nuGetProvider = Get-PackageProvider -Name 'NuGet' -ListAvailable | Select-Object -First 1 if (-not $powerShellGetModule -and -not $nuGetProvider) { $providerBootstrapParameters = @{ Name = 'nuget' Force = $true ForceBootstrap = $true ErrorAction = 'Stop' } switch ($PSBoundParameters.Keys) { 'Proxy' { $providerBootstrapParameters.Add('Proxy', $Proxy) } 'ProxyCredential' { $providerBootstrapParameters.Add('ProxyCredential', $ProxyCredential) } 'Scope' { $providerBootstrapParameters.Add('Scope', $Scope) } 'AllowPrerelease' { $providerBootstrapParameters.Add('AllowPrerelease', $AllowPrerelease) } } if ($AllowPrerelease) { $providerBootstrapParameters.Add('AllowPrerelease', $true) } Write-Information -MessageData 'Bootstrap: Installing NuGet Package Provider from the web (Make sure Microsoft addresses/ranges are allowed).' # TODO: This does not handle a private Gallery yet. $null = Install-PackageProvider @providerBootstrapParams $nuGetProvider = Get-PackageProvider -Name 'NuGet' -ListAvailable | Select-Object -First 1 $nuGetProviderVersion = $nuGetProvider.Version.ToString() Write-Information -MessageData "Bootstrap: Importing NuGet Package Provider version $nuGetProviderVersion to current session." $Null = Import-PackageProvider -Name 'NuGet' -RequiredVersion $nuGetProviderVersion -Force } if ($RegisterGallery) { if ($RegisterGallery.ContainsKey('Name') -and -not [System.String]::IsNullOrEmpty($RegisterGallery.Name)) { $Gallery = $RegisterGallery.Name } else { $RegisterGallery.Name = $Gallery } Write-Progress -Activity 'Bootstrap:' -PercentComplete 7 -CurrentOperation "Verifying private package repository '$Gallery'" -Completed $previousRegisteredRepository = Get-PSRepository -Name $Gallery -ErrorAction 'SilentlyContinue' if ($previousRegisteredRepository.SourceLocation -ne $RegisterGallery.SourceLocation) { if ($previousRegisteredRepository) { Write-Progress -Activity 'Bootstrap:' -PercentComplete 9 -CurrentOperation "Re-registrering private package repository '$Gallery'" -Completed Unregister-PSRepository -Name $Gallery $unregisteredPreviousRepository = $true } else { Write-Progress -Activity 'Bootstrap:' -PercentComplete 9 -CurrentOperation "Registering private package repository '$Gallery'" -Completed } Register-PSRepository @RegisterGallery } } Write-Progress -Activity 'Bootstrap:' -PercentComplete 10 -CurrentOperation "Ensuring Gallery $Gallery is trusted" # Fail if the given PSGallery is not registered. $previousGalleryInstallationPolicy = (Get-PSRepository -Name $Gallery -ErrorAction 'Stop').InstallationPolicy if ($previousGalleryInstallationPolicy -ne 'Trusted') { # Only change policy if the repository is not trusted Set-PSRepository -Name $Gallery -InstallationPolicy 'Trusted' -ErrorAction 'Ignore' } try { Write-Progress -Activity 'Bootstrap:' -PercentComplete 25 -CurrentOperation 'Checking PowerShellGet' # Ensure the module is loaded and retrieve the version you have. $powerShellGetVersion = (Import-Module -Name 'PowerShellGet' -PassThru -ErrorAction 'SilentlyContinue').Version Write-Verbose -Message "Bootstrap: The PowerShellGet version is $powerShellGetVersion" # Versions below 2.0 are considered old, unreliable & not recommended if (-not $powerShellGetVersion -or ($powerShellGetVersion -lt [System.Version] '2.0' -and -not $AllowOldPowerShellGetModule)) { Write-Progress -Activity 'Bootstrap:' -PercentComplete 40 -CurrentOperation 'Installing newer version of PowerShellGet' $installPowerShellGetParameters = @{ Name = 'PowerShellGet' Force = $True SkipPublisherCheck = $true AllowClobber = $true Scope = $Scope Repository = $Gallery } switch ($PSBoundParameters.Keys) { 'Proxy' { $installPowerShellGetParameters.Add('Proxy', $Proxy) } 'ProxyCredential' { $installPowerShellGetParameters.Add('ProxyCredential', $ProxyCredential) } 'GalleryCredential' { $installPowerShellGetParameters.Add('Credential', $GalleryCredential) } 'AllowPrerelease' { $installPowerShellGetParameters.Add('AllowPrerelease', $AllowPrerelease) } } Write-Progress -Activity 'Bootstrap:' -PercentComplete 60 -CurrentOperation 'Installing newer version of PowerShellGet' Install-Module @installPowerShellGetParameters Remove-Module -Name 'PowerShellGet' -Force -ErrorAction 'SilentlyContinue' Remove-Module -Name 'PackageManagement' -Force $powerShellGetModule = Import-Module PowerShellGet -Force -PassThru $powerShellGetVersion = $powerShellGetModule.Version.ToString() Write-Information -MessageData "Bootstrap: PowerShellGet version loaded is $powerShellGetVersion" } # Try to import the PSDepend module from the available modules. $getModuleParameters = @{ Name = 'PSDepend' ListAvailable = $true } $psDependModule = Get-Module @getModuleParameters if ($PSBoundParameters.ContainsKey('MinimumPSDependVersion')) { try { $psDependModule = $psDependModule | Where-Object -FilterScript { $_.Version -ge $MinimumPSDependVersion } } catch { throw ('There was a problem finding the minimum version of PSDepend. Error: {0}' -f $_) } } if (-not $psDependModule) { # PSDepend module not found, installing or saving it. if ($PSDependTarget -in 'CurrentUser', 'AllUsers') { Write-Debug -Message "PSDepend module not found. Attempting to install from Gallery '$Gallery'." Write-Warning -Message "Installing PSDepend in $PSDependTarget Scope." $installPSDependParameters = @{ Name = 'PSDepend' Repository = $Gallery Force = $true Scope = $PSDependTarget SkipPublisherCheck = $true AllowClobber = $true } if ($MinimumPSDependVersion) { $installPSDependParameters.Add('MinimumVersion', $MinimumPSDependVersion) } Write-Progress -Activity 'Bootstrap:' -PercentComplete 75 -CurrentOperation "Installing PSDepend from $Gallery" Install-Module @installPSDependParameters } else { Write-Debug -Message "PSDepend module not found. Attempting to Save from Gallery $Gallery to $PSDependTarget" $saveModuleParameters = @{ Name = 'PSDepend' Repository = $Gallery Path = $PSDependTarget Force = $true } if ($MinimumPSDependVersion) { $saveModuleParameters.add('MinimumVersion', $MinimumPSDependVersion) } Write-Progress -Activity 'Bootstrap:' -PercentComplete 75 -CurrentOperation "Saving & Importing PSDepend from $Gallery to $Scope" Save-Module @saveModuleParameters } } Write-Progress -Activity 'Bootstrap:' -PercentComplete 80 -CurrentOperation 'Loading PSDepend' $importModulePSDependParameters = @{ Name = 'PSDepend' ErrorAction = 'Stop' Force = $true } if ($PSBoundParameters.ContainsKey('MinimumPSDependVersion')) { $importModulePSDependParameters.Add('MinimumVersion', $MinimumPSDependVersion) } # We should have successfully bootstrapped PSDepend. Fail if not available. $null = Import-Module @importModulePSDependParameters if ($WithYAML) { Write-Progress -Activity 'Bootstrap:' -PercentComplete 82 -CurrentOperation 'Verifying PowerShell module PowerShell-Yaml' if (-not (Get-Module -ListAvailable -Name 'PowerShell-Yaml')) { Write-Progress -Activity 'Bootstrap:' -PercentComplete 85 -CurrentOperation 'Installing PowerShell module PowerShell-Yaml' Write-Verbose -Message "PowerShell-Yaml module not found. Attempting to Save from Gallery '$Gallery' to '$PSDependTarget'." $SaveModuleParam = @{ Name = 'PowerShell-Yaml' Repository = $Gallery Path = $PSDependTarget Force = $true } Save-Module @SaveModuleParam } else { Write-Verbose "PowerShell-Yaml is already available" } } Write-Progress -Activity 'Bootstrap:' -PercentComplete 90 -CurrentOperation 'Invoke PSDepend' Write-Progress -Activity "PSDepend:" -PercentComplete 0 -CurrentOperation "Restoring Build Dependencies" if (Test-Path -Path $DependencyFile) { $psDependParameters = @{ Force = $true Path = $DependencyFile } # TODO: Handle when the Dependency file is in YAML, and -WithYAML is specified. Invoke-PSDepend @psDependParameters } Write-Progress -Activity "PSDepend:" -PercentComplete 100 -CurrentOperation "Dependencies restored" -Completed Write-Progress -Activity 'Bootstrap:' -PercentComplete 100 -CurrentOperation "Bootstrap complete" -Completed } finally { if ($RegisterGallery) { Write-Verbose -Message "Removing private package repository '$Gallery'." Unregister-PSRepository -Name $Gallery } if ($unregisteredPreviousRepository) { Write-Verbose -Message "Reverting private package repository '$Gallery' to previous location URI:s." $registerPSRepositoryParameters = @{ Name = $previousRegisteredRepository.Name InstallationPolicy = $previousRegisteredRepository.InstallationPolicy } if ($previousRegisteredRepository.SourceLocation) { $registerPSRepositoryParameters.SourceLocation = $previousRegisteredRepository.SourceLocation } if ($previousRegisteredRepository.PublishLocation) { $registerPSRepositoryParameters.PublishLocation = $previousRegisteredRepository.PublishLocation } if ($previousRegisteredRepository.ScriptSourceLocation) { $registerPSRepositoryParameters.ScriptSourceLocation = $previousRegisteredRepository.ScriptSourceLocation } if ($previousRegisteredRepository.ScriptPublishLocation) { $registerPSRepositoryParameters.ScriptPublishLocation = $previousRegisteredRepository.ScriptPublishLocation } Register-PSRepository @registerPSRepositoryParameters } # Only try to revert installation policy if the repository exist if ((Get-PSRepository -Name $Gallery -ErrorAction 'SilentlyContinue')) { if ($previousGalleryInstallationPolicy -and $previousGalleryInstallationPolicy -ne 'Trusted') { # Reverting the Installation Policy for the given gallery if it was not already trusted Set-PSRepository -Name $Gallery -InstallationPolicy $previousGalleryInstallationPolicy } } Write-Verbose -Message "Project Bootstrapped, returning to Invoke-Build" } ================================================ FILE: Resolve-Dependency.psd1 ================================================ @{ #PSDependTarget = './output/modules' #Proxy = '' #ProxyCredential = '$MyCredentialVariable' #TODO: find a way to support credentials in build (resolve variable) Gallery = 'PSGallery' # To use a private nuget repository change the following to your own feed. The locations must be a Nuget v2 feed due # to limitation in PowerShellGet v2.x. Example below is for a Azure DevOps Server project-scoped feed. While resolving # dependencies it will be registered as a trusted repository with the name specified in the property 'Gallery' above, # unless property 'Name' is provided in the hashtable below, if so it will override the property 'Gallery' above. The # registered repository will be removed when dependencies has been resolved, unless it was already registered to begin # with. If repository is registered already but with different URL:s the repository will be re-registered and reverted # after dependencies has been resolved. Currently only Windows integrated security works with private Nuget v2 feeds # (or if it is a public feed with no security), it is not possible yet to securely provide other credentials for the feed. #RegisterGallery = @{ # #Name = 'MyPrivateFeedName' # GallerySourceLocation = 'https://azdoserver.company.local///_packaging//nuget/v2' # GalleryPublishLocation = 'https://azdoserver.company.local///_packaging//nuget/v2' # GalleryScriptSourceLocation = 'https://azdoserver.company.local///_packaging//nuget/v2' # GalleryScriptPublishLocation = 'https://azdoserver.company.local///_packaging//nuget/v2' # #InstallationPolicy = 'Trusted' #} #AllowOldPowerShellGetModule = $true #MinimumPSDependVersion = '0.3.0' AllowPrerelease = $false WithYAML = $true # Will also bootstrap PowerShell-Yaml to read other config files } ================================================ FILE: SECURITY.md ================================================ ## Security The DSC Community takes the security of our modules seriously, which includes all source code repositories managed through our GitHub organization. If you believe you have found a security vulnerability in any DSC Community owned repository, please report it to us as described below. ## Reporting Security Issues **Please do not report security vulnerabilities through public GitHub issues.** Instead, please report them to one or several members of the DSC Community organization. The easiest way to do so is to send us a direct message via twitter or slack. You should receive a response within 48 hours. If for some reason you do not, please follow up to other member of the community. Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: * Type of issue * Full paths of source file(s) related to the manifestation of the issue * The location of the affected source code (tag/branch/commit or direct URL) * Any special configuration required to reproduce the issue * Step-by-step instructions to reproduce the issue * Proof-of-concept or exploit code (if possible) * Impact of the issue, including how an attacker might exploit the issue This information will help us triage your report more quickly. ## Preferred Languages We prefer all communications to be in English. ================================================ FILE: azure-pipelines.yml ================================================ trigger: branches: include: - main paths: exclude: - CHANGELOG.md tags: include: - "v*" exclude: - "*-*" variables: buildFolderName: output buildArtifactName: output testResultFolderName: testResults defaultBranch: main stages: - stage: Build jobs: - job: Package_Module displayName: 'Package Module' pool: vmImage: 'ubuntu-latest' steps: - pwsh: | dotnet tool install --global GitVersion.Tool $gitVersionObject = dotnet-gitversion | ConvertFrom-Json $gitVersionObject.PSObject.Properties.ForEach{ Write-Host -Object "Setting Task Variable '$($_.Name)' with value '$($_.Value)'." Write-Host -Object "##vso[task.setvariable variable=$($_.Name);]$($_.Value)" } Write-Host -Object "##vso[build.updatebuildnumber]$($gitVersionObject.FullSemVer)" displayName: Calculate ModuleVersion (GitVersion) - task: PowerShell@2 name: package displayName: 'Build & Package Module' inputs: filePath: './build.ps1' arguments: '-ResolveDependency -tasks pack' pwsh: true env: ModuleVersion: $(NuGetVersionV2) - task: PublishPipelineArtifact@1 displayName: 'Publish Build Artifact' inputs: targetPath: '$(buildFolderName)/' artifact: $(buildArtifactName) publishLocation: 'pipeline' parallel: true - stage: Test dependsOn: Build jobs: - job: test_linux displayName: 'Linux' timeoutInMinutes: 0 pool: vmImage: 'ubuntu-latest' steps: - task: DownloadPipelineArtifact@2 displayName: 'Download Build Artifact' inputs: buildType: 'current' artifactName: $(buildArtifactName) targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' - task: PowerShell@2 name: test displayName: 'Run Tests' inputs: filePath: './build.ps1' arguments: '-tasks test' - task: PublishTestResults@2 displayName: 'Publish Test Results' condition: succeededOrFailed() inputs: testResultsFormat: 'NUnit' testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit*.xml' testRunTitle: 'Linux' - task: PublishPipelineArtifact@1 displayName: 'Publish Test Artifact' inputs: targetPath: '$(buildFolderName)/$(testResultFolderName)/' artifactName: 'CodeCoverageLinux' parallel: true - job: test_windows_core displayName: 'Windows (PowerShell)' timeoutInMinutes: 0 pool: vmImage: 'windows-latest' steps: - task: DownloadPipelineArtifact@2 displayName: 'Download Build Artifact' inputs: buildType: 'current' artifactName: $(buildArtifactName) targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' - task: PowerShell@2 name: test displayName: 'Run Tests' inputs: filePath: './build.ps1' arguments: '-tasks test' pwsh: true - task: PublishTestResults@2 displayName: 'Publish Test Results' condition: succeededOrFailed() inputs: testResultsFormat: 'NUnit' testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit*.xml' testRunTitle: 'Windows (PowerShell)' - task: PublishPipelineArtifact@1 displayName: 'Publish Test Artifact' inputs: targetPath: '$(buildFolderName)/$(testResultFolderName)/' artifactName: 'CodeCoverageWinPS7' parallel: true - job: test_windows_ps displayName: 'Windows (Windows PowerShell)' timeoutInMinutes: 0 pool: vmImage: 'windows-latest' steps: - task: DownloadPipelineArtifact@2 displayName: 'Download Build Artifact' inputs: buildType: 'current' artifactName: $(buildArtifactName) targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' - task: PowerShell@2 name: test displayName: 'Run Tests' inputs: filePath: './build.ps1' arguments: '-tasks test' pwsh: false - task: PublishTestResults@2 displayName: 'Publish Test Results' condition: succeededOrFailed() inputs: testResultsFormat: 'NUnit' testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit*.xml' testRunTitle: 'Windows (Windows PowerShell)' - task: PublishPipelineArtifact@1 displayName: 'Publish Test Artifact' inputs: targetPath: '$(buildFolderName)/$(testResultFolderName)/' artifactName: 'CodeCoverageWinPS51' parallel: true - job: test_macos displayName: 'macOS' timeoutInMinutes: 0 pool: vmImage: 'macos-latest' steps: - task: DownloadPipelineArtifact@2 displayName: 'Download Build Artifact' inputs: buildType: 'current' artifactName: $(buildArtifactName) targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' - task: PowerShell@2 name: test displayName: 'Run Tests' inputs: filePath: './build.ps1' arguments: '-tasks test' pwsh: true - task: PublishTestResults@2 displayName: 'Publish Test Results' condition: succeededOrFailed() inputs: testResultsFormat: 'NUnit' testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit*.xml' testRunTitle: 'MacOS' - task: PublishPipelineArtifact@1 displayName: 'Publish Test Artifact' inputs: targetPath: '$(buildFolderName)/$(testResultFolderName)/' artifactName: 'CodeCoverageMacOS' parallel: true # If no code coverage should be reported, then this entire removed: - job: Code_Coverage displayName: 'Publish Code Coverage' dependsOn: - test_macos - test_linux - test_windows_core - test_windows_ps pool: vmImage: 'ubuntu-latest' timeoutInMinutes: 0 steps: - pwsh: | $repositoryOwner,$repositoryName = $env:BUILD_REPOSITORY_NAME -split '/' echo "##vso[task.setvariable variable=RepositoryOwner;isOutput=true]$repositoryOwner" echo "##vso[task.setvariable variable=RepositoryName;isOutput=true]$repositoryName" name: dscBuildVariable displayName: 'Set Environment Variables' - task: DownloadPipelineArtifact@2 displayName: 'Download Pipeline Artifact' inputs: buildType: 'current' artifactName: $(buildArtifactName) targetPath: '$(Build.SourcesDirectory)/$(buildArtifactName)' - task: DownloadPipelineArtifact@2 displayName: 'Download Test Artifact macOS' inputs: buildType: 'current' artifactName: 'CodeCoverageMacOS' targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)/$(testResultFolderName)' - task: DownloadPipelineArtifact@2 displayName: 'Download Test Artifact Linux' inputs: buildType: 'current' artifactName: 'CodeCoverageLinux' targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)/$(testResultFolderName)' - task: DownloadPipelineArtifact@2 displayName: 'Download Test Artifact Windows (PS 5.1)' inputs: buildType: 'current' artifactName: 'CodeCoverageWinPS51' targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)/$(testResultFolderName)' - task: DownloadPipelineArtifact@2 displayName: 'Download Test Artifact Windows (PS7)' inputs: buildType: 'current' artifactName: 'CodeCoverageWinPS7' targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)/$(testResultFolderName)' # Make sure to update build.yaml to support these tasks, then uncomment these tasks: #- task: PowerShell@2 # name: merge # displayName: 'Merge Code Coverage files' # inputs: # filePath: './build.ps1' # arguments: '-tasks merge' # pwsh: true #- task: PublishCodeCoverageResults@1 # displayName: 'Publish Azure Code Coverage' # inputs: # codeCoverageTool: 'JaCoCo' # summaryFileLocation: '$(buildFolderName)/$(testResultFolderName)/JaCoCo_coverage.xml' # pathToSources: '$(Build.SourcesDirectory)/$(dscBuildVariable.RepositoryName)/' # Uncomment if Codecov.io should be used (see docs at Codecov.io how to use and the required repository configuration). #- script: | # bash <(curl -s https://codecov.io/bash) -f "./$(buildFolderName)/$(testResultFolderName)/JaCoCo_coverage.xml" # displayName: 'Publish Code Coverage to Codecov.io' - stage: Deploy dependsOn: Test # Only execute deploy stage if we're on main and previous stage succeeded condition: | and( succeeded(), or( eq(variables['Build.SourceBranch'], 'refs/heads/main'), startsWith(variables['Build.SourceBranch'], 'refs/tags/') ), contains(variables['System.TeamFoundationCollectionUri'], 'MyOrgName') ) jobs: - job: Deploy_Module displayName: 'Deploy Module' pool: vmImage: 'ubuntu-latest' steps: - task: DownloadPipelineArtifact@2 displayName: 'Download Build Artifact' inputs: buildType: 'current' artifactName: $(buildArtifactName) targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' - task: PowerShell@2 name: publishRelease displayName: 'Publish Release' inputs: filePath: './build.ps1' arguments: '-tasks publish' pwsh: true env: GitHubToken: $(GitHubToken) GalleryApiToken: $(GalleryApiToken) ReleaseBranch: $(defaultBranch) MainGitBranch: $(defaultBranch) - task: PowerShell@2 name: sendChangelogPR displayName: 'Send Changelog PR' inputs: filePath: './build.ps1' arguments: '-tasks Create_ChangeLog_GitHub_PR' pwsh: true env: GitHubToken: $(GitHubToken) ReleaseBranch: $(defaultBranch) MainGitBranch: $(defaultBranch) ================================================ FILE: build.ps1 ================================================ <# .DESCRIPTION Bootstrap and build script for PowerShell module CI/CD pipeline .PARAMETER Tasks The task or tasks to run. The default value is '.' (runs the default task). .PARAMETER CodeCoverageThreshold The code coverage target threshold to uphold. Set to 0 to disable. The default value is '' (empty string). .PARAMETER BuildConfig Not yet written. .PARAMETER OutputDirectory Specifies the folder to build the artefact into. The default value is 'output'. .PARAMETER BuiltModuleSubdirectory Subdirectory name to build the module (under $OutputDirectory). The default value is '' (empty string). .PARAMETER RequiredModulesDirectory Can be a path (relative to $PSScriptRoot or absolute) to tell Resolve-Dependency and PSDepend where to save the required modules. It is also possible to use 'CurrentUser' och 'AllUsers' to install missing dependencies. You can override the value for PSDepend in the Build.psd1 build manifest. The default value is 'output/RequiredModules'. .PARAMETER PesterScript One or more paths that will override the Pester configuration in build configuration file when running the build task Invoke_Pester_Tests. If running Pester 5 test, use the alias PesterPath to be future-proof. .PARAMETER PesterTag Filter which tags to run when invoking Pester tests. This is used in the Invoke-Pester.pester.build.ps1 tasks. .PARAMETER PesterExcludeTag Filter which tags to exclude when invoking Pester tests. This is used in the Invoke-Pester.pester.build.ps1 tasks. .PARAMETER DscTestTag Filter which tags to run when invoking DSC Resource tests. This is used in the DscResource.Test.build.ps1 tasks. .PARAMETER DscTestExcludeTag Filter which tags to exclude when invoking DSC Resource tests. This is used in the DscResource.Test.build.ps1 tasks. .PARAMETER ResolveDependency Not yet written. .PARAMETER BuildInfo The build info object from ModuleBuilder. Defaults to an empty hashtable. .PARAMETER AutoRestore Not yet written. #> [CmdletBinding()] param ( [Parameter(Position = 0)] [System.String[]] $Tasks = '.', [Parameter()] [System.String] $CodeCoverageThreshold = '', [Parameter()] [System.String] [ValidateScript( { Test-Path -Path $_ } )] $BuildConfig, [Parameter()] [System.String] $OutputDirectory = 'output', [Parameter()] [System.String] $BuiltModuleSubdirectory = '', [Parameter()] [System.String] $RequiredModulesDirectory = $(Join-Path 'output' 'RequiredModules'), [Parameter()] # This alias is to prepare for the rename of this parameter to PesterPath when Pester 4 support is removed [Alias('PesterPath')] [System.Object[]] $PesterScript, [Parameter()] [System.String[]] $PesterTag, [Parameter()] [System.String[]] $PesterExcludeTag, [Parameter()] [System.String[]] $DscTestTag, [Parameter()] [System.String[]] $DscTestExcludeTag, [Parameter()] [Alias('bootstrap')] [System.Management.Automation.SwitchParameter] $ResolveDependency, [Parameter(DontShow)] [AllowNull()] [System.Collections.Hashtable] $BuildInfo, [Parameter()] [System.Management.Automation.SwitchParameter] $AutoRestore ) <# The BEGIN block (at the end of this file) handles the Bootstrap of the Environment before Invoke-Build can run the tasks if the parameter ResolveDependency (or parameter alias Bootstrap) is specified. #> process { if ($MyInvocation.ScriptName -notLike '*Invoke-Build.ps1') { # Only run the process block through InvokeBuild (look at the Begin block at the bottom of this script). return } # Execute the Build process from the .build.ps1 path. Push-Location -Path $PSScriptRoot -StackName 'BeforeBuild' try { Write-Host -Object "[build] Parsing defined tasks" -ForeGroundColor Magenta # Load the default BuildInfo if the parameter BuildInfo is not set. if (-not $PSBoundParameters.ContainsKey('BuildInfo')) { try { if (Test-Path -Path $BuildConfig) { $configFile = Get-Item -Path $BuildConfig Write-Host -Object "[build] Loading Configuration from $configFile" $BuildInfo = switch -Regex ($configFile.Extension) { # Native Support for PSD1 '\.psd1' { if (-not (Get-Command -Name Import-PowerShellDataFile -ErrorAction SilentlyContinue)) { Import-Module -Name Microsoft.PowerShell.Utility -RequiredVersion 3.1.0.0 } Import-PowerShellDataFile -Path $BuildConfig } # Support for yaml when module PowerShell-Yaml is available '\.[yaml|yml]' { Import-Module -Name 'powershell-yaml' -ErrorAction Stop ConvertFrom-Yaml -Yaml (Get-Content -Raw $configFile) } # Native Support for JSON and JSONC (by Removing comments) '\.[json|jsonc]' { $jsonFile = Get-Content -Raw -Path $configFile $jsonContent = $jsonFile -replace '(?m)\s*//.*?$' -replace '(?ms)/\*.*?\*/' # Yaml is superset of JSON. ConvertFrom-Yaml -Yaml $jsonContent } # Unknown extension, return empty hashtable. default { Write-Error -Message "Extension '$_' not supported. using @{}" @{ } } } } else { Write-Host -Object "Configuration file '$($BuildConfig.FullName)' not found" -ForegroundColor Red # No config file was found, return empty hashtable. $BuildInfo = @{ } } } catch { $logMessage = "Error loading Config '$($BuildConfig.FullName)'.`r`nAre you missing dependencies?`r`nMake sure you run './build.ps1 -ResolveDependency -tasks noop' before running build to restore the required modules." Write-Host -Object $logMessage -ForegroundColor Yellow $BuildInfo = @{ } Write-Error -Message $_.Exception.Message } } # If the Invoke-Build Task Header is specified in the Build Info, set it. if ($BuildInfo.TaskHeader) { Set-BuildHeader -Script ([scriptblock]::Create($BuildInfo.TaskHeader)) } <# Add BuildModuleOutput to PSModule Path environment variable. Moved here (not in begin block) because build file can contains BuiltSubModuleDirectory value. #> if ($BuiltModuleSubdirectory) { if (-not (Split-Path -IsAbsolute -Path $BuiltModuleSubdirectory)) { $BuildModuleOutput = Join-Path -Path $OutputDirectory -ChildPath $BuiltModuleSubdirectory } else { $BuildModuleOutput = $BuiltModuleSubdirectory } } # test if BuiltModuleSubDirectory set in build config file elseif ($BuildInfo.ContainsKey('BuiltModuleSubDirectory')) { $BuildModuleOutput = Join-Path -Path $OutputDirectory -ChildPath $BuildInfo['BuiltModuleSubdirectory'] } else { $BuildModuleOutput = $OutputDirectory } # Pre-pending $BuildModuleOutput folder to PSModulePath to resolve built module from this folder. if ($powerShellModulePaths -notcontains $BuildModuleOutput) { Write-Host -Object "[build] Pre-pending '$BuildModuleOutput' folder to PSModulePath" -ForegroundColor Green $env:PSModulePath = $BuildModuleOutput + [System.IO.Path]::PathSeparator + $env:PSModulePath } <# Import Tasks from modules via their exported aliases when defined in Build Manifest. https://github.com/nightroman/Invoke-Build/tree/master/Tasks/Import#example-2-import-from-a-module-with-tasks #> if ($BuildInfo.ContainsKey('ModuleBuildTasks')) { foreach ($module in $BuildInfo['ModuleBuildTasks'].Keys) { try { Write-Host -Object "Importing tasks from module $module" -ForegroundColor DarkGray $loadedModule = Import-Module -Name $module -PassThru -ErrorAction Stop foreach ($TaskToExport in $BuildInfo['ModuleBuildTasks'].($module)) { $loadedModule.ExportedAliases.GetEnumerator().Where{ Write-Host -Object "`t Loading $($_.Key)..." -ForegroundColor DarkGray # Using -like to support wildcard. $_.Key -like $TaskToExport }.ForEach{ # Dot-sourcing the Tasks via their exported aliases. . (Get-Alias $_.Key) } } } catch { Write-Host -Object "Could not load tasks for module $module." -ForegroundColor Red Write-Error -Message $_ } } } # Loading Build Tasks defined in the .build/ folder (will override the ones imported above if same task name). Get-ChildItem -Path '.build/' -Recurse -Include '*.ps1' -ErrorAction Ignore | ForEach-Object { "Importing file $($_.BaseName)" | Write-Verbose . $_.FullName } # Synopsis: Empty task, useful to test the bootstrap process. task noop { } # Define default task sequence ("."), can be overridden in the $BuildInfo. task . { Write-Build -Object 'No sequence currently defined for the default task' -ForegroundColor Yellow } Write-Host -Object 'Adding Workflow from configuration:' -ForegroundColor DarkGray # Load Invoke-Build task sequences/workflows from $BuildInfo. foreach ($workflow in $BuildInfo.BuildWorkflow.keys) { Write-Verbose -Message "Creating Build Workflow '$Workflow' with tasks $($BuildInfo.BuildWorkflow.($Workflow) -join ', ')." $workflowItem = $BuildInfo.BuildWorkflow.($workflow) if ($workflowItem.Trim() -match '^\{(?[\w\W]*)\}$') { $workflowItem = [ScriptBlock]::Create($Matches['sb']) } Write-Host -Object " +-> $workflow" -ForegroundColor DarkGray task $workflow $workflowItem } Write-Host -Object "[build] Executing requested workflow: $($Tasks -join ', ')" -ForeGroundColor Magenta } finally { Pop-Location -StackName 'BeforeBuild' } } Begin { # Find build config if not specified. if (-not $BuildConfig) { $config = Get-ChildItem -Path "$PSScriptRoot\*" -Include 'build.y*ml', 'build.psd1', 'build.json*' -ErrorAction Ignore if (-not $config -or ($config -is [System.Array] -and $config.Length -le 0)) { throw 'No build configuration found. Specify path via parameter BuildConfig.' } elseif ($config -is [System.Array]) { if ($config.Length -gt 1) { throw 'More than one build configuration found. Specify which path to use via parameter BuildConfig.' } $BuildConfig = $config[0] } else { $BuildConfig = $config } } # Bootstrapping the environment before using Invoke-Build as task runner if ($MyInvocation.ScriptName -notlike '*Invoke-Build.ps1') { Write-Host -Object "[pre-build] Starting Build Init" -ForegroundColor Green Push-Location $PSScriptRoot -StackName 'BuildModule' } if ($RequiredModulesDirectory -in @('CurrentUser', 'AllUsers')) { # Installing modules instead of saving them. Write-Host -Object "[pre-build] Required Modules will be installed to the PowerShell module path that is used for $RequiredModulesDirectory." -ForegroundColor Green <# The variable $PSDependTarget will be used below when building the splatting variable before calling Resolve-Dependency.ps1, unless overridden in the file Resolve-Dependency.psd1. #> $PSDependTarget = $RequiredModulesDirectory } else { if (-not (Split-Path -IsAbsolute -Path $OutputDirectory)) { $OutputDirectory = Join-Path -Path $PSScriptRoot -ChildPath $OutputDirectory } # Resolving the absolute path to save the required modules to. if (-not (Split-Path -IsAbsolute -Path $RequiredModulesDirectory)) { $RequiredModulesDirectory = Join-Path -Path $PSScriptRoot -ChildPath $RequiredModulesDirectory } # Create the output/modules folder if not exists, or resolve the Absolute path otherwise. if (Resolve-Path -Path $RequiredModulesDirectory -ErrorAction SilentlyContinue) { Write-Debug -Message "[pre-build] Required Modules path already exist at $RequiredModulesDirectory" $requiredModulesPath = Convert-Path -Path $RequiredModulesDirectory } else { Write-Host -Object "[pre-build] Creating required modules directory $RequiredModulesDirectory." -ForegroundColor Green $requiredModulesPath = (New-Item -ItemType Directory -Force -Path $RequiredModulesDirectory).FullName } $powerShellModulePaths = $env:PSModulePath -split [System.IO.Path]::PathSeparator # Pre-pending $requiredModulesPath folder to PSModulePath to resolve from this folder FIRST. if ($RequiredModulesDirectory -notin @('CurrentUser', 'AllUsers') -and ($powerShellModulePaths -notcontains $RequiredModulesDirectory)) { Write-Host -Object "[pre-build] Pre-pending '$RequiredModulesDirectory' folder to PSModulePath" -ForegroundColor Green $env:PSModulePath = $RequiredModulesDirectory + [System.IO.Path]::PathSeparator + $env:PSModulePath } $powerShellYamlModule = Get-Module -Name 'powershell-yaml' -ListAvailable $invokeBuildModule = Get-Module -Name 'InvokeBuild' -ListAvailable $psDependModule = Get-Module -Name 'PSDepend' -ListAvailable # Checking if the user should -ResolveDependency. if (-not ($powerShellYamlModule -and $invokeBuildModule -and $psDependModule) -and -not $ResolveDependency) { if ($AutoRestore -or -not $PSBoundParameters.ContainsKey('Tasks') -or $Tasks -contains 'build') { Write-Host -Object "[pre-build] Dependency missing, running './build.ps1 -ResolveDependency -Tasks noop' for you `r`n" -ForegroundColor Yellow $ResolveDependency = $true } else { Write-Warning -Message "Some required Modules are missing, make sure you first run with the '-ResolveDependency' parameter. Running 'build.ps1 -ResolveDependency -Tasks noop' will pull required modules without running the build task." } } <# The variable $PSDependTarget will be used below when building the splatting variable before calling Resolve-Dependency.ps1, unless overridden in the file Resolve-Dependency.psd1. #> $PSDependTarget = $requiredModulesPath } if ($ResolveDependency) { Write-Host -Object "[pre-build] Resolving dependencies." -ForegroundColor Green $resolveDependencyParams = @{ } # If BuildConfig is a Yaml file, bootstrap powershell-yaml via ResolveDependency. if ($BuildConfig -match '\.[yaml|yml]$') { $resolveDependencyParams.Add('WithYaml', $true) } $resolveDependencyAvailableParams = (Get-Command -Name '.\Resolve-Dependency.ps1').Parameters.Keys foreach ($cmdParameter in $resolveDependencyAvailableParams) { # The parameter has been explicitly used for calling the .build.ps1 if ($MyInvocation.BoundParameters.ContainsKey($cmdParameter)) { $paramValue = $MyInvocation.BoundParameters.Item($cmdParameter) Write-Debug " adding $cmdParameter :: $paramValue [from user-provided parameters to Build.ps1]" $resolveDependencyParams.Add($cmdParameter, $paramValue) } # Use defaults parameter value from Build.ps1, if any else { $paramValue = Get-Variable -Name $cmdParameter -ValueOnly -ErrorAction Ignore if ($paramValue) { Write-Debug " adding $cmdParameter :: $paramValue [from default Build.ps1 variable]" $resolveDependencyParams.Add($cmdParameter, $paramValue) } } } Write-Host -Object "[pre-build] Starting bootstrap process." -ForegroundColor Green .\Resolve-Dependency.ps1 @resolveDependencyParams } if ($MyInvocation.ScriptName -notlike '*Invoke-Build.ps1') { Write-Verbose -Message "Bootstrap completed. Handing back to InvokeBuild." if ($PSBoundParameters.ContainsKey('ResolveDependency')) { Write-Verbose -Message "Dependency already resolved. Removing task." $null = $PSBoundParameters.Remove('ResolveDependency') } Write-Host -Object "[build] Starting build with InvokeBuild." -ForegroundColor Green Invoke-Build @PSBoundParameters -Task $Tasks -File $MyInvocation.MyCommand.Path Pop-Location -StackName 'BuildModule' return } } ================================================ FILE: build.yaml ================================================ --- # Invoke-Build Header to be used to 'decorate' the terminal output of the tasks. TaskHeader: | param($Path) "" "=" * 79 Write-Build Cyan "`t`t`t$($Task.Name.replace("_"," ").ToUpper())" Write-Build DarkGray "$(Get-BuildSynopsis $Task)" "-" * 79 Write-Build DarkGray " $Path" Write-Build DarkGray " $($Task.InvocationInfo.ScriptName):$($Task.InvocationInfo.ScriptLineNumber)" "" #################################################### # Pipeline Build Task Configuration (Invoke-Build) # #################################################### BuildWorkflow: '.': - build - test build: - Clean - Build_Module_ModuleBuilder - Build_NestedModules_ModuleBuilder - Create_changelog_release_output pack: - build - package_module_nupkg test: - Pester_Tests_Stop_On_Fail #- Convert_Pester_Coverage - Pester_if_Code_Coverage_Under_Threshold # Use this task when you have multiple parallel tests, which produce multiple # code coverage files and needs to get merged into one file. #merge: #- Merge_CodeCoverage_Files publish: - publish_module_to_gallery - Publish_Release_To_GitHub # - Publish_GitHub_Wiki_Content #################################################### # ModuleBuilder Configuration # #################################################### CopyPaths: - bin - checks - functions - internal - xml Encoding: UTF8 VersionedOutputDirectory: true #################################################### # PESTER Configuration # #################################################### # PESTER CONFIG START Pester: # Pester Advanced configuration. # If a key is not set it will be using Sampler pipeline default value. Configuration: Run: Path: tests ExcludePath: Filter: Tag: ExcludeTag: Output: Verbosity: None CodeCoverage: Path: '*/checks/*' OutputFormat: CoveragePercentTarget: 0 OutputPath: JaCoCo_coverage.xml OutputEncoding: ascii ExcludeTests: TestResult: OutputFormat: NUnitXML OutputPath: OutputEncoding: TestSuiteName: #################################################### # Import ModuleBuilder Configuration # #################################################### # Import ModuleBuilder tasks from a specific PowerShell module using the build task's alias. Wildcard * can be used to specify all tasks that has a similar # prefix and or suffix. The module contain the task must be added as a required # module in the file RequiredModules.psd1. ModuleBuildTasks: Sampler: - '*.build.Sampler.ib.tasks' Sampler.GitHubTasks: - '*.ib.tasks' #################################################### # PSDepend Configuration # #################################################### Resolve-Dependency: Gallery: 'PSGallery' AllowPrerelease: false Verbose: false #################################################### # GitHub Configuration # #################################################### GitHubConfig: GitHubFilesToAdd: - 'CHANGELOG.md' GitHubConfigUserName: BeardAutoBot GitHubConfigUserEmail: mrrobsewell@outlook.com UpdateChangelogOnPrerelease: true ================================================ FILE: builddocs.ps1 ================================================ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Install-Module PlatyPs -Scope CurrentUser -Force Import-Module PlatyPs # Get the Module versions Install-Module Configuration -RequiredVersion 1.3.0 -Scope CurrentUser -Force $Modules = Get-ManifestValue -Path .\dbachecks.psd1 -PropertyName RequiredModules $PSFrameworkVersion = $Modules.Where{$_.Get_Item('ModuleName') -eq 'PSFramework'}[0].Get_Item('ModuleVersion') $dbatoolsVersion = $Modules.Where{$_.Get_Item('ModuleName') -eq 'dbatools'}[0].Get_Item('ModuleVersion') # Install Pester try { Write-Output "Installing Pester" Install-Module Pester -RequiredVersion 4.10.0 -Scope CurrentUser -Force -SkipPublisherCheck Write-Output "Installed Pester" } catch { Write-Error "Failed to Install Pester $($_)" } # Install dbatools try { Write-Output "Installing PSFramework" Install-Module PSFramework -RequiredVersion $PsFrameworkVersion -Scope CurrentUser -Force Write-Output "Installed PSFramework" } catch { Write-Error "Failed to Install PSFramework $($_)" } # Install dbachecks try { Write-Output "Installing dbatools" Write-Output "Install-Module dbatools -RequiredVersion $dbatoolsVersion -Scope CurrentUser -Force" Install-Module dbatools -RequiredVersion $dbatoolsVersion -Scope CurrentUser -Force Write-Output "Installed dbatools" } catch { Write-Error "Failed to Install dbatools $($_)" } # Add current folder to PSModulePath try { Write-Output "Adding local folder to PSModulePath" $ENV:PSModulePath = $ENV:PSModulePath + ";$pwd" Write-Output "Added local folder to PSModulePath" $ENV:PSModulePath.Split(';') } catch { Write-Error "Failed to add $pwd to PSModulePAth - $_" } try { Write-Output "Importing dbachecks" Import-Module .\dbachecks.psd1 -verbose Write-Output "Imported dbachecks" } catch { try { Write-Output "Importing dbachecks again to get around the stupid failure for dbatools" Import-Module .\dbachecks.psd1 -verbose Write-Output "Imported dbachecks - again to get around the stupid failure for dbatools" } catch { Write-Error "Failed to Install dbachecks $($_)" } } $ProjectRoot = Get-Location $ReleaseNotes = ".\RELEASE.md" $ChangeLog = "$ProjectRoot\docs\ChangeLog.md" #Build YAMLText starting with the header $YMLtext = (Get-Content "$ProjectRoot\header-mkdocs.yml") -join "`n" $YMLtext = "$YMLtext`n" $parameters = @{ Path = $ReleaseNotes ErrorAction = 'SilentlyContinue' } $ReleaseText = (Get-Content @parameters) -join "`n" if ($ReleaseText) { $ReleaseText | Set-Content "$ProjectRoot\docs\RELEASE.md" $YMLText = "$YMLtext - Release Notes: RELEASE.md`n" } if ((Test-Path -Path $ChangeLog)) { $YMLText = "$YMLtext - Change Log: ChangeLog.md`n" } $YMLText = "$YMLtext - Functions:`n" $Params = @{ Module = 'dbachecks' Force = $true OutputFolder = "$ProjectRoot\docs\functions" NoMetadata = $true } New-MarkdownHelp @Params | foreach-object { $Function = $_.Name -replace '\.md', '' $Part = " - {0}: functions/{1}" -f $Function, $_.Name $YMLText = "{0}{1}`n" -f $YMLText, $Part $Part } $YMLtext | Set-Content -Path "$ProjectRoot\mkdocs.yml" # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUDdPclX9bMrkY1BsUGvj1TEwy # ciqgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBSzz+yLLVqFPDBCsi+BQFmjwuh5 # CDANBgkqhkiG9w0BAQEFAASCAQAI3TlWQUHrQTKwuJY5pedwnfvBmc2GSTrPbMhQ # arwpd8yDmEMl9QCuUDEcRYSyXaLoxqa5RgVpIj717MUFSmVDWPTKtXuTak23Mstv # vl88D/cpH5fJvkdM7IA+EMdfX9q03wWMnKop84MiAdsKfyLPN+xCNx5jLy/CYOEm # 8k8f3TrZ8z4/zZIsYiAS0kQHx1okKF4+cvYUNParzPyfWJVVhdfsquNnW3x6C1hK # E0pI9m6gW0ZXsNn3rLwi4bc68GUuMsNQTGN4DuihFGo1OGhFt8OZ40lTglfYWmVr # pepNkgAGQFJLoYWlWMuCOUFbcqfA2XU88s9M1sAfrjY69mLj # SIG # End signature block ================================================ FILE: codecov.yml ================================================ codecov: require_ci_to_pass: no # main should be the baseline for reporting branch: main comment: layout: "reach, diff, flags, files" behavior: default coverage: range: 50..80 round: down precision: 0 status: project: default: # Set the overall project code coverage requirement to 70% target: 70 patch: default: # Set the pull request requirement to not regress overall coverage by more than 5% # and let codecov.io set the goal for the code changed in the patch. target: auto threshold: 5 # This is not needed if the module only contain class-based resources. fixes: - '^\d+\.\d+\.\d+::source' # move path "X.Y.Z" => "source" # Use this if there are paths that should not be part of the code coverage, for # example a deprecated function where tests has been removed. #ignore: # - 'source/Public/Get-Deprecated.ps1' ================================================ FILE: containers/JessAndBeard.psm1 ================================================ # TODO remove all the training day code :-) [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '', Justification = 'Because this is just for testing and developing')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'Because this is for the prompt and it is required')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'containers', Justification = 'Because it is a global variable used later')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'SQLInstances', Justification = 'Because it is a global variable used later')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'currentAccountName', Justification = 'Because silly script analyuser cant see it is used')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'v4code', Justification = 'Because silly script analyuser cant see it is used')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'v5code', Justification = 'Because silly script analyuser cant see it is used')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'originalCodeMessage', Justification = 'Because silly script analyuser cant see it is used')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'cred', Justification = 'Because silly script analyuser cant see it is used')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', 'Global:allofTheThings', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', 'Global:Italwaysis', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', 'Global:v4code', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', 'Global:v5code', Justification = 'Dont tell me what to do')] [CmdletBinding()] param() #region words $ShallWePLayAGame = @" _____ _ _ _ __ __ _____ _ _____ ___ / ____| | | | | \ \ / / | __ \| | /\ / ____| |__ \ | (___ | |__ __ _| | | \ \ /\ / /__ | |__) | | __ _ _ _ / \ | | __ __ _ _ __ ___ ___ ) | \___ \| '_ \ / _` | | | \ \/ \/ / _ \ | ___/| |/ _` | | | | / /\ \ | | |_ |/ _` | '_ ` _ \ / _ \/ / ____) | | | | (_| | | | \ /\ / __/ | | | | (_| | |_| | / ____ \ | |__| | (_| | | | | | | __/_| |_____/|_| |_|\__,_|_|_| \/ \/ \___| |_| |_|\__,_|\__, | /_/ \_\ \_____|\__,_|_| |_| |_|\___(_) __/ | |___/ "@ #ANSI Shadow https://patorjk.com/software/taag/#p=testall&f=Doom&t=Shall%20We%20Play%20A%20Game%3F $ShallWePLayAGame = @" ███████╗██╗ ██╗ █████╗ ██╗ ██╗ ██╗ ██╗███████╗ ██████╗ ██╗ █████╗ ██╗ ██╗ █████╗ ██████╗ █████╗ ███╗ ███╗███████╗██████╗ ██╔════╝██║ ██║██╔══██╗██║ ██║ ██║ ██║██╔════╝ ██╔══██╗██║ ██╔══██╗╚██╗ ██╔╝ ██╔══██╗ ██╔════╝ ██╔══██╗████╗ ████║██╔════╝╚════██╗ ███████╗███████║███████║██║ ██║ ██║ █╗ ██║█████╗ ██████╔╝██║ ███████║ ╚████╔╝ ███████║ ██║ ███╗███████║██╔████╔██║█████╗ ▄███╔╝ ╚════██║██╔══██║██╔══██║██║ ██║ ██║███╗██║██╔══╝ ██╔═══╝ ██║ ██╔══██║ ╚██╔╝ ██╔══██║ ██║ ██║██╔══██║██║╚██╔╝██║██╔══╝ ▀▀══╝ ███████║██║ ██║██║ ██║███████╗███████╗ ╚███╔███╔╝███████╗ ██║ ███████╗██║ ██║ ██║ ██║ ██║ ╚██████╔╝██║ ██║██║ ╚═╝ ██║███████╗ ██╗ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚══════╝ ╚══╝╚══╝ ╚══════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ ╚═╝ "@ $OhNo1 = @" ██████ ██░ ██ ▄▄▄ ██▓ ██▓ █ █░▓█████ ██▓███ ██▓ ▄▄▄ ▓██ ██▓ ▄▄▄ ▄████ ▄▄▄ ███▄ ▄███▓▓█████ ▒██ ▒ ▓██░ ██▒▒████▄ ▓██▒ ▓██▒ ▓█░ █ ░█░▓█ ▀ ▓██░ ██▒▓██▒ ▒████▄ ▒██ ██▒ ▒████▄ ██▒ ▀█▒▒████▄ ▓██▒▀█▀ ██▒▓█ ▀ ░ ▓██▄ ▒██▀▀██░▒██ ▀█▄ ▒██░ ▒██░ ▒█░ █ ░█ ▒███ ▓██░ ██▓▒▒██░ ▒██ ▀█▄ ▒██ ██░ ▒██ ▀█▄ ▒██░▄▄▄░▒██ ▀█▄ ▓██ ▓██░▒███ ▒ ██▒░▓█ ░██ ░██▄▄▄▄██ ▒██░ ▒██░ ░█░ █ ░█ ▒▓█ ▄ ▒██▄█▓▒ ▒▒██░ ░██▄▄▄▄██ ░ ▐██▓░ ░██▄▄▄▄██ ░▓█ ██▓░██▄▄▄▄██ ▒██ ▒██ ▒▓█ ▄ ▒██████▒▒░▓█▒░██▓ ▓█ ▓██▒░██████▒░██████▒ ░░██▒██▓ ░▒████▒ ▒██▒ ░ ░░██████▒▓█ ▓██▒ ░ ██▒▓░ ▓█ ▓██▒ ░▒▓███▀▒ ▓█ ▓██▒▒██▒ ░██▒░▒████▒ ▒ ▒▓▒ ▒ ░ ▒ ░░▒░▒ ▒▒ ▓▒█░░ ▒░▓ ░░ ▒░▓ ░ ░ ▓░▒ ▒ ░░ ▒░ ░ ▒▓▒░ ░ ░░ ▒░▓ ░▒▒ ▓▒█░ ██▒▒▒ ▒▒ ▓▒█░ ░▒ ▒ ▒▒ ▓▒█░░ ▒░ ░ ░░░ ▒░ ░ ░ ░▒ ░ ░ ▒ ░▒░ ░ ▒ ▒▒ ░░ ░ ▒ ░░ ░ ▒ ░ ▒ ░ ░ ░ ░ ░ ░▒ ░ ░ ░ ▒ ░ ▒ ▒▒ ░▓██ ░▒░ ▒ ▒▒ ░ ░ ░ ▒ ▒▒ ░░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░░ ░ ░ ▒ ░ ░ ░ ░ ░ ░ ░ ░░ ░ ░ ░ ▒ ▒ ▒ ░░ ░ ▒ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ "@ $OhNo2 = @" ▄████ ▒█████ ▒█████ ▓█████▄ ▄▄▄▄ ▓██ ██▓▓█████ ██▒ ▀█▒▒██▒ ██▒▒██▒ ██▒▒██▀ ██▌ ▓█████▄▒██ ██▒▓█ ▀ ▒██░▄▄▄░▒██░ ██▒▒██░ ██▒░██ █▌ ▒██▒ ▄██▒██ ██░▒███ ░▓█ ██▓▒██ ██░▒██ ██░░▓█▄ ▌ ▒██░█▀ ░ ▐██▓░▒▓█ ▄ ░▒▓███▀▒░ ████▓▒░░ ████▓▒░░▒████▓ ░▓█ ▀█▓░ ██▒▓░░▒████▒ ░▒ ▒ ░ ▒░▒░▒░ ░ ▒░▒░▒░ ▒▒▓ ▒ ░▒▓███▀▒ ██▒▒▒ ░░ ▒░ ░ ░ ░ ░ ▒ ▒░ ░ ▒ ▒░ ░ ▒ ▒ ▒░▒ ░▓██ ░▒░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ▒ ░ ░ ░ ░ ░▒ ▒ ░░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░░ ░ ▄▄▄█████▓ ██░ ██ ▓█████ ▓█████ ███▄ █ ▓█████▄ ▓ ██▒ ▓▒▓██░ ██▒▓█ ▀ ▓█ ▀ ██ ▀█ █ ▒██▀ ██▌ ▒ ▓██░ ▒░▒██▀▀██░▒███ ▒███ ▓██ ▀█ ██▒░██ █▌ ░ ▓██▓ ░ ░▓█ ░██ ▒▓█ ▄ ▒▓█ ▄ ▓██▒ ▐▌██▒░▓█▄ ▌ ▒██▒ ░ ░▓█▒░██▓░▒████▒ ░▒████▒▒██░ ▓██░░▒████▓ ▒ ░░ ▒ ░░▒░▒░░ ▒░ ░ ░░ ▒░ ░░ ▒░ ▒ ▒ ▒▒▓ ▒ ░ ▒ ░▒░ ░ ░ ░ ░ ░ ░ ░░ ░░ ░ ▒░ ░ ▒ ▒ ░ ░ ░░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ "@ $ChooseYourgame = @" ██████ ██ ██ ██████ ██████ ███████ ███████ ██ ██ ██████ ██ ██ ██████ ██████ █████ ███ ███ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ███████ ██ ██ ██ ██ ███████ █████ ████ ██ ██ ██ ██ ██████ ██ ███ ███████ ██ ████ ██ █████ █████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██████ ██ ██ ██████ ██████ ███████ ███████ ██ ██████ ██████ ██ ██ ██████ ██ ██ ██ ██ ███████ "@ $wrongChoice = @" █ █░ ██▀███ ▒█████ ███▄ █ ▄████ ▓█░ █ ░█░▓██ ▒ ██▒▒██▒ ██▒ ██ ▀█ █ ██▒ ▀█▒ ▒█░ █ ░█ ▓██ ░▄█ ▒▒██░ ██▒▓██ ▀█ ██▒▒██░▄▄▄░ ░█░ █ ░█ ▒██▀▀█▄ ▒██ ██░▓██▒ ▐▌██▒░▓█ ██▓ ░░██▒██▓ ░██▓ ▒██▒░ ████▓▒░▒██░ ▓██░░▒▓███▀▒ ░ ▓░▒ ▒ ░ ▒▓ ░▒▓░░ ▒░▒░▒░ ░ ▒░ ▒ ▒ ░▒ ▒ ▒ ░ ░ ░▒ ░ ▒░ ░ ▒ ▒░ ░ ░░ ░ ▒░ ░ ░ ░ ░ ░░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ▄████▄ ██░ ██ ▒█████ ██▓ ▄████▄ ▓█████ ▒██▀ ▀█ ▓██░ ██▒▒██▒ ██▒▓██▒▒██▀ ▀█ ▓█ ▀ ▒▓█ ▄ ▒██▀▀██░▒██░ ██▒▒██▒▒▓█ ▄ ▒███ ▒▓▓▄ ▄██▒░▓█ ░██ ▒██ ██░░██░▒▓▓▄ ▄██▒▒▓█ ▄ ▒ ▓███▀ ░░▓█▒░██▓░ ████▓▒░░██░▒ ▓███▀ ░░▒████▒ ░ ░▒ ▒ ░ ▒ ░░▒░▒░ ▒░▒░▒░ ░▓ ░ ░▒ ▒ ░░░ ▒░ ░ ░ ▒ ▒ ░▒░ ░ ░ ▒ ▒░ ▒ ░ ░ ▒ ░ ░ ░ ░ ░ ░░ ░░ ░ ░ ▒ ▒ ░░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ "@ $Global:allofTheThings = @" ▄▄▄ ██▓ ██▓ ▒█████ █████▒ ▄▄▄█████▓ ██░ ██ ▓█████ ▒████▄ ▓██▒ ▓██▒ ▒██▒ ██▒▓██ ▒ ▓ ██▒ ▓▒▓██░ ██▒▓█ ▀ ▒██ ▀█▄ ▒██░ ▒██░ ▒██░ ██▒▒████ ░ ▒ ▓██░ ▒░▒██▀▀██░▒███ ░██▄▄▄▄██ ▒██░ ▒██░ ▒██ ██░░▓█▒ ░ ░ ▓██▓ ░ ░▓█ ░██ ▒▓█ ▄ ▓█ ▓██▒░██████▒░██████▒ ░ ████▓▒░░▒█░ ▒██▒ ░ ░▓█▒░██▓░▒████▒ ▒▒ ▓▒█░░ ▒░▓ ░░ ▒░▓ ░ ░ ▒░▒░▒░ ▒ ░ ▒ ░░ ▒ ░░▒░▒░░ ▒░ ░ ▒ ▒▒ ░░ ░ ▒ ░░ ░ ▒ ░ ░ ▒ ▒░ ░ ░ ▒ ░▒░ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ▄▄▄█████▓ ██░ ██ ██▓ ███▄ █ ▄████ ██████ ▓ ██▒ ▓▒▓██░ ██▒▓██▒ ██ ▀█ █ ██▒ ▀█▒▒██ ▒ ▒ ▓██░ ▒░▒██▀▀██░▒██▒▓██ ▀█ ██▒▒██░▄▄▄░░ ▓██▄ ░ ▓██▓ ░ ░▓█ ░██ ░██░▓██▒ ▐▌██▒░▓█ ██▓ ▒ ██▒ ▒██▒ ░ ░▓█▒░██▓░██░▒██░ ▓██░░▒▓███▀▒▒██████▒▒ ▒ ░░ ▒ ░░▒░▒░▓ ░ ▒░ ▒ ▒ ░▒ ▒ ▒ ▒▓▒ ▒ ░ ░ ▒ ░▒░ ░ ▒ ░░ ░░ ░ ▒░ ░ ░ ░ ░▒ ░ ░ ░ ░ ░░ ░ ▒ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ "@ $Global:Italwaysis = @" ██▓▄▄▄█████▓ ██████ ▄▄▄ ██▓ █ █░ ▄▄▄ ▓██ ██▓ ██████ ▓██▒▓ ██▒ ▓▒▒██ ▒ ▒████▄ ▓██▒ ▓█░ █ ░█░▒████▄ ▒██ ██▒▒██ ▒ ▒██▒▒ ▓██░ ▒░░ ▓██▄ ▒██ ▀█▄ ▒██░ ▒█░ █ ░█ ▒██ ▀█▄ ▒██ ██░░ ▓██▄ ░██░░ ▓██▓ ░ ▒ ██▒ ░██▄▄▄▄██ ▒██░ ░█░ █ ░█ ░██▄▄▄▄██ ░ ▐██▓░ ▒ ██▒ ░██░ ▒██▒ ░ ▒██████▒▒ ▓█ ▓██▒░██████▒░░██▒██▓ ▓█ ▓██▒ ░ ██▒▓░▒██████▒▒ ░▓ ▒ ░░ ▒ ▒▓▒ ▒ ░ ▒▒ ▓▒█░░ ▒░▓ ░░ ▓░▒ ▒ ▒▒ ▓▒█░ ██▒▒▒ ▒ ▒▓▒ ▒ ░ ▒ ░ ░ ░ ░▒ ░ ░ ▒ ▒▒ ░░ ░ ▒ ░ ▒ ░ ░ ▒ ▒▒ ░▓██ ░▒░ ░ ░▒ ░ ░ ▒ ░ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░ ▒ ▒ ▒ ░░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░░ ░ ░ ░ ░ ▄▄▄█████▓ ██░ ██ ██▀███ ▓█████ ▓█████ ▄▄▄ ███▄ ▄███▓ ▓ ██▒ ▓▒▓██░ ██▒▓██ ▒ ██▒▓█ ▀ ▓█ ▀ ▒████▄ ▓██▒▀█▀ ██▒ ▒ ▓██░ ▒░▒██▀▀██░▓██ ░▄█ ▒▒███ ▒███ ▒██ ▀█▄ ▓██ ▓██░ ░ ▓██▓ ░ ░▓█ ░██ ▒██▀▀█▄ ▒▓█ ▄ ▒▓█ ▄ ░██▄▄▄▄██ ▒██ ▒██ ▒██▒ ░ ░▓█▒░██▓░██▓ ▒██▒░▒████▒░▒████▒ ▓█ ▓██▒▒██▒ ░██▒ ▒ ░░ ▒ ░░▒░▒░ ▒▓ ░▒▓░░░ ▒░ ░░░ ▒░ ░ ▒▒ ▓▒█░░ ▒░ ░ ░ ░ ▒ ░▒░ ░ ░▒ ░ ▒░ ░ ░ ░ ░ ░ ░ ▒ ▒▒ ░░ ░ ░ ░ ░ ░░ ░ ░░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ "@ #endregion # If we are not using the config files because they take too long even though they are the correct wya to do things # we don't need this replace inhere # [version]$dbachecksversioninconfig = (Get-DbcConfigValue -Name app.checkrepos).Split('/')[-1].Split('\')[0] # [version]$dbachecksmodulevarsion = (Get-Module dbachecks).Version # # if ($dbachecksmodulevarsion -ne $dbachecksversioninconfig) { # Get-ChildItem /workspace/Demos/dbachecksconfigs/*.json | ForEach-Object { # (Get-Content -Path $_.FullName) -replace $dbachecksversioninconfig, $dbachecksmodulevarsion | Set-Content $_.FullName # } # } function Start-Game { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'Clear-Host', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'cls', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', 'cls', Justification = 'Dont tell me what to do')] [CmdletBinding()] param() #region set-up # Because we are using volumes for the restore demo, need to ensure they are clean before starting the game Remove-Item '/var/opt/backups/dbachecks1' -Recurse -Force -ErrorAction SilentlyContinue $securePassword = ('dbatools.IO' | ConvertTo-SecureString -AsPlainText -Force) $containercredential = New-Object System.Management.Automation.PSCredential('sqladmin', $securePassword) New-DbaDatabase -SqlInstance $dbachecks1 -SqlCredential $containercredential -Name Validation -RecoveryModel Full -WarningAction SilentlyContinue | Out-Null # we need an app login $Password = ConvertTo-SecureString PubsAdmin -AsPlainText -Force New-DbaLogin -SqlInstance $dbachecks1 -SqlCredential $containercredential -Login PubsAdmin -SecurePassword $Password -WarningAction SilentlyContinue | Out-Null New-DbaDbUser -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Pubs -Login PubsAdmin -Username PubsAdmin -WarningAction SilentlyContinue | Out-Null Add-DbaDbRoleMember -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Pubs -User PubsAdmin -Role db_owner -Confirm:$false | Out-Null # Let's add some things to find Invoke-DbaQuery -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Northwind -WarningAction SilentlyContinue -Query " CREATE PROCEDURE SP_FindMe AS BEGIN with cte as ( select top 1 OrderID, ProductID FROM dbo.[Order Details] ORDER BY NEWID() ) DELETE FROM cte END GO CREATE TRIGGER dbo.trg_chaos_monkey ON dbo.[order details] INSTEAD OF UPDATE AS BEGIN print 'no update for you' END GO CREATE FUNCTION udf_FindMe (@test int = 1) RETURNS int AS -- For the order details BEGIN RETURN @test END" # Add a failed job $job = New-DbaAgentJob -SqlInstance $dbachecks2 -SqlCredential $containercredential -Job IamBroke -WarningAction SilentlyContinue if ($job) { $null = New-DbaAgentJobStep -SqlInstance $dbachecks2 -SqlCredential $containercredential -Job $job.Name -Subsystem TransactSql -Command 'Select * from MissingTable' -StepName 'Step One' $null = $job | Start-DbaAgentJob } #endregion Clear-Host # dont use cls here $title = "Joshua Says" $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Will continue" $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Will exit" $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) $result = $host.ui.PromptForChoice($title, $ShallWePLayAGame, $options, 0) if ($result -eq 1) { cls Write-Output $OhNo1 Start-Sleep -Seconds 1 cls Start-Sleep -Milliseconds 250 Write-Output $OhNo2 } elseif ($result -eq 0) { Clear-Host # Dont use cls here Get-Index } } function Get-Index { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'Clear-Host', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'cls', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', 'cls', Justification = 'Dont tell me what to do')] [CmdletBinding()] param() cls Write-Output $ChooseYourgame $gameChapters = @( ("&1 - Introduction to dbatools", "1 - Introduction to dbatools"), ("&2 - Backup and Restore", "2 - Backup and Restore"), ("&3 - Copy Copy Copy", "3 - Copy Copy Copy"), ("&4 - Snapshots", "4 - Snapshots"), ("&5 - Export", "5 - Export"), ("&6 - Availability Groups", "6 - Availability Groups"), ("&7 - Finding Things", "7 - Finding Things"), ("&8 - Data Masking", "8 - Data Masking"), ("&9 - Logins", "9 - Logins"), ("&M - Advanced Migrations", "10 - Advanced Migrations"), ("&R - Registered Servers", "11 - Registered Servers"), ("&C - Estate Validation", "12 - Estate Validation"), ("&T - TIC TAC TOE", "98 - TIC TAC TOE"), ("&Q - Quit", "Quit") ) $options = New-Object System.Collections.ObjectModel.Collection[System.Management.Automation.Host.ChoiceDescription] foreach ($Chapter in $gameChapters) { $message = '{0}' -f $chapter[1] Write-Output $message $options.Add((New-Object System.Management.Automation.Host.ChoiceDescription $Chapter ) ) } $title = "Joshua Says" $IndexChoice = $host.ui.PromptForChoice($title, "Make Your Choice", $options, 0) + 1 switch ($IndexChoice) { 1 { cls code /workspace/Demos/01-introduction.ps1 #reset and run tests Write-PSFHostColor -String "It was a dark and stormy morning and ripe for learning about dbatools" -DefaultColor DarkCyan Write-PSFHostColor -String "The teachers arrived in the class first thing and ran some tests" -DefaultColor DarkYellow Write-PSFHostColor -String "They needed to ensure that nothing was wrong before" -DefaultColor DarkRed Write-PSFHostColor -String "The Introduction to dbatools" -DefaultColor DarkMagenta Write-PSFHostColor -String "Narrator - The Tests are running" -DefaultColor Blue Assert-Correct -chapter intro Get-GameTimeRemaining } 2 { cls code /workspace/Demos/02-BackUpRestore.ps1 Write-PSFHostColor -String "All the students knew that backups and restores were so very important" -DefaultColor DarkCyan Write-PSFHostColor -String "To ensure the safety and security of their employees data" -DefaultColor DarkYellow Write-PSFHostColor -String "The instructors need to ensure that everything is ok before" -DefaultColor DarkRed Write-PSFHostColor -String "2 - Backup and Restore" -DefaultColor DarkMagenta Write-PSFHostColor -String "Narrator - The Tests are running" -DefaultColor Blue Assert-Correct -chapter Backup Get-GameTimeRemaining } 3 { cls code /workspace/Demos/03-CopyCopy.ps1 Write-PSFHostColor -String "Entering this chapter carefully" -DefaultColor DarkCyan Write-PSFHostColor -String "the players realised that is all looked the same" -DefaultColor DarkYellow Write-PSFHostColor -String "It's almost like it has been copied over" -DefaultColor DarkRed Write-PSFHostColor -String "3 - Copy Copy Copy" -DefaultColor DarkMagenta Write-PSFHostColor -String "Narrator - The Tests are running" -DefaultColor Blue Assert-Correct -chapter Copy Get-GameTimeRemaining } 4 { cls code /workspace/Demos/04-Snapshots.ps1 Write-PSFHostColor -String "The sound of a gun echoed down the corridor" -DefaultColor DarkCyan Write-PSFHostColor -String "But as the mist cleared they realised that it was not that sort of shot" -DefaultColor DarkYellow Write-PSFHostColor -String "Welcome, said the deep voice, come on in" -DefaultColor DarkRed Write-PSFHostColor -String "4 - SnapShots" -DefaultColor DarkMagenta Write-PSFHostColor -String "Narrator - The Tests are running" -DefaultColor Blue Assert-Correct -chapter SnapShots Get-GameTimeRemaining } 6 { cls code /workspace/Demos/06-AvailabilityGroups.ps1 Write-PSFHostColor -String "The noise was getting louder" -DefaultColor DarkCyan Write-PSFHostColor -String "This machine can no longer take the strain of the app and the reporting" -DefaultColor DarkYellow Write-PSFHostColor -String "I need many copies of this data the voice shouted and quickly now" -DefaultColor DarkRed Write-PSFHostColor -String "6 - Availability Groups" -DefaultColor DarkMagenta Write-PSFHostColor -String "Narrator - The Tests are running" -DefaultColor Blue Assert-Correct -chapter Ags Get-GameTimeRemaining } 5 { cls code /workspace/Demos/05-Export.ps1 Write-PSFHostColor -String "As they stomped through the swamp" -DefaultColor DarkCyan Write-PSFHostColor -String "They wished the path was easier" -DefaultColor DarkYellow Write-PSFHostColor -String "If only someone had written it all down where it could be found.........." -DefaultColor DarkRed Write-PSFHostColor -String "5 - Export" -DefaultColor DarkMagenta Write-PSFHostColor -String "Narrator - The Tests are running" -DefaultColor Blue Assert-Correct -chapter Export Get-GameTimeRemaining } 7 { cls code /workspace/Demos/07-FindingThings.ps1 Write-PSFHostColor -String "Lost, said the wispy voices" -DefaultColor DarkCyan Write-PSFHostColor -String "and unless you can locate the right things" -DefaultColor DarkYellow Write-PSFHostColor -String "~~~~~~~ YOU SHALL BE LOST FOREVER ~~~~~~~" -DefaultColor DarkRed Write-PSFHostColor -String "7 - Finding Things" -DefaultColor DarkMagenta Write-PSFHostColor -String "Narrator - The Tests are running" -DefaultColor Blue Assert-Correct -chapter Found Get-GameTimeRemaining } 8 { cls code /workspace/Demos/08-DataMasking.ps1 Write-PSFHostColor -String "They could hear them rushing towards them" -DefaultColor DarkCyan Write-PSFHostColor -String "shouting and hollering in a dreadful manner" -DefaultColor DarkYellow Write-PSFHostColor -String "But what was on those faces? Are those ....... Masks?" -DefaultColor DarkRed Write-PSFHostColor -String "8 - Data Masking" -DefaultColor DarkMagenta Write-PSFHostColor -String "Narrator - The Tests are running" -DefaultColor Blue Assert-Correct -chapter Masking Get-GameTimeRemaining } 9 { cls code /workspace/Demos/09-Logins.ps1 Write-PSFHostColor -String "They saw a house in the distance and picked up speed" -DefaultColor DarkCyan Write-PSFHostColor -String "A massive wooden door faced them, they rang the bell" -DefaultColor DarkYellow Write-PSFHostColor -String "The monsters were close though ~~~ LET US IN" -DefaultColor DarkRed Write-PSFHostColor -String "PLEASE ~~~ LET US IN" -DefaultColor DarkRed Write-PSFHostColor -String "9 - Logins" -DefaultColor DarkMagenta Write-PSFHostColor -String "Narrator - The Tests are running" -DefaultColor Blue Assert-Correct -chapter Logins Get-GameTimeRemaining } #even though you choose M 10 { cls Write-Output "10 - Advanced Migrations" code /workspace/Demos/10-AdvancedMigrations.ps1 Write-PSFHostColor -String "Just running some tests a mo" -DefaultColor Green Assert-Correct -chapter AdvMigration Get-GameTimeRemaining Write-PSFHostColor -String "we also need an app to run in the background" -DefaultColor Green Write-PSFHostColor -String "In a new session run Invoke-PubsApplication" -DefaultColor Green } #even though you choose R 11 { cls Write-Output "11 - Registered Servers" code /workspace/Demos/11-RegisteredServers.ps1 Write-PSFHostColor -String "Just running some tests a mo" -DefaultColor Green # Assert-Correct -chapter RegisterdServers Get-GameTimeRemaining } #even though you choose C 12 { cls Write-Output "12 - Estate Validation" code /workspace/Demos/12-EstateValidation.ps1 Write-PSFHostColor -String "Just running some tests a mo" -DefaultColor Green # Assert-Correct -chapter RegisterdServers Get-GameTimeRemaining } # even though you choose G 14 { cls $Message = ' GREETINGS PROFESSOR FALKEN HELLO A STRANGE GAME. THE ONLY WINNING MOVE IS NOT TO PLAY. HOW ABOUT A NICE GAME OF CHESS? ' Write-Host $message -BackgroundColor 03fcf4 -ForegroundColor Black } # even though you choose T 13 { Start-TicTacToe } 'q' { cls } Default { cls Write-Output $wrongChoice Start-Sleep -Seconds 1 cls Start-Sleep -Milliseconds 250 Write-Output $OhNo2 $message = "You chose - {0}" -f $IndexChoice Write-Output $message } } } function Set-ConnectionInfo { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'Clear-Host', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'cls', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', 'cls', Justification = 'Dont tell me what to do')] [CmdletBinding()] param() #region Set up connection $securePassword = ('dbatools.IO' | ConvertTo-SecureString -AsPlainText -Force) $containercredential = New-Object System.Management.Automation.PSCredential('sqladmin', $securePassword) #$Global:PSDefaultParameterValues = @{ # "*dba*:SqlCredential" = $containercredential # "*dba*:SourceSqlCredential" = $containercredential # "*dba*:DestinationSqlCredential" = $containercredential # "*dba*:DestinationCredential" = $containercredential # "*dba*:PrimarySqlCredential" = $containercredential # "*dba*:SecondarySqlCredential" = $containercredential #} $containers = $SQLInstances = $dbachecks1, $dbachecks2, $dbachecks3 = 'dbachecks1', 'dbachecks2', 'dbachecks3' #endregion } Set-ConnectionInfo function Set-FailedTestMessage { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'Clear-Host', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'Out-GridView', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'cls', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', 'cls', Justification = 'Dont tell me what to do')] [CmdletBinding()] param() $FailedTests = ($results.FailedCount | Measure-Object -Sum).Sum if ($FailedTests -gt 0) { Write-PSFHostColor -String "NARRATOR - A thing went wrong" -DefaultColor DarkMagenta Write-PSFHostColor -String "NARRATOR - It MUST be fixed before we can continue" -DefaultColor DarkMagenta $Failures = $results.TestResult | Where-Object Result -EQ 'Failed' | Select-Object Describe, Context, Name, FailureMessage $Failures.ForEach{ $Message = '{0} at {1} in {2}' -f $_.FailureMessage, $_.Name, $_.Describe Write-PSFHostColor -String $Message -DefaultColor DarkCyan } } } function Assert-Correct { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'Clear-Host', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'cls', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', 'cls', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'results', Justification = 'Because it is a global variable used later')] [CmdletBinding()] param ( # Parameter help description [Parameter()] [ValidateSet( 'initial', 'Intro' , 'Backup', 'Copy', 'SnapShots', 'Export', 'Ags', 'Found', 'Masking', 'Logins', 'AdvMigration' )] [string] $chapter = 'initial' ) # $Global:PSDefaultParameterValues.CLear() switch ($chapter) { 'initial' { # Valid estate is as we expect $null = Reset-DbcConfig $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $true # so we dont get silly output from convert-dbcresult Set-DbcConfig -Name app.sqlinstance -Value $containers Set-DbcConfig -Name policy.connection.authscheme -Value 'SQL' Set-DbcConfig -Name skip.connection.remoting -Value $true Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection -Verbose Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks2' Invoke-DbcCheck -SqlCredential $containercredential -Check DatabaseExists Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks1' Set-DbcConfig -Name database.exists -Value 'pubs', 'NorthWind' -Append Invoke-DbcCheck -SqlCredential $containercredential -Check DatabaseExists $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $false # reset } 'Intro' { # Valid estate is as we expect $null = Reset-DbcConfig $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $true # so we dont get silly output from convert-dbcresult $null = Set-DbcConfig -Name app.sqlinstance -Value $containers $null = Set-DbcConfig -Name policy.connection.authscheme -Value 'SQL' $null = Set-DbcConfig -Name skip.connection.remoting -Value $true $check1 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection -Show Summary -PassThru $check1 | Convert-DbcResult -Label Intro -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation $null = Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks2' $check2 = Invoke-DbcCheck -SqlCredential $containercredential -Check DatabaseExists -Show Summary -PassThru $check2 | Convert-DbcResult -Label Intro -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation $null = Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks1' $null = Set-DbcConfig -Name database.exists -Value 'pubs', 'NorthWind' -Append $check3 = Invoke-DbcCheck -SqlCredential $containercredential -Check DatabaseExists -Show Summary -PassThru $check3 | Convert-DbcResult -Label Intro -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation $results = @($check1, $check2, $check3) Set-FailedTestMessage Write-PSFHostColor -String "Are you ready to begin your adventure?" -DefaultColor Blue $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $false # reset } 'Backup' { # Valid estate is as we expect $null = Reset-DbcConfig $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $true # so we dont get silly output from convert-dbcresult $null = Set-DbcConfig -Name app.checkrepos -Value '/workspace/Demos/dbachecksconfigs' -Append $null = Set-DbcConfig -Name app.sqlinstance -Value $containers $null = Set-DbcConfig -Name policy.connection.authscheme -Value 'SQL' $null = Set-DbcConfig -Name skip.connection.remoting -Value $true $null = Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks2' $check1 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection, DatabaseExists -Show Summary -PassThru $check1 | Convert-DbcResult -Label Backup -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation $null = Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks1' $null = Set-DbcConfig -Name database.exists -Value 'master', 'model', 'msdb', 'Northwind', 'pubs', 'tempdb' $check2 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection, DatabaseExists, NoDatabasesOn1, NoBackupFiles -Show Summary -PassThru $check2 | Convert-DbcResult -Label Backup -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation $results = @($check1, $check2) Set-FailedTestMessage Write-PSFHostColor -String "Should you create a save point before this chapter?" -DefaultColor Blue Start-Sleep -Seconds 5 Write-PSFHostColor -String "Or can you make it to the end?" -DefaultColor DarkRed $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $false # reset } 'Copy' { # Valid estate is as we expect $null = Reset-DbcConfig $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $true # so we dont get silly output from convert-dbcresult $null = Set-DbcConfig -Name app.checkrepos -Value '/workspace/Demos/dbachecksconfigs' -Append Set-DbcConfig -Name app.sqlinstance -Value $containers | Out-Null Set-DbcConfig -Name policy.connection.authscheme -Value 'SQL' | Out-Null Set-DbcConfig -Name skip.connection.remoting -Value $true | Out-Null Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks2' | Out-Null Set-DbcConfig -Name database.exists -Value 'master', 'model', 'msdb', 'tempdb' | Out-Null $check1 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection, DatabaseExists, NoDatabasesOn2, NeedNoLogins -Show Summary -PassThru $check1 | Convert-DbcResult -Label Copy -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks1' | Out-Null Set-DbcConfig -Name database.exists -Value 'master', 'model', 'msdb', 'Northwind', 'pubs', 'pubs-0', 'pubs-1', 'pubs-10', 'pubs-2', 'pubs-3', 'pubs-4', 'pubs-5', 'pubs-6', 'pubs-7', 'pubs-8', 'pubs-9', 'tempdb' | Out-Null $check2 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection, DatabaseExists -Show Summary -PassThru $check2 | Convert-DbcResult -Label Copy -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation $results = @($check1, $check2) Set-FailedTestMessage Write-PSFHostColor -String "If you get database missing failures - Chapter 2 will be your friend" -DefaultColor Magenta $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $false # reset } 'Snapshots' { # Valid estate is as we expect Write-PSFHostColor -String "Running the SnapShot Chapter checks" -DefaultColor Green $null = Reset-DbcConfig $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $true # so we dont get silly output from convert-dbcresult Set-DbcConfig -Name app.checkrepos -Value '/workspace/Demos/dbachecksconfigs' -Append | Out-Null Set-DbcConfig -Name app.sqlinstance -Value $containers | Out-Null Set-DbcConfig -Name policy.connection.authscheme -Value 'SQL' | Out-Null Set-DbcConfig -Name skip.connection.remoting -Value $true | Out-Null Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks2' | Out-Null Set-DbcConfig -Name database.exists -Value 'master', 'model', 'msdb', 'tempdb' | Out-Null $check1 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection, DatabaseExists, NoDatabasesOn2, DatabaseStatus, NoSnapshots -Show Summary -PassThru $check1 | Convert-DbcResult -Label SnapShots -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks1' | Out-Null Set-DbcConfig -Name database.exists -Value 'master', 'model', 'msdb', 'Northwind', 'pubs', 'tempdb' | Out-Null $check2 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection, DatabaseExists, DatabaseStatus -Show Summary -PassThru $check1 | Convert-DbcResult -Label SnapShots -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation $results = @($check1, $check2) Set-FailedTestMessage $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $false # reset } 'Export' { # Valid estate is as we expect $null = Reset-DbcConfig $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $true # so we dont get silly output from convert-dbcresult $null = Set-DbcConfig -Name app.sqlinstance -Value $containers $null = Set-DbcConfig -Name policy.connection.authscheme -Value 'SQL' $null = Set-DbcConfig -Name skip.connection.remoting -Value $true $check1 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection -Show Summary -PassThru $check1 | Convert-DbcResult -Label Export -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation $null = Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks2' $check2 = Invoke-DbcCheck -SqlCredential $containercredential -Check DatabaseExists -Show Summary -PassThru $check2 | Convert-DbcResult -Label Export -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation $null = Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks1' $null = Set-DbcConfig -Name database.exists -Value 'pubs', 'NorthWind' -Append $check3 = Invoke-DbcCheck -SqlCredential $containercredential -Check DatabaseExists -Show Summary -PassThru $check3 | Convert-DbcResult -Label Export -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation $results = @($check1, $check2, $check3) Set-FailedTestMessage $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $false } 'Ags' { # Valid estate is as we expect $null = Reset-DbcConfig $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $true # so we dont get silly output from convert-dbcresult $null = Set-DbcConfig -Name app.checkrepos -Value '/workspace/Demos/dbachecksconfigs' -Append | Out-Null $null = Set-DbcConfig -Name app.sqlinstance -Value $containers $null = Set-DbcConfig -Name policy.connection.authscheme -Value 'SQL' $null = Set-DbcConfig -Name skip.connection.remoting -Value $true $check1 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection -Show Summary -PassThru $check1 | Convert-DbcResult -Label AvailabilityGroups -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks2' | Out-Null Set-DbcConfig -Name database.exists -Value 'master', 'model', 'msdb', 'tempdb' | Out-Null $check2 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection, DatabaseExists, NoDatabasesOn2, DatabaseStatus, NoSnapshots, NoAgs -Show Summary -PassThru $check2 | Convert-DbcResult -Label AvailabilityGroups -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks1' | Out-Null Set-DbcConfig -Name database.exists -Value 'master', 'model', 'msdb', 'Northwind', 'pubs', 'pubs-0', 'pubs-1', 'pubs-10', 'pubs-2', 'pubs-3', 'pubs-4', 'pubs-5', 'pubs-6', 'pubs-7', 'pubs-8', 'pubs-9', 'tempdb' | Out-Null $check3 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection, DatabaseExists, DatabaseStatus -Show Summary -PassThru $check3 | Convert-DbcResult -Label AvailabilityGroups -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation $results = @($check1, $check2, $check3) Set-FailedTestMessage Write-PSFHostColor -String "If you get database missing failures - Chapter 2 will be your friend" -DefaultColor Magenta $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $false } 'AdvMigration' { # Valid estate is as we expect $null = Reset-DbcConfig $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $true # so we dont get silly output from convert-dbcresult Set-DbcConfig -Name app.checkrepos -Value '/workspace/Demos/dbachecksconfigs' -Append | Out-Null $null = Set-DbcConfig -Name app.sqlinstance -Value $containers $null = Set-DbcConfig -Name policy.connection.authscheme -Value 'SQL' $null = Set-DbcConfig -Name skip.connection.remoting -Value $true $check1 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection -Show Summary -PassThru $check1 | Convert-DbcResult -Label AdvancedMigration -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks2' | Out-Null Set-DbcConfig -Name database.exists -Value 'master', 'model', 'msdb', 'tempdb' | Out-Null $check2 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection, DatabaseExists, NoDatabasesOn2, DatabaseStatus, NoSnapshots, NoAgs -Show Summary -PassThru $check2 | Convert-DbcResult -Label AdvancedMigration -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks1' | Out-Null Set-DbcConfig -Name database.exists -Value 'master', 'model', 'msdb', 'Northwind', 'pubs', 'tempdb' | Out-Null $check3 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection, DatabaseExists, DatabaseStatus -Show Summary -PassThru $check3 | Convert-DbcResult -Label AdvancedMigration -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation $results = @($check1, $check2, $check3) Set-FailedTestMessage $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $false } 'Found' { # Valid estate is as we expect $null = Reset-DbcConfig $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $true # so we dont get silly output from convert-dbcresult Set-DbcConfig -Name app.checkrepos -Value '/workspace/Demos/dbachecksconfigs' -Append | Out-Null $null = Set-DbcConfig -Name app.sqlinstance -Value $containers $null = Set-DbcConfig -Name policy.connection.authscheme -Value 'SQL' $null = Set-DbcConfig -Name skip.connection.remoting -Value $true $check1 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection -Show Summary -PassThru $check1 | Convert-DbcResult -Label Found -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks2' | Out-Null Set-DbcConfig -Name database.exists -Value 'master', 'model', 'msdb', 'tempdb' | Out-Null $check2 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection, DatabaseExists, NeedJobs, NeedFailedJobs -Show Summary -PassThru $check2 | Convert-DbcResult -Label Found -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks1' | Out-Null Set-DbcConfig -Name database.exists -Value 'master', 'model', 'msdb', 'Northwind', 'pubs', 'tempdb' | Out-Null $check3 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection, DatabaseExists, DatabaseStatus, NeedSps, NeedUDfs, NeedTriggers, NeedLogins -Show Summary -PassThru $check3 | Convert-DbcResult -Label Found -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation $results = @($check1, $check2, $check3) Set-FailedTestMessage $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $false } 'Masking' { # Valid estate is as we expect $null = Reset-DbcConfig $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $true # so we dont get silly output from convert-dbcresult Set-DbcConfig -Name app.checkrepos -Value '/workspace/Demos/dbachecksconfigs' -Append | Out-Null $null = Set-DbcConfig -Name app.sqlinstance -Value $containers $null = Set-DbcConfig -Name policy.connection.authscheme -Value 'SQL' $null = Set-DbcConfig -Name skip.connection.remoting -Value $true $check1 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection -Show Summary -PassThru $check1 | Convert-DbcResult -Label Masking -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks2' | Out-Null Set-DbcConfig -Name database.exists -Value 'master', 'model', 'msdb', 'tempdb' | Out-Null $check2 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection, DatabaseExists -Show Summary -PassThru $check2 | Convert-DbcResult -Label Masking -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks1' | Out-Null Set-DbcConfig -Name database.exists -Value 'master', 'model', 'msdb', 'Northwind', 'pubs', 'tempdb' | Out-Null $check3 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection, DatabaseExists, DatabaseStatus -Show Summary -PassThru $check3 | Convert-DbcResult -Label Masking -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation $results = @($check1, $check2, $check3) Set-FailedTestMessage $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $false } 'Logins' { # Valid estate is as we expect $null = Reset-DbcConfig $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $true # so we dont get silly output from convert-dbcresult Set-DbcConfig -Name app.checkrepos -Value '/workspace/Demos/dbachecksconfigs' -Append | Out-Null $null = Set-DbcConfig -Name app.sqlinstance -Value $containers $null = Set-DbcConfig -Name policy.connection.authscheme -Value 'SQL' $null = Set-DbcConfig -Name skip.connection.remoting -Value $true $check1 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection -Show Summary -PassThru $check1 | Convert-DbcResult -Label Logins -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks2' | Out-Null Set-DbcConfig -Name database.exists -Value 'master', 'model', 'msdb', 'tempdb' | Out-Null $check2 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection, DatabaseExists -Show Summary -PassThru $check2 | Convert-DbcResult -Label Logins -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation Set-DbcConfig -Name app.sqlinstance -Value 'dbachecks1' | Out-Null Set-DbcConfig -Name database.exists -Value 'master', 'model', 'msdb', 'Northwind', 'pubs', 'tempdb' | Out-Null $check3 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection, DatabaseExists, DatabaseStatus -Show Summary -PassThru $check3 | Convert-DbcResult -Label Logins -warningaction SilentlyContinue | Write-DbcTable -SqlInstance $dbachecks1 -SqlCredential $containercredential -Database Validation $results = @($check1, $check2, $check3) Set-FailedTestMessage $null = Set-PSFConfig -FullName PSFramework.Message.ConsoleOutput.Disable -Value $false } Default { # Valid estate is as we expect $null = Reset-DbcConfig $null = Import-DbcConfig /workspace/Demos/dbachecksconfigs/initial-config.json $check3 = Invoke-DbcCheck -SqlCredential $containercredential -Check InstanceConnection -Show Summary -PassThru $null = Reset-DbcConfig $null = Import-DbcConfig /workspace/Demos/dbachecksconfigs/initial-dbachecks1-config.json $check2 = Invoke-DbcCheck -SqlCredential $containercredential -Check DatabaseExists -Show Summary -PassThru $null = Reset-DbcConfig $null = Import-DbcConfig /workspace/Demos/dbachecksconfigs/initial-dbachecks2-config.json $check1 = Invoke-DbcCheck -SqlCredential $containercredential -Check DatabaseExists -Show Summary -PassThru $results = @($check1, $check2, $check3) Set-FailedTestMessage } } #$Global:PSDefaultParameterValues = @{ # "*dba*:SqlCredential" = $containercredential # "*dba*:SourceSqlCredential" = $containercredential # "*dba*:DestinationSqlCredential" = $containercredential # "*dba*:DestinationCredential" = $containercredential # "*dba*:PrimarySqlCredential" = $containercredential # "*dba*:SecondarySqlCredential" = $containercredential #} } Function Compare-SPConfig { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'Clear-Host', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'Out-GridView', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'cls', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', 'cls', Justification = 'Dont tell me what to do')] [CmdletBinding()] Param( $Source, $Destination ) $SourceSpConfigure = Get-DbaSpConfigure -SqlInstance $Source -SqlCredential $containercredential $DestSPConfigure = Get-DbaSpConfigure -SqlInstance $Destination -SqlCredential $containercredential $propcompare = foreach ($prop in $SourceSpConfigure) { [pscustomobject]@{ Config = $prop.DisplayName 'Source setting' = $prop.RunningValue 'Destination Setting' = $DestSPConfigure | Where-Object DisplayName -EQ $prop.DisplayName | Select-Object -ExpandProperty RunningValue } } if ($IsCoreCLR) { $propcompare | Out-ConsoleGridView -Title "Comparing Sp_configure Settings Source - $Source With Destination $Destination" } else { $propcompare | Out-GridView -Title "Comparing Sp_configure Settings Source - $SourceWith Destination $Destination" } } function Invoke-PubsApplication { # This will randomly insert rows into the pubs.dbo.sales table on dbachecks1 to simulate sales activity # It'll run until you kill it # app connection $securePassword = ('PubsAdmin' | ConvertTo-SecureString -AsPlainText -Force) $appCred = New-Object System.Management.Automation.PSCredential('PubsAdmin', $securePassword) $appConnection = Connect-DbaInstance -SqlInstance $dbachecks1 -SqlCredential $appCred -ClientName 'PubsApplication' while ($true) { Write-PSFHostColor -String "Pubs application is running...forever... Ctrl+C to get out of here" -DefaultColor Green $newOrder = [PSCustomObject]@{ stor_id = Get-Random (Invoke-DbaQuery -SqlInstance $appConnection -Database pubs -Query 'select stor_id from stores').stor_id ord_num = Get-DbaRandomizedValue -DataType int -Min 1000 -Max 99999 ord_date = Get-Date qty = Get-Random -Minimum 1 -Maximum 30 payterms = Get-Random (Invoke-DbaQuery -SqlInstance $appConnection -Database pubs -Query 'select distinct payterms from pubs.dbo.sales').payterms title_id = Get-Random (Invoke-DbaQuery -SqlInstance $appConnection -Database pubs -Query 'select title_id from titles').title_id } Write-DbaDataTable -SqlInstance $appConnection -Database pubs -InputObject $newOrder -Table sales Start-Sleep -Seconds (Get-Random -Maximum 10) } } function Get-GameTimeRemaining { $StartDate = Get-Date -Hour 9 -Minute 00 -Second 0 $Date = Get-Date $Diff = $Date - $StartDate $MorningBreak = Get-Date -Hour 10 -Minute 30 -Second 0 $Lunch = Get-Date -Hour 12 -Minute 30 -Second 0 $AfternoonBreak = Get-Date -Hour 15 -Minute 00 -Second 0 $TheEnd = Get-Date -Hour 17 -Minute 00 -Second 0 switch ($Date) { { $Date -lt $TheEnd } { $Remaining = $TheEnd - $Date $Reason = 'THE END' } { $Date -lt $AfternoonBreak } { $Remaining = $AfternoonBreak - $Date $Reason = 'AFTERNOON BREAK' } { $Date -lt $Lunch } { $Remaining = $Lunch - $Date $Reason = 'LUNCH BREAK' } { $Date -lt $MorningBreak } { $Remaining = $MorningBreak - $Date $Reason = 'MORNING BREAK' } Default {} } $message = ' _______________________ _______________________ | GAME TIME ELAPSED | | GAME TIME REMAINING | | {0} HRS | | {3} HRS | | {1} MINS {2} SECS | | {4} MINS {5} SECS | | | | UNTIL {6} |______________________| |______________________| ' -f $Diff.Hours , ("{0:D2}" -f $diff.Minutes) , ("{0:D2}" -f $diff.Seconds), $Remaining.Hours , ("{0:D2}" -f $Remaining.Minutes) , ("{0:D2}" -f $Remaining.Seconds), $Reason Write-Host $message -BackgroundColor 03fcf4 -ForegroundColor Black } Function TicTacToe { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'Clear-Host', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'Out-GridView', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'cls', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', 'cls', Justification = 'Dont tell me what to do')] [CmdletBinding()] Param( $Sleep ) $message = ' | | | | | | | | | | ------------------------------ | | | | | | | | | | ------------------------------ | | | | | | | | | | ' Clear-Host Write-Host $message Start-Sleep -Milliseconds $Sleep $message = ' | | | | | | | | | | ------------------------------ | | | X X | | X | | X X | | | ------------------------------ | | | | | | | | | | ' Clear-Host Write-Host $message Start-Sleep -Milliseconds $Sleep $message = ' | | O | | O O | | O | | | | ------------------------------ | | | X X | | X | | X X | | | ------------------------------ | | | | | | | | | | ' Clear-Host Write-Host $message Start-Sleep -Milliseconds $Sleep $message = ' | | O | | O O | | O | | | | ------------------------------ | | | X X | | X | | X X | | | ------------------------------ | | | X X | | X | | X X | | | ' Clear-Host Write-Host $message Start-Sleep -Milliseconds $Sleep $message = ' | | O | O | O O | O O | O | O | | | ------------------------------ | | | X X | | X | | X X | | | ------------------------------ | | | X X | | X | | X X | | | ' Clear-Host Write-Host $message Start-Sleep -Milliseconds $Sleep $message = ' | | O | O | X X O O | O O | X O | O | X X | | ------------------------------ | | | X X | | X | | X X | | | ------------------------------ | | | X X | | X | | X X | | | ' Clear-Host Write-Host $message Start-Sleep -Milliseconds $Sleep $message = ' | | O | O | X X O O | O O | X O | O | X X | | ------------------------------ | | | X X | | X | | X X | | | ------------------------------ | | O | X X | O O | X | O | X X | | | ' Clear-Host Write-Host $message Start-Sleep -Milliseconds $Sleep $message = ' | | O | O | X X O O | O O | X O | O | X X | | ------------------------------ | | X X | X X | X | X | X X | X X | | | ------------------------------ | | O | X X | O O | X | O | X X | | | ' Clear-Host Write-Host $message Start-Sleep -Milliseconds $Sleep $message = ' | | O | O | X X O O | O O | X O | O | X X | | ------------------------------ | | X X | X X | O X | X | O O X X | X X | O | | ------------------------------ | | O | X X | O O | X | O | X X | | | ' Clear-Host Write-Host $message Start-Sleep -Milliseconds $Sleep $message = ' | | O | O | X X O O | O O | X O | O | X X | | ------------------------------ | | X X | X X | O X | X | O O X X | X X | O | | ------------------------------ | | O | X X | X X O O | X | X O | X X | X X | | ' Clear-Host Write-Host $message Start-Sleep -Milliseconds $Sleep } function Start-TicTacToe { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'Clear-Host', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'Out-GridView', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'cls', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', 'cls', Justification = 'Dont tell me what to do')] [CmdletBinding()] param() $Options = 500, 200, 200, 100, 100, 100, 50, 50, 50, 50, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 $Options | ForEach-Object { TicTacToe -Sleep $_ } Clear-Host $Message = ' GREETINGS PROFESSOR FALKEN HELLO A STRANGE GAME. THE ONLY WINNING MOVE IS NOT TO PLAY. HOW ABOUT A NICE GAME OF CHESS? ' Write-Host $message -BackgroundColor 03fcf4 -ForegroundColor Black } function pacman { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'Clear-Host', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'Out-GridView', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'cls', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', 'cls', Justification = 'Dont tell me what to do')] [CmdletBinding()] param() Clear-Host $sleep = 15 $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. . | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' ' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .- | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '- '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .- | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '- '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .- | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '- '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. . | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' ' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. .- | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '- '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. . | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' ' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. .- | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '- '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. . | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' ' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. .- | | \ '-. '-' '-' '-' '-' '-' '-' '-' '- '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. . | | \ '-. '-' '-' '-' '-' '-' '-' '-' ' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. .- | | \ '-. '-' '-' '-' '-' '-' '-' '- '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. . | | \ '-. '-' '-' '-' '-' '-' '-' ' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. .- | | \ '-. '-' '-' '-' '-' '-' '- '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. . | | \ '-. '-' '-' '-' '-' '-' ' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. .- | | \ '-. '-' '-' '-' '-' '- '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. . | | \ '-. '-' '-' '-' '-' ' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .-. | | \ '-. '-' '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. .- | | \ '-. '-' '-' '-' '- '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. . | | \ '-. '-' '-' '-' ' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. | | \ '-. '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. | | \ '-. '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. | | \ '-. '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .-. | | \ '-. '-' '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. .- | | \ '-. '-' '-' '- '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. . | | \ '-. '-' '-' ' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. | | \ '-. '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. | | \ '-. '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. | | \ '-. '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .-. | | \ '-. '-' '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. .- | | \ '-. '-' '- '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. . | | \ '-. '-' ' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. | | \ '-. '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. | | \ '-. '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. | | \ '-. '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .-. | | \ '-. '-' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' .- | | \ '-. '- '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' . | | \ '-. ' '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' | | \ '-. '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .--. | OO| / _.-' | | \ '-. '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .-- | OO| / _.- | | \ '- '^^^' '--' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. .- | OO| / _. | | \ ' '^^^' '-- " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. . | OO| / _ | | \ '^^^' '- " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. | OO| / | | \ '^^^' ' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. | OO| / | | \ '^^^' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. | OO| | | '^^^' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. | OO| | | '^^^' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. | OO| | | '^^^' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. | OO| | | '^^^' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .-. | OO | '^^^ " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " .- | O | '^^ " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " . | | '^ " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " | | ' " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host $pac = " " Write-Host $pac -ForegroundColor Yellow Start-Sleep -Milliseconds $sleep Clear-Host } New-Alias -Name cls -Value pacman -Force function Invoke-PerfAndValidateCheck { <# .SYNOPSIS Function to help test that the v5 and v4 tests are doing the same thing & get the performance stats .DESCRIPTION Function to help test that the v5 and v4 tests are doing the same thing & get the performance stats .PARAMETER Checks Which checks shall we test .PARAMETER PerfDetails Shall we show the performance output from profiler .PARAMETER SQLInstances Which SQL Instances shall we test. Defaults ($dbachecks1, $dbachecks2, $dbachecks3 = 'dbachecks1', 'dbachecks2', 'dbachecks3') .EXAMPLE Invoke-PerfAndValidateCheck -Check InvalidDatabaseOwner Check validity and performance for InvalidDatabaseOwner test .EXAMPLE Invoke-PerfAndValidateCheck -Check ValidDatabaseOwner, InvalidDatabaseOwner Check validity and performance for both the ValidDatabaseOwner and InvalidDatabaseOwner tests .EXAMPLE Invoke-PerfAndValidateCheck -Check ValidDatabaseOwner, InvalidDatabaseOwner -PerfDetails Check validity and performance for both the ValidDatabaseOwner and InvalidDatabaseOwner tests and show the top 50 slowest lines .EXAMPLE Invoke-PerfAndValidateCheck -SqlInstances 'localhost,7401' -Check ValidDatabaseOwner, InvalidDatabaseOwner Check validity and performance for both the ValidDatabaseOwner and InvalidDatabaseOwner tests aganinst one container. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'Clear-Host', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'Out-GridView', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', 'cls', Justification = 'Dont tell me what to do')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', 'cls', Justification = 'Dont tell me what to do')] [CmdletBinding()] param( $Checks, [switch]$PerfDetail, [switch]$showTestResults, $SQLInstances = ($dbachecks1, $dbachecks2, $dbachecks3 = 'dbachecks1', 'dbachecks2', 'dbachecks3') ) $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password if ($showTestResults) { $show = 'All' } else { $show = 'None' } $originalCode = { $global:v4code = Invoke-DbcCheck -SqlInstance $Sqlinstances -Check $Checks -SqlCredential $cred -legacy $true -Show $show -PassThru } $NewCode = { $global:v5code = Invoke-DbcCheck -SqlInstance $Sqlinstances -Check $Checks -SqlCredential $cred -legacy $false -Show $show -PassThru } $originalCodetrace = Trace-Script -ScriptBlock $originalCode Remove-Module Pester Import-Module Pester -MinimumVersion 5.0.0 -Global $NewCodetrace = Trace-Script -ScriptBlock $NewCode $originalCodeMessage = "With original Code it takes {0} MilliSeconds" -f $originalCodetrace.StopwatchDuration.TotalMilliseconds $savingMessage = " Running with {3} Checks against $($Sqlinstances.Count) SQL Containers With original Code it takes {1} Seconds With New Code it takes {4} Seconds New Code for these {5} checks is saving {0} seconds from a run of {1} seconds New Code runs in {2} % of the time " -f ('{0:N2}' -f ($originalCodetrace.StopwatchDuration.TotalSeconds - $NewCodetrace.StopwatchDuration.TotalSeconds)), ('{0:N2}' -f $originalCodetrace.StopwatchDuration.TotalSeconds), ('{0:N2}' -f (($NewCodetrace.StopwatchDuration.TotalSeconds / $originalCodetrace.StopwatchDuration.TotalSeconds) * 100)), ($Checks -split ',' -join ',') , ('{0:N2}' -f $NewCodetrace.StopwatchDuration.TotalSeconds), $Checks.Count Write-PSFMessage -Message $savingMessage -Level Output ##validate we got the right answers too [System.Collections.ArrayList]$v5CodeTags = $v5code.Configuration.Filter.Tag.Value $v5CodeTags.Remove('FailedConnections') If (Compare-Object $v5CodeTags $v4code.TagFilter) { $Message = " Uh-Oh - The Tag filters between v4 and v5 are not the same somehow. For v4 We returned {0} and for v4 we returned {1} " -f ($v4code.TagFilter | Out-String), ($v5code.Configuration.Filter.Tag.Value | Out-String) Write-PSFMessage -Message $Message -Level Warning } else { $message = " The Tags are the same" Write-PSFMessage -Message $Message -Level Output } $changedTags = @( @{ Name = 'TraceFlagsExpected' RunChange = 3 # + or - the number of tests run for v4 PassedChange = 3 # + or - the number of tests passed for v4 FailedChange = 0 # + or - the number of tests failed for v4 SkippedChange = 0 # + or - the number of tests skipped for v4 }, @{ Name = 'TraceFlagsNotExpected' RunChange = 3 # + or - the number of tests for v4 PassedChange = 3 # + or - the number of tests passed for v4 FailedChange = 0 # + or - the number of tests failed for v4 SkippedChange = 0 # + or - the number of tests skipped for v4 }, @{ Name = 'XESessionRunningAllowed' RunChange = -12 # + or - the number of tests for v4 PassedChange = 0 # + or - the number of tests passed for v4 FailedChange = -12 # + or - the number of tests failed for v4 SkippedChange = 0 # + or - the number of tests skipped for v4 }, @{ Name = 'LinkedServerConnection' RunChange = -3 # + or - the number of tests for v4 PassedChange = -3 # + or - the number of tests passed for v4 FailedChange = 0 # + or - the number of tests failed for v4 SkippedChange = 0 # + or - the number of tests skipped for v4 }, @{ Name = 'SupportedBuild' RunChange = -3 # + or - the number of tests run for v4 PassedChange = -3 # + or - the number of tests passed for v4 FailedChange = 0 # + or - the number of tests failed for v4 SkippedChange = 0 # + or - the number of tests skipped for v4 }, @{ Name = 'GuestUserConnect' RunChange = 0 # + or - the number of tests run for v4 PassedChange = +2 # + or - the number of tests passed for v4 FailedChange = -2 # + or - the number of tests failed for v4 SkippedChange = 0 # + or - the number of tests skipped for v4 }, @{ Name = 'AgentServiceAccount' RunChange = -3 # + or - the number of tests run for v4 PassedChange = -5 # + or - the number of tests passed for v4 FailedChange = -1 # + or - the number of tests failed for v4 SkippedChange = +3 # + or - the number of tests skipped for v4 }, @{ Name = 'SqlEngineServiceAccount' RunChange = -3 # + or - the number of tests run for v5 PassedChange = 0 # + or - the number of tests passed for v5 FailedChange = 0 # + or - the number of tests failed for v5 SkippedChange = -3 # + or - the number of tests skipped for v5 } ) $runchange = 0 $passedchange = 0 $failedchange = 0 $skippedchange = 0 $tagNameMessageAppend = $null foreach ($changedTag in $changedTags) { if ($v5code.Configuration.Filter.Tag.Value -contains $changedTag.Name) { $runchange += $changedTag.RunChange $passedchange += $changedTag.PassedChange $failedchange += $changedTag.FailedChange $skippedchange += $changedTag.SkippedChange $tagNameMessageAppend += "tag {0} with: - run change {1} - passed change {2} - failed change {3} - skipped change {4} " -f $changedTag.Name, $changedTag.RunChange, $changedTag.PassedChange, $changedTag.FailedChange, $changedTag.SkippedChange } } $messageAppend = if ($tagNameMessageAppend) { "although this includes {0}" -f $tagNameMessageAppend } else { '' } $v5run = $v5code.TotalCount - $v5code.NotRunCount + $runchange $v5Passed = $v5code.PassedCount + $passedchange $v5failed = $v5code.FailedCount + $failedchange $v5skipped = $v5code.SkippedCount + $skippedchange #total checks If ($v5run -ne $v4code.TotalCount) { $Message = " Uh-Oh - The total tests run between v4 and v5 are not the same somehow. For v4 We ran {0} tests and for v5 we ran {1} tests The MOST COMMON REASON IS you have used Tags instead of Tag in your Describe block {2} " -f $v4code.TotalCount, $v5run, $messageAppend Write-PSFMessage -Message $Message -Level Warning } else { $message = " The Total Tests Run are the same {0} {1} {2}" -f $v4code.TotalCount, $v5run, $messageAppend Write-PSFMessage -Message $Message -Level Output } #total passed checks If ($v5Passed -ne $v4code.PassedCount) { $Message = " Uh-Oh - The total tests Passed between v4 and v5 are not the same somehow. For v4 We Passed {0} tests and for v5 we Passed {1} tests {2} " -f $v4code.PassedCount, $v5Passed, $messageAppend if($MessageAppend){ $Message += " v4 TestNames {0} v5 TestNames {1} " -f ($v4code.TestResult.Where{$_.Result -eq 'Passed'}.Name |Out-String),($v5code.Passed.ExpandedName |Out-String) } Write-PSFMessage -Message $Message -Level Warning } else { $message = " The Total Tests Passed are the same {0} {1} {2}" -f $v4code.PassedCount, $v5Passed, $messageAppend Write-PSFMessage -Message $Message -Level Output } # total failed If ($v5failed -ne $v4code.FailedCount) { $Message = " Uh-Oh - The total tests Failed between v4 and v5 are not the same somehow. For v4 We Failed {0} tests and for v5 we Failed {1} tests " -f $v4code.FailedCount, $v5Failed, $messageAppend if($MessageAppend){ $Message += " v4 TestNames {0} v5 TestNames {1} " -f ($v4code.TestResult.Where{$_.Result -eq 'Failed'}.Name |Out-String),($v5code.Failed.ExpandedName |Out-String) } Write-PSFMessage -Message $Message -Level Warning } else { $message = " The Total Tests Failed are the same {0} {1} {2}" -f $v4code.FailedCount, $v5failed, $messageAppend Write-PSFMessage -Message $Message -Level Output } If ($v5skipped -ne $v4code.SkippedCount) { $Message = " Uh-Oh - The total tests Skipped between v4 and v5 are not the same somehow. For v4 We Skipped {0} tests and For v5 we Skipped {1} " -f $v4code.SkippedCount, $v5Skipped, $messageAppend if($MessageAppend){ $Message += " v4 TestNames {0} v5 TestNames {1} " -f ($v4code.TestResult.Where{$_.Result -eq 'Skipped'}.Name |Out-String),($v5code.Skipped.ExpandedName |Out-String) } Write-PSFMessage -Message $Message -Level Warning } else { $message = " The Total Tests Skipped are the same {0} {1} {2}"-f $v4code.SkippedCount, $v5skipped, $messageAppend Write-PSFMessage -Message $Message -Level Output } if ($PerfDetail) { $message = " Let's take a look at the slowest code as well " Write-PSFMessage -Message $Message -Level Output $NewCodetrace.Top50SelfDuration| Select SelfPercent,HitCount,Line,Function, Text } } Set-PSFConfig -Module JessAndBeard -Name shallweplayagame -Value $true -Initialize -Description "Whether to ask or not" -ModuleExport ================================================ FILE: containers/base/dockerfile ================================================ FROM dbachecks/sqlinstance1 USER root # remove old dbatools directory so 2.0 will import RUN rm -rf /usr/local/share/powershell/Modules/dbatools/1.1.145 # Copy Profile ADD profile.ps1 /root/.config/powershell/ # Install PowerShell latest please RUN apt-get update && apt install -y powershell ================================================ FILE: containers/base/profile.ps1 ================================================ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '', Justification = 'Because this is just for testing and developing')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'Because this is for the prompt and it is required')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'containers', Justification = 'Because it is a global variable used later')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'SQLInstances', Justification = 'Because it is a global variable used later')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'currentAccountName', Justification = 'Because silly script analyuser cant see it is used')] [CmdletBinding()] param() # Set these defaults for all future sessions on this machine Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -Register Set-DbatoolsConfig -FullName sql.connection.encrypt -Value $false -Register if (Test-Path /workspace/containers -ErrorAction SilentlyContinue) { Import-Module /workspace/containers/JessAndBeard.psm1 } else { Import-Module /workspaces/dbachecks/containers/JessAndBeard.psm1 } Remove-Item '/var/opt/backups/dbachecks1' -Recurse -Force -ErrorAction SilentlyContinue Remove-Item '/shared' -Recurse -Force -ErrorAction SilentlyContinue function Load-Profile { Import-Module posh-git # Import-Module oh-my-posh # Set-PoshPrompt -Theme atomic $env:POSH_THEMES_PATH = '~/.poshthemes' function global:Set-PoshPrompt { param( $theme ) & oh-my-posh init pwsh --config "$env:POSH_THEMES_PATH\$theme.omp.json" | Invoke-Expression } # Create scriptblock that collects information and name it Register-PSFTeppScriptblock -Name "poshthemes" -ScriptBlock { Get-ChildItem $env:POSH_THEMES_PATH | Select-Object -ExpandProperty Name -Unique | ForEach-Object { $_ -replace '\.omp\.json$', '' } } #Assign scriptblock to function Register-PSFTeppArgumentCompleter -Command Set-PoshPrompt -Parameter theme -Name poshthemes $themes = @( 'neko', 'sonicboom_dark', 'neko', 'easy-term', 'if_tea', 'neko', 'kushal' 'nigfht-owl', 'neko', 'powerlevel10k_rainbow', 'quick-term', 'neko', 'stelbent.minimal', 'tokyo', 'neko', 'unicorn', 'wholespace', 'sonicboom_dark', 'lambdageneration' ) $global:__currentTheme = (Get-Random -InputObject $themes) function global:Get-CurrentPoshTheme { $__currentTheme } # Set-PoshPrompt -Theme $__currentTheme Set-PoshPrompt -Theme 'chips' if ($psstyle) { $psstyle.FileInfo.Directory = $psstyle.FileInfo.Executable = $psstyle.FileInfo.SymbolicLink = "" $PSStyle.FileInfo.Extension.Clear() $PSStyle.Formatting.TableHeader = "" $PsStyle.Formatting.FormatAccent = "" } } "Load-Profile for full profile" function prompt { #Load-Profile "PS > " } function whatsmyip { [CmdletBinding()] param ( [Parameter()] [switch] $clip ) if ($clip) { (Invoke-WebRequest -Uri 'http://ifconfig.me/ip').Content | Set-Clipboard } else { (Invoke-WebRequest -Uri 'http://ifconfig.me/ip').Content } } function whatsmyip { [CmdletBinding()] param ( [Parameter()] [switch] $clip ) if ($clip) { (Invoke-WebRequest -Uri 'http://ifconfig.me/ip').Content | Set-Clipboard } else { (Invoke-WebRequest -Uri 'http://ifconfig.me/ip').Content } } ================================================ FILE: containers/second/dockerfile ================================================ FROM dbachecks/sqlinstance2 USER root # Install PowerShell RUN apt-get update && apt install -y powershell # install git RUN apt install -y git # some cleanup RUN apt-get autoremove -y \ && apt-get clean -y ================================================ FILE: containers/third/dockerfile ================================================ FROM dbachecks/sqlinstance3 USER root # Install PowerShell RUN apt-get update && apt install -y powershell # install git RUN apt install -y git # some cleanup RUN apt-get autoremove -y \ && apt-get clean -y ================================================ FILE: dbachecksdevcontainer.code-workspace ================================================ { "folders": [ { "path": "." } ], "settings": { "powershell.scriptAnalysis.settingsPath": "PSScriptAnalyzerSettings.psd1", "mssql.connections": [ { "server": "dbachecks1", "database": "Northwind", "authenticationType": "SqlLogin", "user": "sqladmin", "password": "dbatools.IO", "emptyPasswordInput": false, "savePassword": true, "profileName": "dbachecks1-Northwind", "connectTimeout": 15, "encrypt": false, "applicationName": "vscode-mssql" }, { "server": "dbachecks1", "database": "pubs", "authenticationType": "SqlLogin", "user": "sqladmin", "password": "dbatools.IO", "emptyPasswordInput": false, "savePassword": true, "profileName": "dbachecks1-pubs", "connectTimeout": 15, "encrypt": false, "applicationName": "vscode-mssql" }, { "server": "dbachecks1", "database": "master", "authenticationType": "SqlLogin", "user": "sqladmin", "password": "dbatools.IO", "emptyPasswordInput": false, "savePassword": true, "profileName": "dbachecks1-master", "connectTimeout": 15, "encrypt": false, "applicationName": "vscode-mssql" }, { "server": "dbachecks1", "database": "msdb", "authenticationType": "SqlLogin", "user": "sqladmin", "password": "dbatools.IO", "emptyPasswordInput": false, "savePassword": true, "profileName": "dbachecks1-msdb", "connectTimeout": 15, "encrypt": false, "applicationName": "vscode-mssql" }, { "server": "dbachecks2", "database": "master", "authenticationType": "SqlLogin", "user": "sqladmin", "password": "dbatools.IO", "emptyPasswordInput": false, "savePassword": true, "profileName": "dbachecks2-master", "connectTimeout": 15, "encrypt": false, "applicationName": "vscode-mssql" }, { "server": "dbachecks2", "database": "msdb", "authenticationType": "SqlLogin", "user": "sqladmin", "password": "dbatools.IO", "emptyPasswordInput": false, "savePassword": true, "profileName": "dbachecks2-msdb", "connectTimeout": 15, "encrypt": false, "applicationName": "vscode-mssql" }, { "server": "dbachecks3", "database": "Northwind", "authenticationType": "SqlLogin", "user": "sqladmin", "password": "dbatools.IO", "emptyPasswordInput": false, "savePassword": true, "profileName": "dbachecks3-Northwind", "connectTimeout": 15, "encrypt": false, "applicationName": "vscode-mssql" }, { "server": "dbachecks3", "database": "pubs", "authenticationType": "SqlLogin", "user": "sqladmin", "password": "dbatools.IO", "emptyPasswordInput": false, "savePassword": true, "profileName": "dbachecks3-pubs", "connectTimeout": 15, "encrypt": false, "applicationName": "vscode-mssql" }, { "server": "dbachecks3", "database": "master", "authenticationType": "SqlLogin", "user": "sqladmin", "password": "dbatools.IO", "emptyPasswordInput": false, "savePassword": true, "profileName": "dbachecks3-master", "connectTimeout": 15, "encrypt": false, "applicationName": "vscode-mssql" }, { "server": "dbachecks3", "database": "msdb", "authenticationType": "SqlLogin", "user": "sqladmin", "password": "dbatools.IO", "emptyPasswordInput": false, "savePassword": true, "profileName": "dbachecks3-msdb", "connectTimeout": 15, "encrypt": false, "applicationName": "vscode-mssql" } ] } } ================================================ FILE: developing/Archive/Get-AllInstanceInfo testing.ps1 ================================================ # Get-AllInstanceInfo testing # so the initial load doesnt skew the figures ipmo dbatools ipmo ./dbachecks.psd1 function prompt { Write-Host "pwsh >" -NoNewline; ' ' } cls # load the original function . .\originalGet-AllInstanceInfo.ps1 . .\internal\functions\NewGet-AllInstanceInfo.ps1 $Checks = 'TwoDigitYearCutoff','MaxDopInstance','ErrorLogCount','ModelDbGrowth','DefaultBackupCompression','SaExist','SaDisabled','SaRenamed','DefaultFilePath','AdHocDistributedQueriesEnabled','AdHocWorkload', 'DefaultTrace', 'OleAutomationProceduresDisabled', 'CrossDBOwnershipChaining', 'ScanForStartupProceduresDisabled', 'RemoteAccessDisabled', 'SQLMailXPsDisabled', 'DAC', 'OLEAutomation' $Checks = 'TwoDigitYearCutoff' Compare-GetAllInstanceInfoPerf -Checks $Checks function Compare-GetAllInstanceInfoPerf { Param($Checks) $originalCode = { $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $Sqlinstances = 'localhost,7401', 'localhost,7402', 'localhost,7403' $smos = Connect-DbaInstance -SqlInstance $Sqlinstances -SqlCredential $cred foreach ($smo in $smos) { Get-AllInstanceInfo -Instance $smo -Tags $Checks -There $true } } $NewCode = { $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $Sqlinstances = 'localhost,7401', 'localhost,7402', 'localhost,7403' $smos = Connect-DbaInstance -SqlInstance $Sqlinstances -SqlCredential $cred foreach ($smo in $smos) { NewGet-AllInstanceInfo -Instance $smo -Tags $SPConfigureChecks -There $true } } $originalCodetrace = Trace-Script -ScriptBlock $originalCode $NewCodetrace = Trace-Script -ScriptBlock $NewCode $originalCodeMessage = "With original Code it takes {0} MilliSeconds" -f $originalCodetrace.StopwatchDuration.TotalMilliseconds $NewCodeMessage = "With New Code it takes {0} MilliSeconds" -f $NewCodetrace.StopwatchDuration.TotalMilliseconds $savingMessage = " Running with {3} Checks against 3 SQL Containers With original Code it takes {1} Seconds With New Code it takes {4} Seconds New Code for these {5} checks is saving {0} seconds from a run of {1} seconds New Code runs in {2} % of the time " -f ('{0:N2}' -f ($originalCodetrace.StopwatchDuration.TotalSeconds - $NewCodetrace.StopwatchDuration.TotalSeconds)),('{0:N2}' -f $originalCodetrace.StopwatchDuration.TotalSeconds),('{0:N2}' -f (($NewCodetrace.StopwatchDuration.TotalSeconds/$originalCodetrace.StopwatchDuration.TotalSeconds) * 100)),($Checks -split ',' -join ',') ,('{0:N2}' -f $NewCodetrace.StopwatchDuration.TotalSeconds), $Checks.Count cls Write-PSFMessage -Message $originalCodeMessage -Level Significant Write-PSFMessage -Message $NewCodeMessage -Level Significant Write-PSFMessage -Message $savingMessage -Level Output } ================================================ FILE: developing/Archive/Perf Testing pesterv5.ps1 ================================================ ## To Test performance - I pull the dbatools docker repo and cd to the samples/stackoverflow Directory ## I changed the ports because I have some of them already running SQL ## line 17 - "7401:1433" ## line 34 - "7402:1433" ## line 52 - "7403:1433" #then docker compose up -d # cd to the root of dbachecks and checkout the pesterv5 branch ipmo ./dbachecks.psd1 # $Checks = 'XpCmdShellDisabled','WhoIsActiveInstalled','CLREnabled','TraceFlagsNotExpected','TraceFlagsExpected','TwoDigitYearCutoff','MaxDopInstance','ErrorLogCount','ModelDbGrowth','DefaultBackupCompression','SaExist','SaDisabled','SaRenamed','DefaultFilePath','AdHocDistributedQueriesEnabled','AdHocWorkload', 'DefaultTrace', 'OleAutomationProceduresDisabled', 'CrossDBOwnershipChaining', 'ScanForStartupProceduresDisabled', 'RemoteAccessDisabled', 'SQLMailXPsDisabled', 'DAC', 'OLEAutomation' $Checks = 'XpCmdShellDisabled' <# When there are default skips (some of the CIS checks) we need to set the configs and check Set-DbcConfig skip.security.sadisabled -Value $false Set-DbcConfig skip.security.sadisabled -Value $true Get-DbcConfigValue skip.security.sadisabled Set-DbcConfig skip.security.saexist -Value $false Set-DbcConfig skip.security.saexist -Value $true Get-DbcConfigValue skip.security.saexist Get-DbcConfigValue policy.instancemaxdop.userecommended Get-DbcConfigValue policy.instancemaxdop.maxdop Get-DbcConfigValue policy.instancemaxdop.excludeinstance Set-DbcConfig policy.instancemaxdop.userecommended -Value $false Set-DbcConfig policy.instancemaxdop.userecommended -Value $true Set-DbcConfig policy.instancemaxdop.maxdop -Value 0 Set-DbcConfig policy.instancemaxdop.excludeinstance -Value $null Set-DbcConfig policy.instancemaxdop.excludeinstance -Value 'localhost,7401' Get-DbcConfigValue policy.traceflags.expected Get-DbaTraceFlag -SqlInstance $Sqlinstances -SqlCredential $cred Set-DbcConfig policy.traceflags.expected -Value 1117,1118 Set-DbcConfig policy.traceflags.expected -Value $null Enable-DbaTraceFlag -SqlInstance $Sqlinstances -SqlCredential $cred -TraceFlag 1117,1118 Disable-DbaTraceFlag -SqlInstance $Sqlinstances -SqlCredential $cred -TraceFlag 1117,1118 Disable-DbaTraceFlag -SqlInstance $Sqlinstances -SqlCredential $cred -TraceFlag 1118 #> # Load the function below and then you can keep running the checks defined above in v4 and v5 and compare the performance # You can keep updating the .Tests.ps1 files and rerunning the function without needing to re-import hte module # If you change any of the functions you WILL need to re-import or better still use a new session # If you get odd results - or you dont get any checks run # run the import module and the Invoke Dbc Check with Verbose and that might show you New-Json messing # with your files or that you are looking in PSMOdulePath instead of Git Repo path (run Reset-dbcConfig to fix that) function Compare-CheckRuns { param($Checks) $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $Sqlinstances = 'localhost,7401', 'localhost,7402', 'localhost,7403' $originalCode = { Invoke-DbcCheck -SqlInstance $Sqlinstances -Check $Checks -SqlCredential $cred -legacy $true -Show None } $NewCode = { Invoke-DbcCheck -SqlInstance $Sqlinstances -Check $Checks -SqlCredential $cred -legacy $false -Show None } $originalCodetrace = Trace-Script -ScriptBlock $originalCode $NewCodetrace = Trace-Script -ScriptBlock $NewCode $originalCodeMessage = "With original Code it takes {0} MilliSeconds" -f $originalCodetrace.StopwatchDuration.TotalMilliseconds $savingMessage = " Running with {3} Checks against $($Sqlinstances.Count) SQL Containers With original Code it takes {1} Seconds With New Code it takes {4} Seconds New Code for these {5} checks is saving {0} seconds from a run of {1} seconds New Code runs in {2} % of the time " -f ('{0:N2}' -f ($originalCodetrace.StopwatchDuration.TotalSeconds - $NewCodetrace.StopwatchDuration.TotalSeconds)),('{0:N2}' -f $originalCodetrace.StopwatchDuration.TotalSeconds),('{0:N2}' -f (($NewCodetrace.StopwatchDuration.TotalSeconds/$originalCodetrace.StopwatchDuration.TotalSeconds) * 100)),($Checks -split ',' -join ',') ,('{0:N2}' -f $NewCodetrace.StopwatchDuration.TotalSeconds), $Checks.Count cls Write-PSFMessage -Message $savingMessage -Level Output } # $Checks = 'DbaOperator' Compare-CheckRuns -Checks $checks ================================================ FILE: developing/Archive/PerfAndValidate-Checks.ps1 ================================================ ## To Test performance - I pull the dbatools docker repo and cd to the samples/stackoverflow Directory ## I changed the ports because I have some of them already running SQL ## line 17 - "7401:1433" ## line 34 - "7402:1433" ## line 52 - "7403:1433" #then docker compose up -d # cd to the root of dbachecks and checkout the pesterv5 branch ipmo ./dbachecks.psd1 # #$Checks = 'XpCmdShellDisabled','WhoIsActiveInstalled','CLREnabled','TraceFlagsNotExpected','TraceFlagsExpected','TwoDigitYearCutoff','MaxDopInstance','ErrorLogCount','ModelDbGrowth','DefaultBackupCompression','SaExist','SaDisabled','SaRenamed','DefaultFilePath','AdHocDistributedQueriesEnabled','AdHocWorkload', 'DefaultTrace', 'OleAutomationProceduresDisabled', 'CrossDBOwnershipChaining', 'ScanForStartupProceduresDisabled', 'RemoteAccessDisabled', 'SQLMailXPsDisabled', 'DAC', 'OLEAutomation' $Checks = 'AsymmetricKeySize' <# When there are default skips (some of the CIS checks) we need to set the configs and check Set-DbcConfig skip.security.sadisabled -Value $false Set-DbcConfig skip.security.sadisabled -Value $true Get-DbcConfigValue skip.security.sadisabled Set-DbcConfig skip.security.saexist -Value $false Set-DbcConfig skip.security.saexist -Value $true Get-DbcConfigValue skip.security.saexist Get-DbcConfigValue policy.instancemaxdop.userecommended Get-DbcConfigValue policy.instancemaxdop.maxdop Get-DbcConfigValue policy.instancemaxdop.excludeinstance Set-DbcConfig policy.instancemaxdop.userecommended -Value $false Set-DbcConfig policy.instancemaxdop.userecommended -Value $true Set-DbcConfig policy.instancemaxdop.maxdop -Value 0 Set-DbcConfig policy.instancemaxdop.excludeinstance -Value $null Set-DbcConfig policy.instancemaxdop.excludeinstance -Value 'localhost,7401' Get-DbcConfigValue policy.traceflags.expected Get-DbaTraceFlag -SqlInstance $Sqlinstances -SqlCredential $cred Set-DbcConfig policy.traceflags.expected -Value 1117,1118 Set-DbcConfig policy.traceflags.expected -Value $null Enable-DbaTraceFlag -SqlInstance $Sqlinstances -SqlCredential $cred -TraceFlag 1117,1118 Disable-DbaTraceFlag -SqlInstance $Sqlinstances -SqlCredential $cred -TraceFlag 1117,1118 Disable-DbaTraceFlag -SqlInstance $Sqlinstances -SqlCredential $cred -TraceFlag 1118 #> # Load the function below and then you can keep running the checks defined above in v4 and v5 and compare the performance # You can keep updating the .Tests.ps1 files and rerunning the function without needing to re-import hte module # If you change any of the functions you WILL need to re-import or better still use a new session # If you get odd results - or you dont get any checks run # run the import module and the Invoke Dbc Check with Verbose and that might show you New-Json messing # with your files or that you are looking in PSMOdulePath instead of Git Repo path (run Reset-dbcConfig to fix that) function Invoke-PerfAndValidateChecks { param($Checks) $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $Sqlinstances = 'localhost,7401', 'localhost,7402', 'localhost,7403' $originalCode = { $global:v4code = Invoke-DbcCheck -SqlInstance $Sqlinstances -Check $Checks -SqlCredential $cred -legacy $true -Show None -PassThru } $NewCode = { $global:v5code = Invoke-DbcCheck -SqlInstance $Sqlinstances -Check $Checks -SqlCredential $cred -legacy $false -Show None -PassThru } $originalCodetrace = Trace-Script -ScriptBlock $originalCode $NewCodetrace = Trace-Script -ScriptBlock $NewCode $originalCodeMessage = "With original Code it takes {0} MilliSeconds" -f $originalCodetrace.StopwatchDuration.TotalMilliseconds $savingMessage = " Running with {3} Checks against $($Sqlinstances.Count) SQL Containers With original Code it takes {1} Seconds With New Code it takes {4} Seconds New Code for these {5} checks is saving {0} seconds from a run of {1} seconds New Code runs in {2} % of the time " -f ('{0:N2}' -f ($originalCodetrace.StopwatchDuration.TotalSeconds - $NewCodetrace.StopwatchDuration.TotalSeconds)),('{0:N2}' -f $originalCodetrace.StopwatchDuration.TotalSeconds),('{0:N2}' -f (($NewCodetrace.StopwatchDuration.TotalSeconds/$originalCodetrace.StopwatchDuration.TotalSeconds) * 100)),($Checks -split ',' -join ',') ,('{0:N2}' -f $NewCodetrace.StopwatchDuration.TotalSeconds), $Checks.Count Write-PSFMessage -Message $savingMessage -Level Output ##validate we got the right answers too If (Compare-Object $v5code.Configuration.Filter.Tag.Value $v4code.TagFilter) { $Message = " Uh-Oh - The Tag filters between v4 and v5 are not the same somehow. For v4 We returned {0} and For v5 we returned {1} " -f ($v4code.TagFilter | Out-String), ($v5code.Configuration.Filter.Tag.Value | Out-String) Write-PSFMessage -Message $Message -Level Warning } else { $message = " The Tags are the same" Write-PSFMessage -Message $Message -Level Output } If (($v5code.TotalCount - $v5code.NotRunCount) -ne $v4code.TotalCount) { $Message = " Uh-Oh - The total tests run between v4 and v5 are not the same somehow. For v4 We ran {0} tests and For v5 we ran {1} tests The MOST COMMON REASON IS you have used Tags instead of Tag in your Describe block but TraceFlagsNotExpected will change that also " -f $v4code.TotalCount, ($v5code.TotalCount - $v5code.NotRunCount) Write-PSFMessage -Message $Message -Level Warning } else { $message = " The Total Tests Run are the same {0} {1} " -f $v4code.TotalCount, ($v5code.TotalCount - $v5code.NotRunCount) Write-PSFMessage -Message $Message -Level Output } If ($v5code.PassedCount -ne $v4code.PassedCount) { $Message = " Uh-Oh - The total tests Passed between v4 and v5 are not the same somehow. For v4 We Passed {0} tests and For v5 we Passed {1} tests " -f $v4code.PassedCount, $v5code.PassedCount Write-PSFMessage -Message $Message -Level Warning } else { $message = " The Total Tests Passed are the same {0} {1} " -f $v4code.PassedCount, $v5code.PassedCount Write-PSFMessage -Message $Message -Level Output } If ($v5code.FailedCount -ne $v4code.FailedCount) { $Message = " Uh-Oh - The total tests Failed between v4 and v5 are not the same somehow. For v4 We Failed {0} tests and For v5 we Failed {1} tests " -f $v4code.FailedCount, $v5code.FailedCount Write-PSFMessage -Message $Message -Level Warning } else { $message = " The Total Tests Failed are the same {0} {1} " -f $v4code.FailedCount, $v5code.FailedCount Write-PSFMessage -Message $Message -Level Output } If ($v5code.SkippedCount -ne $v4code.SkippedCount) { $Message = " Uh-Oh - The total tests Skipped between v4 and v5 are not the same somehow. For v4 We Skipped {0} tests and For v5 we Skipped {1} tests " -f $v4code.SkippedCount, $v5code.SkippedCount Write-PSFMessage -Message $Message -Level Warning } else { $message = " The Total Tests Skipped are the same {0} {1} "-f $v4code.SkippedCount, $v5code.SkippedCount Write-PSFMessage -Message $Message -Level Output } } # $Checks = 'DbaOperator' Invoke-PerfAndValidateChecks -Checks 'VirtualLogFile' ================================================ FILE: developing/Archive/Validate v4 adn v5.ps1 ================================================ ## To Test performance - I pull the dbatools docker repo and cd to the samples/stackoverflow Directory ## I changed the ports because I have some of them already running SQL ## line 17 - "7401:1433" ## line 34 - "7402:1433" ## line 52 - "7403:1433" #then docker compose up -d # cd to the root of dbachecks and checkout the pesterv5 branch <# RUN THIS SECTION MANUALLY IF YOU JUST IMPORT THE FUNCTION BELOW! ipmo ./dbachecks.psd1 $Checks = 'XESessionExists','XESessionStopped','XpCmdShellDisabled','WhoIsActiveInstalled','CLREnabled','TraceFlagsNotExpected','TraceFlagsExpected','TwoDigitYearCutoff','MaxDopInstance','ErrorLogCount','ModelDbGrowth','DefaultBackupCompression','SaExist','SaDisabled','SaRenamed','DefaultFilePath','AdHocDistributedQueriesEnabled','AdHocWorkload', 'DefaultTrace', 'OleAutomationProceduresDisabled', 'CrossDBOwnershipChaining', 'ScanForStartupProceduresDisabled', 'RemoteAccessDisabled', 'SQLMailXPsDisabled', 'DAC', 'OLEAutomation' $Checks = 'XESessionExists' Compare-v4andv5Results -Checks $Checks # if you need to see the details to see why the results are different Compare-v4andv5Results -Checks $Checks -Details #> <# When there are default skips (some of the CIS checks) we need to set the configs and check Set-DbcConfig skip.security.sadisabled -Value $false Set-DbcConfig skip.security.sadisabled -Value $true Get-DbcConfigValue skip.security.sadisabled Set-DbcConfig skip.security.saexist -Value $false Set-DbcConfig skip.security.saexist -Value $true Get-DbcConfigValue skip.security.saexist Get-DbcConfigValue policy.instancemaxdop.userecommended Get-DbcConfigValue policy.instancemaxdop.maxdop Get-DbcConfigValue policy.instancemaxdop.excludeinstance Set-DbcConfig policy.instancemaxdop.userecommended -Value $false Set-DbcConfig policy.instancemaxdop.userecommended -Value $true Set-DbcConfig policy.instancemaxdop.maxdop -Value 0 Set-DbcConfig policy.instancemaxdop.excludeinstance -Value $null Set-DbcConfig policy.instancemaxdop.excludeinstance -Value 'localhost,7402' Get-DbcConfigValue policy.traceflags.expected Get-DbaTraceFlag -SqlInstance $Sqlinstances -SqlCredential $cred Set-DbcConfig policy.traceflags.expected -Value 1117,1118 Set-DbcConfig policy.traceflags.expected -Value $null Enable-DbaTraceFlag -SqlInstance $Sqlinstances -SqlCredential $cred -TraceFlag 1117,1118 Disable-DbaTraceFlag -SqlInstance $Sqlinstances -SqlCredential $cred -TraceFlag 1117,1118 Disable-DbaTraceFlag -SqlInstance $Sqlinstances -SqlCredential $cred -TraceFlag 1118 Get-DbcConfigValue policy.traceflags.expected Get-DbcConfigValue policy.traceflags.notexpected Get-DbaTraceFlag -SqlInstance $Sqlinstances -SqlCredential $cred Set-DbcConfig policy.traceflags.expected -Value 1117,1118 Set-DbcConfig policy.traceflags.notexpected -Value 1117,1118 Set-DbcConfig policy.traceflags.expected -Value $null Set-DbcConfig policy.traceflags.notexpected -Value $null Enable-DbaTraceFlag -SqlInstance $Sqlinstances -SqlCredential $cred -TraceFlag 1117,1118 Disable-DbaTraceFlag -SqlInstance $Sqlinstances -SqlCredential $cred -TraceFlag 1117,1118 Disable-DbaTraceFlag -SqlInstance $Sqlinstances -SqlCredential $cred -TraceFlag 1118 #> # Load the function below and then you can keep running the checks defined above in v4 and v5 and compare the performance # You can keep updating the .Tests.ps1 files and rerunning the function without needing to re-import hte module # You can keep updating the .Tests.ps1 files and rerunning without needing to re-import hte module # If you change any of the functions you WILL need to re-import or better still use a new session # If you get odd results - or you dont get any checks run # run the import module and the Invoke Dbc Check with Verbose and that might show you New-Json messing # with your files or that you are looking in PSModulePath instead of Git Repo path (run Reset-dbcConfig to fix that) function Compare-v4andv5Results { param( $Checks, [switch]$details ) $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $Sqlinstances = 'localhost,7401', 'localhost,7402', 'localhost,7403' if ($details) { $show = 'all' } else { $show = 'none' } # Run v4 checks $v4code = Invoke-DbcCheck -SqlInstance $Sqlinstances -SqlCredential $cred -Check $Checks -legacy $true -Show $show -PassThru # Run v5 checks $v5code = Invoke-DbcCheck -SqlInstance $Sqlinstances -SqlCredential $cred -Check $Checks -legacy $false -Show $show -PassThru If (Compare-Object $v5code.Configuration.Filter.Tag.Value $v4code.TagFilter) { $Message = " Uh-Oh - The Tag filters between v4 and v5 are not the same somehow. For v4 We returned {0} and For v5 we returned {1} " -f ($v4code.TagFilter | Out-String), ($v5code.Configuration.Filter.Tag.Value | Out-String) Write-PSFMessage -Message $Message -Level Warning } else { $message = " The Tags are the same" Write-PSFMessage -Message $Message -Level Output } If (($v5code.TotalCount - $v5code.NotRunCount) -ne $v4code.TotalCount) { $Message = " Uh-Oh - The total tests run between v4 and v5 are not the same somehow. For v4 We ran {0} tests and For v5 we ran {1} tests The MOST COMMON REASON IS you have used Tags instead of Tag in your Describe block but TraceFlagsNotExpected will change that also " -f $v4code.TotalCount, ($v5code.TotalCount - $v5code.NotRunCount) Write-PSFMessage -Message $Message -Level Warning } else { $message = " The Total Tests Run are the same {0} {1} " -f $v4code.TotalCount, ($v5code.TotalCount - $v5code.NotRunCount) Write-PSFMessage -Message $Message -Level Output } If ($v5code.PassedCount -ne $v4code.PassedCount) { $Message = " Uh-Oh - The total tests Passed between v4 and v5 are not the same somehow. For v4 We Passed {0} tests and For v5 we Passed {1} tests " -f $v4code.PassedCount, $v5code.PassedCount Write-PSFMessage -Message $Message -Level Warning } else { $message = " The Total Tests Passed are the same {0} {1} " -f $v4code.PassedCount, $v5code.PassedCount Write-PSFMessage -Message $Message -Level Output } If ($v5code.FailedCount -ne $v4code.FailedCount) { $Message = " Uh-Oh - The total tests Failed between v4 and v5 are not the same somehow. For v4 We Failed {0} tests and For v5 we Failed {1} tests " -f $v4code.FailedCount, $v5code.FailedCount Write-PSFMessage -Message $Message -Level Warning } else { $message = " The Total Tests Failed are the same {0} {1} " -f $v4code.FailedCount, $v5code.FailedCount Write-PSFMessage -Message $Message -Level Output } If ($v5code.SkippedCount -ne $v4code.SkippedCount) { $Message = " Uh-Oh - The total tests Skipped between v4 and v5 are not the same somehow. For v4 We Skipped {0} tests and For v5 we Skipped {1} tests " -f $v4code.SkippedCount, $v5code.SkippedCount Write-PSFMessage -Message $Message -Level Warning } else { $message = " The Total Tests Skipped are the same {0} {1} "-f $v4code.SkippedCount, $v5code.SkippedCount Write-PSFMessage -Message $Message -Level Output } } <#e $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $Sqlinstances = 'localhost,7401', 'localhost,7402', 'localhost,7403' Invoke-DbcCheck -SqlInstance $Sqlinstances -SqlCredential $cred -Check $Checks -legacy $false Invoke-DbcCheck -SqlInstance $Sqlinstances -SqlCredential $cred -Check $Checks -legacy $true $smo = $Instance = Connect-DbaInstance -Sqlinstance $SqlInstances[0] -SqlCredential $cred #> ================================================ FILE: developing/Archive/initfields.ps1 ================================================ # uses Jakubs Profiler Module - Install-Module Profiler $withinitFIeldsSMO = { $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $Sqlinstances = 'localhost,7401', 'localhost,7402', 'localhost,7403' $smos = Connect-DbaInstance -SqlInstance $Sqlinstances -SqlCredential $cred foreach ($smo in $smos) { $smo.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server], $false) $smo.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database], $false) $smo.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Login], $false) $smo.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job], $false) $initfields = $smo.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server]) $initfields.Add("Collation") $smo.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server], $initfields) $dbinitfields = $smo.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database]) $dbinitfields.Add("Collation") $smo.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database], $initfields) [PSCustomObject]@{ ComputerName = $smo.ComputerName InstanceName = $smo.DbaInstanceName Collation = $smo.Collation Databases = $Smo.Databases.ForEach{ [PSCustomObject]@{ Name = $_.Name Collation = $_.Collation } } } } } $WithoutInitFieldsSMO = { $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $Sqlinstances = 'localhost,7401', 'localhost,7402', 'localhost,7403' $smos = Connect-DbaInstance -SqlInstance $Sqlinstances -SqlCredential $cred foreach ($smo in $smos) { [PSCustomObject]@{ ComputerName = $smo.ComputerName InstanceName = $smo.DbaInstanceName Collation = $smo.Collation Databases = $Smo.Databases.ForEach{ [PSCustomObject]@{ Name = $_.Name Collation = $_.Collation } } } } } $justdbatools = { $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $Sqlinstances = 'localhost,7401', 'localhost,7402', 'localhost,7403' $smos = Connect-DbaInstance -SqlInstance $Sqlinstances -SqlCredential $cred foreach($smo in $smos){ $collation = Test-DbaDbCollation -SqlInstance $smo [PSCustomObject]@{ ComputerName = $smo.ComputerName InstanceName = $smo.DbaInstanceName Collation = $collation[0].ServerCollation Databases = $collation.ForEach{ [PSCustomObject]@{ Name = $_.Database Collation = $_.DatabaseCollation } } } } } # so the initial load doesnt skew the figures ipmo dbatools function prompt { Write-Host "pwsh >" -NoNewline; ' '} $justdbatoolstrace = Trace-Script -ScriptBlock $justdbatools $WithoutInittrace = Trace-Script -ScriptBlock $WithoutInitFieldsSMO $withinittrace = Trace-Script -ScriptBlock $withinitFIeldsSMO $dbatoolsMessage = "With dbatools it takes {0} MilliSeconds" -f $justdbatoolstrace.StopwatchDuration.TotalMilliseconds $withinittMessage = "With initfields and SMO it takes {0} MilliSeconds" -f $withinittrace.StopwatchDuration.TotalMilliseconds $WithoutInitMessage = "Without initfields and SMO it takes {0} MilliSeconds" -f $WithoutInittrace.StopwatchDuration.TotalMilliseconds Write-PSFMessage -Message $dbatoolsMessage -Level Significant Write-PSFMessage -Message $WithoutInitMessage -Level Significant Write-PSFMessage -Message $withinittMessage -Level Significant <# pwsh > Write-PSFMessage -Message $dbatoolsMessage -Level Significant [10:36:20][] With dbatools it takes 308.9962 MilliSeconds pwsh > Write-PSFMessage -Message $WithoutInitMessage -Level Significant [10:36:20][] Without initfields and SMO it takes 270.5188 MilliSeconds pwsh > Write-PSFMessage -Message $withinittMessage -Level Significant [10:36:20][] With initfields and SMO it takes 117.5935 MilliSeconds #> $10timesWithInit = Invoke-Script -ScriptBlock $withinitFIeldsSMO -Preheat 0 -Repeat 10 # We run Pester V4 here because the -legacy parameter of Invoke-DbcCheck is set to true by default $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $Sqlinstances = 'localhost,7401', 'localhost,7402', 'localhost,7403' $smos = Connect-DbaInstance -SqlInstance $Sqlinstances -SqlCredential $cred $Fields2000_Db = 'Collation', 'CompatibilityLevel', 'CreateDate', 'ID', 'IsAccessible', 'IsFullTextEnabled', 'IsSystemObject', 'IsUpdateable', 'LastBackupDate', 'LastDifferentialBackupDate', 'LastLogBackupDate', 'Name', 'Owner', 'ReadOnly', 'RecoveryModel', 'ReplicationOptions', 'Status', 'Version' $Fields200x_Db = $Fields2000_Db + @('BrokerEnabled', 'DatabaseSnapshotBaseName', 'IsMirroringEnabled', 'Trustworthy') $Fields201x_Db = $Fields200x_Db + @('ActiveConnections', 'AvailabilityDatabaseSynchronizationState', 'AvailabilityGroupName', 'ContainmentType', 'EncryptionEnabled') $Fields2000_Login = 'CreateDate', 'DateLastModified', 'DefaultDatabase', 'DenyWindowsLogin', 'IsSystemObject', 'Language', 'LanguageAlias', 'LoginType', 'Name', 'Sid', 'WindowsLoginAccessType' $Fields200x_Login = $Fields2000_Login + @('AsymmetricKey', 'Certificate', 'Credential', 'ID', 'IsDisabled', 'IsLocked', 'IsPasswordExpired', 'MustChangePassword', 'PasswordExpirationEnabled', 'PasswordPolicyEnforced') $Fields201x_Login = $Fields200x_Login + @('PasswordHashAlgorithm') #see #7753 $Fields_Job = 'LastRunOutcome', 'CurrentRunStatus', 'CurrentRunStep', 'CurrentRunRetryAttempt', 'NextRunScheduleID', 'NextRunDate', 'LastRunDate', 'JobType', 'HasStep', 'HasServer', 'CurrentRunRetryAttempt', 'HasSchedule', 'Category', 'CategoryID', 'CategoryType', 'OperatorToEmail', 'OperatorToNetSend', 'OperatorToPage' $initFieldsDb = New-Object System.Collections.Specialized.StringCollection $initFieldsLogin = New-Object System.Collections.Specialized.StringCollection $initFieldsJob = New-Object System.Collections.Specialized.StringCollection ================================================ FILE: developing/Archive/originalGet-AllInstanceInfo.ps1 ================================================ function Get-AllInstanceInfo { # Using the unique tags gather the information required Param($Instance, $Tags, $There) # Using there so that if the instance is not contactable, no point carrying on with gathering more information switch ($tags) { 'ErrorLog' { if ($There) { try { $logWindow = Get-DbcConfigValue -Name policy.errorlog.warningwindow # so that it can be mocked function Get-ErrorLogEntry { # get the number of the first error log that was created after the log window config $OldestErrorLogNumber = ($InstanceSMO.EnumErrorLogs() | Where-Object { $psitem.CreateDate -gt (Get-Date).AddDays( - $LogWindow) } | Sort-Object ArchiveNo -Descending | Select-Object -First 1).ArchiveNo + 1 # Get the Error Log entries for each one (0..$OldestErrorLogNumber).ForEach{ $InstanceSMO.ReadErrorLog($psitem).Where{ $_.Text -match "Severity: 1[7-9]|Severity: 2[0-4]" } } } # It is not enough to check the CreateDate on the log, you must check the LogDate on every error record as well. $ErrorLog = @(Get-ErrorLogEntry).ForEach{ [PSCustomObject]@{ LogDate = $psitem.LogDate ProcessInfo = $Psitem.ProcessInfo Text = $Psitem.Text } | Where-Object { $psitem.LogDate -gt (Get-Date).AddDays( - $LogWindow) } } } catch { $There = $false $ErrorLog = [PSCustomObject]@{ LogDate = 'Do not know the Date' ProcessInfo = 'Do not know the Process' Text = 'Do not know the Test' InstanceName = 'An Error occurred ' + $Instance } } } else { $There = $false $ErrorLog = [PSCustomObject]@{ LogDate = 'Do not know the Date' ProcessInfo = 'Do not know the Process' Text = 'Do not know the Test' InstanceName = 'An Error occurred ' + $Instance } } } 'DefaultTrace' { if ($There) { try { $SpConfig = Get-DbaSpConfigure -SqlInstance $Instance -ConfigName 'DefaultTraceEnabled' $DefaultTrace = [pscustomobject] @{ ConfiguredValue = $SpConfig.ConfiguredValue } } catch { $There = $false $DefaultTrace = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } else { $There = $false $DefaultTrace = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } 'OleAutomationProceduresDisabled' { if ($There) { try { $SpConfig = Get-DbaSpConfigure -SqlInstance $Instance -ConfigName 'OleAutomationProceduresEnabled' $OleAutomationProceduresDisabled = [pscustomobject] @{ ConfiguredValue = $SpConfig.ConfiguredValue } } catch { $There = $false $OleAutomationProceduresDisabled = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } else { $There = $false $OleAutomationProceduresDisabled = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } 'CrossDBOwnershipChaining' { if ($There) { try { $SpConfig = Get-DbaSpConfigure -SqlInstance $Instance -ConfigName 'CrossDBOwnershipChaining' $CrossDBOwnershipChaining = [pscustomobject] @{ ConfiguredValue = $SpConfig.ConfiguredValue } } catch { $There = $false $CrossDBOwnershipChaining = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } else { $There = $false $CrossDBOwnershipChaining = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } 'ScanForStartupProceduresDisabled' { if ($There) { try { $SpConfig = Get-DbaSpConfigure -SqlInstance $Instance -ConfigName 'ScanForStartupProcedures' $query = " SELECT name FROM sys.procedures WHERE OBJECTPROPERTY(OBJECT_ID, 'ExecIsStartup') = 1 AND name <> 'sp_MSrepl_startup'" $results = Invoke-DbaQuery -SqlInstance $Instance -Query $query if ($null -eq $results) { $Value = 0 } else { $Value = $SpConfig.ConfiguredValue } $ScanForStartupProceduresDisabled = [pscustomobject] @{ ConfiguredValue = $Value } } catch { $There = $false $ScanForStartupProceduresDisabled = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } else { $There = $false $ScanForStartupProceduresDisabled = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } 'MemoryDump' { if ($There) { try { $daystocheck = Get-DbcConfigValue policy.instance.memorydumpsdaystocheck if ($null -eq $daystocheck) { $datetocheckfrom = '0001-01-01' } else { $datetocheckfrom = (Get-Date).ToUniversalTime().AddDays( - $daystocheck ) } $MaxDump = [pscustomobject] @{ # Warning Action removes dbatools output for version too low from test results # Skip on the it will show in the results Count = (@(Get-DbaDump -SqlInstance $Instance -WarningAction SilentlyContinue).Where{ $_.CreationTime -gt $datetocheckfrom}).Count } } catch { $There = $false $MaxDump = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } else { $There = $false $MaxDump = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } 'RemoteAccessDisabled' { if ($There) { try { $SpConfig = Get-DbaSpConfigure -SqlInstance $Instance -ConfigName 'RemoteAccess' $RemoteAccessDisabled = [pscustomobject] @{ ConfiguredValue = $SpConfig.ConfiguredValue } } catch { $There = $false $RemoteAccessDisabled = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } else { $There = $false $RemoteAccessDisabled = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } 'LatestBuild' { if ($There) { try { $results = Test-DbaBuild -SqlInstance $Instance -Latest $LatestBuild = [pscustomobject] @{ Compliant = $results.Compliant } } catch { $There = $false $LatestBuild = [pscustomobject] @{ Compliant = 'We Could not Connect to $Instance' } } } else { $There = $false $LatestBuild = [pscustomobject] @{ Compliant = 'We Could not Connect to $Instance' } } } 'SaDisabled' { if ($There) { try { #This needs to be done in query just in case the account had already been renamed $login = Get-DbaLogin -SqlInstance $Instance | Where-Object Id -eq 1 $SaDisabled = [pscustomobject] @{ Disabled = $login.IsDisabled } } catch { $There = $false $SaDisabled = [pscustomobject] @{ Disabled = 'We Could not Connect to $Instance' } } } else { $There = $false $SaDisabled = [pscustomobject] @{ Disabled = 'We Could not Connect to $Instance' } } } 'SaExist' { if ($There) { try { $SaExist = [pscustomobject] @{ Exist = @(Get-DbaLogin -SqlInstance $Instance -Login sa).Count } } catch { $There = $false $SaExist = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } else { $There = $false $SaExist = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } 'SqlEngineServiceAccount' { if ($There) { try { $ComputerName , $InstanceName = $Instance.Name.Split('\') if ($null -eq $InstanceName) { $InstanceName = 'MSSQLSERVER' } $SqlEngineService = Get-DbaService -ComputerName $ComputerName -InstanceName $instanceName -Type Engine -ErrorAction SilentlyContinue $EngineService = [pscustomobject] @{ State = $SqlEngineService.State StartType = $SqlEngineService.StartMode } } catch { $There = $false $EngineService = [pscustomobject] @{ State = 'We Could not Connect to $Instance $ComputerName , $InstanceName from catch' StartType = 'We Could not Connect to $Instance $ComputerName , $InstanceName from catch' } } } else { $There = $false $EngineService = [pscustomobject] @{ State = 'We Could not Connect to $Instance' StartType = 'We Could not Connect to $Instance' } } } 'PublicRolePermission' { if ($There) { try { #This needs to be done in query just in case the account had already been renamed $query = " SELECT Count(*) AS [RowCount] FROM master.sys.server_permissions WHERE (grantee_principal_id = SUSER_SID(N'public') and state_desc LIKE 'GRANT%') AND NOT (state_desc = 'GRANT' and [permission_name] = 'VIEW ANY DATABASE' and class_desc = 'SERVER') AND NOT (state_desc = 'GRANT' and [permission_name] = 'CONNECT' and class_desc = 'ENDPOINT' and major_id = 2) AND NOT (state_desc = 'GRANT' and [permission_name] = 'CONNECT' and class_desc = 'ENDPOINT' and major_id = 3) AND NOT (state_desc = 'GRANT' and [permission_name] = 'CONNECT' and class_desc = 'ENDPOINT' and major_id = 4) AND NOT (state_desc = 'GRANT' and [permission_name] = 'CONNECT' and class_desc = 'ENDPOINT' and major_id = 5); " $results = Invoke-DbaQuery -SqlInstance $Instance -Query $query $PublicRolePermission = [pscustomobject] @{ Count = $results.RowCount } } catch { $There = $false $PublicRolePermission = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } else { $There = $false $PublicRolePermission = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } 'BuiltInAdmin' { if ($There) { try { $BuiltInAdmin = [pscustomobject] @{ Exist = @(Get-DbaLogin -SqlInstance $Instance -Login "BUILTIN\Administrators").Count } } catch { $There = $false $BuiltInAdmin = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } else { $There = $false $BuiltInAdmin = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } 'LocalWindowsGroup' { if ($There) { try { $ComputerName, $InstanceName = $Instance.Name.Split('\') if ($null -eq $InstanceName){ $InstanceName = 'MSSQLSERVER' } $logins = Get-DbaLogin -SqlInstance $Instance | Where-Object {$_.LoginType -eq 'WindowsGroup' -and $_.Name.Split('\') -eq $ComputerName} if ($null -ne $logins) { $LocalWindowsGroup = [pscustomobject] @{ Exist = $true } } else { $LocalWindowsGroup = [pscustomobject] @{ Exist = $false } } } catch { $There = $false $LocalWindowsGroup = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } else { $There = $false $LocalWindowsGroup = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } 'LoginAuditFailed' { if ($There) { try { $results = Get-DbaInstanceProperty -SQLInstance $instance -InstanceProperty AuditLevel $LoginAuditFailed = [pscustomobject] @{ AuditLevel = $results.Value } } catch { $There = $false $LoginAuditFailed = [pscustomobject] @{ AuditLevel = 'We Could not Connect to $Instance' } } } else { $There = $false $LoginAuditFailed = [pscustomobject] @{ AuditLevel = 'We Could not Connect to $Instance' } } } 'LoginAuditSuccessful' { if ($There) { try { $results = Get-DbaInstanceProperty -SQLInstance $instance -InstanceProperty AuditLevel $LoginAuditSuccessful = [pscustomobject] @{ AuditLevel = $results.Value } } catch { $There = $false $LoginAuditSuccessful = [pscustomobject] @{ AuditLevel = 'We Could not Connect to $Instance' } } } else { $There = $false $LoginAuditSuccessful = [pscustomobject] @{ AuditLevel = 'We Could not Connect to $Instance' } } } 'SqlAgentProxiesNoPublicRole' { if ($There) { try { $SqlAgentProxiesWithPublicRole = @() Get-DbaAgentProxy -SqlInstance $Instance | ForEach-Object { if ($psitem.EnumMsdbRoles().Name -contains 'public') { $SqlAgentProxyWithPublicRole = [pscustomobject] @{ Name = $psitem.Name CredentialName = $psitem.CredentialName CredentialIdentity = $psitem.CredentialIdentity } $SqlAgentProxiesWithPublicRole += $SqlAgentProxyWithPublicRole } } } catch { $There = $false $SqlAgentProxiesWithPublicRole = [pscustomobject] @{ Name = 'We Could not Connect to $Instance' CredentialName = $null CredentialIdentity = $null } } } else { $There = $false $SqlAgentProxiesWithPublicRole = [pscustomobject] @{ Name = 'We Could not Connect to $Instance' CredentialName = $null CredentialIdentity = $null } } } 'HideInstance' { if ($There) { try { $results = Get-DbaHideInstance -SqlInstance $Instance $HideInstance = [pscustomobject] @{ HideInstance = $results.HideInstance } } catch { $There = $false $HideInstance = [pscustomobject] @{ HideInstance = 'We Could not Connect to $Instance' } } } else { $There = $false $HideInstance = [pscustomobject] @{ HideInstance = 'We Could not Connect to $Instance' } } } 'EngineServiceAdmin' { if ($There) { if ($IsLinux) { $EngineServiceAdmin = [pscustomobject] @{ Exist = 'We Cant Check running on Linux' } } else { try { $ComputerName , $InstanceName = $Instance.Name.Split('\') if ($null -eq $InstanceName) { $InstanceName = 'MSSQLSERVER' } $SqlEngineService = Get-DbaService -ComputerName $ComputerName -InstanceName $instanceName -Type Engine -ErrorAction SilentlyContinue $LocalAdmins = Invoke-Command -ComputerName $ComputerName -ScriptBlock { Get-LocalGroupMember -Group "Administrators" } -ErrorAction SilentlyContinue $EngineServiceAdmin = [pscustomobject] @{ Exist = $localAdmins.Name.Contains($SqlEngineService.StartName) } } catch [System.Exception] { if ($_.Exception.Message -like '*No services found in relevant namespaces*') { $EngineServiceAdmin = [pscustomobject] @{ Exist = $false } } else { $EngineServiceAdmin = [pscustomobject] @{ Exist = 'Some sort of failure' } } } catch { $There = $false $EngineServiceAdmin = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance $ComputerName , $InstanceName from catch' } } } } else { $There = $false $EngineServiceAdmin = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } 'AgentServiceAdmin' { if ($There) { if ($IsLinux) { $AgentServiceAdmin = [pscustomobject] @{ Exist = 'We Cant Check running on Linux' } } else { try { $ComputerName , $InstanceName = $Instance.Name.Split('\') if ($null -eq $InstanceName) { $InstanceName = 'MSSQLSERVER' } $SqlAgentService = Get-DbaService -ComputerName $ComputerName -InstanceName $instanceName -Type Agent -ErrorAction SilentlyContinue $LocalAdmins = Invoke-Command -ComputerName $ComputerName -ScriptBlock { Get-LocalGroupMember -Group "Administrators" } -ErrorAction SilentlyContinue $AgentServiceAdmin = [pscustomobject] @{ Exist = $localAdmins.Name.Contains($SqlAgentService.StartName) } } catch [System.Exception] { if ($_.Exception.Message -like '*No services found in relevant namespaces*') { $AgentServiceAdmin = [pscustomobject] @{ Exist = $false } } else { $AgentServiceAdmin = [pscustomobject] @{ Exist = 'Some sort of failure' } } } catch { $There = $false $AgentServiceAdmin = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance $ComputerName , $InstanceName from catch' } } } } else { $There = $false $AgentServiceAdmin = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } 'FullTextServiceAdmin' { if ($There) { if ($IsLinux) { $FullTextServiceAdmin = [pscustomobject] @{ Exist = 'We Cant Check running on Linux' } } else { try { $ComputerName , $InstanceName = $Instance.Name.Split('\') if ($null -eq $InstanceName) { $InstanceName = 'MSSQLSERVER' } $SqlFullTextService = Get-DbaService -ComputerName $ComputerName -InstanceName $instanceName -Type FullText -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -WarningVariable WarVar $LocalAdmins = Invoke-Command -ComputerName $ComputerName -ScriptBlock { Get-LocalGroupMember -Group "Administrators" } -ErrorAction SilentlyContinue $FullTextServiceAdmin = [pscustomobject] @{ Exist = $localAdmins.Name.Contains($SqlFullTextService.StartName) } } catch [System.Exception] { if ($_.Exception.Message -like '*No services found in relevant namespaces*') { $FullTextServiceAdmin = [pscustomobject] @{ Exist = $false } } else { $FullTextServiceAdmin = [pscustomobject] @{ Exist = 'Some sort of failure' } } } catch { $There = $false $FullTextServiceAdmin = [pscustomobject] @{ Exist = "We Could not Connect to $Instance $ComputerName , $InstanceName from catch" } } } } else { $There = $false $FullTextServiceAdmin = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } 'LoginCheckPolicy' { if ($There) { try { $LoginCheckPolicy = [pscustomobject] @{ Count = @(Get-DbaLogin -SQLInstance $instance -Type SQL | Where-Object { $_.PasswordPolicyEnforced -eq $false -and $_.IsDisabled -eq $false}).Count } } catch { $There = $false $LoginCheckPolicy = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } else { $There = $false $LoginCheckPolicy = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } 'LoginPasswordExpiration' { if ($There) { try { $role = Get-DbaServerRole -SQLInstance $instance -ServerRole "sysadmin" $LoginPasswordExpiration = [pscustomobject] @{ Count = @(Get-DbaLogin -SQLInstance $instance -Login @($role.Login) -Type SQL | Where-Object { $_.PasswordExpirationEnabled -eq $false -and $_.IsDisabled -eq $false}).Count } } catch { $There = $false $LoginPasswordExpiration = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } else { $There = $false $LoginPasswordExpiration = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } 'LoginMustChange' { if ($There) { try { $role = Get-DbaServerRole -SQLInstance $instance -ServerRole "sysadmin" $LoginMustChange = [pscustomobject] @{ Count = @(Get-DbaLogin -SQLInstance $instance -Login @($role.Login) -Type SQL | Where-Object { $_.IsMustChange -eq $false -and $_.IsDisabled -eq $false -and $null -eq $_LastLogin }).Count } } catch { $There = $false $LoginMustChange = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } else { $There = $false $LoginMustChange = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } 'SQLMailXPsDisabled' { if ($There) { try { $SpConfig = Get-DbaSpConfigure -SqlInstance $Instance -ConfigName 'SqlMailXPsEnabled' $SQLMailXPsDisabled = [pscustomobject] @{ ConfiguredValue = $SpConfig.ConfiguredValue } } catch { $There = $false $SQLMailXPsDisabled = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } else { $There = $false $SQLMailXPsDisabled = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } Default { } } [PSCustomObject]@{ ErrorLog = $ErrorLog DefaultTrace = $DefaultTrace MaxDump = $MaxDump CrossDBOwnershipChaining = $CrossDBOwnershipChaining ScanForStartupProceduresDisabled = $ScanForStartupProceduresDisabled RemoteAccess = $RemoteAccessDisabled OleAutomationProceduresDisabled = $OleAutomationProceduresDisabled LatestBuild = $LatestBuild SaExist = $SaExist SaDisabled = $SaDisabled EngineService = $EngineService SqlAgentProxiesWithPublicRole = $SqlAgentProxiesWithPublicRole HideInstance = $HideInstance LoginAuditFailed = $LoginAuditFailed LoginAuditSuccessful = $LoginAuditSuccessful EngineServiceAdmin = $EngineServiceAdmin AgentServiceAdmin = $AgentServiceAdmin FullTextServiceAdmin = $FullTextServiceAdmin LocalWindowsGroup = $LocalWindowsGroup BuiltInAdmin = $BuiltInAdmin PublicRolePermission = $PublicRolePermission LoginCheckPolicy = $LoginCheckPolicy LoginPasswordExpiration = $LoginPasswordExpiration LoginMustChange = $LoginMustChange SQLMailXPsDisabled = $SQLMailXPsDisabled } } ================================================ FILE: developing/Archive/pesterv5testing.ps1 ================================================ ## To Test pull the dbatools docker repo and cd to the samples/stackoverflow Directory ## I changed the ports because I have some of them already running SQL ## line 17 - "7401:1433" ## line 34 - "7402:1433" ## line 52 - "7403:1433" #then docker compose up -d # cd to the root of dbachecks and checkout the pesterv5 branch <# What Is here So I have removed the check for Pester v5 from the psm1 load and created 2 internal functions Invoke-DbcCheckv4 and Invoke-DbcCheckv5 and added a legacy param to Invoke-DbcCheck by default it passes everything on to Invoke-DbcCheckv4 which is still the same as the original Invoke-DbcCheck so it shouldnt break anything So If you can test original work with Pester v4 that would be great. #> ipmo ./dbachecks.psd1 -Verbose # We run Pester V4 here because the -legacy parameter of Invoke-DbcCheck is set to true by default $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $PSDefaultParameterValues = @{ "Invoke-DbcCheck:SqlInstance" = 'localhost,7401','localhost,7409' "Invoke-DbcCheck:SqlCredential" = $cred } $Sqlinstances = 'localhost,7401','localhost,7402','localhost,7403' $broken = 'localhost,7401','localhost,7409' # check not contactable instances Invoke-DbcCheck -SqlInstance $broken -Check ValidJobOwner -SqlCredential $cred -Verbose Invoke-DbcCheck -Check DatabaseCollation -SqlCredential $cred # especially check both default params and specified - also need to check config too Invoke-DbcCheck -SqlInstance $broken -Check DatabaseCollation -SqlCredential $cred Invoke-DbcCheck -SqlInstance $Sqlinstances[0] -Check DatabaseCollation -SqlCredential $cred Invoke-DbcCheck -SqlInstance $Sqlinstances -Check DatabaseCollation -SqlCredential $cred Invoke-DbcCheck -SqlInstance $Sqlinstances[0] -Check DatabaseStatus -SqlCredential $cred Invoke-DbcCheck -SqlInstance $Sqlinstances[0] -Check AdHocDistributedQueriesEnabled -SqlCredential $cred Invoke-DbcCheck -SqlInstance $Sqlinstances[0] -Check AgentAlert -SqlCredential $cred Invoke-DbcCheck -SqlInstance $Sqlinstances[0] -Check AgentServiceAccount -SqlCredential $cred Invoke-DbcCheck -SqlInstance $Sqlinstances[0] -Check Backup -SqlCredential $cred Invoke-DbcCheck -SqlInstance $Sqlinstances[0] -Check CIS -SqlCredential $cred Invoke-DbcCheck -SqlInstance $Sqlinstances[0] -Check ExtendedEvent -SqlCredential $cred Invoke-DbcCheck -SqlInstance $Sqlinstances[0] -Check VirtualLogFile -SqlCredential $cred Invoke-DbcCheck -SqlInstance $Sqlinstances[0] -Check TempDbConfiguration -SqlCredential $cred Invoke-DbcCheck -SqlInstance $Sqlinstances[0] -Check InstanceConnection -SqlCredential $cred ############################### # We run Pester V5 here because the -legacy parameter of Invoke-DbcCheck is set to false as a default param ## NOt working # AutoClose, AutoSHrink # You dont have to reimport ipmo ./dbachecks.psd1 # -Verbose Reset-DbcConfig $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $Sqlinstances = 'localhost,7401','localhost,7402','localhost,7403' $PSDefaultParameterValues.Clear() # set default params for single instance and v5 $PSDefaultParameterValues = @{ "Invoke-DbcCheck:legacy" = $false "Invoke-DbcCheck:SqlInstance" = $Sqlinstances[0] "Invoke-DbcCheck:SqlCredential" = $cred } # set default params for multiple instances $PSDefaultParameterValues = @{ "Invoke-DbcCheck:legacy" = $false "Invoke-DbcCheck:SqlInstance" = $Sqlinstances[0..1] "Invoke-DbcCheck:SqlCredential" = $cred } # set default params for multiple instances with a broken one $PSDefaultParameterValues = @{ "Invoke-DbcCheck:legacy" = $false "Invoke-DbcCheck:SqlInstance" = 'localhost,7401','localhost,7409' "Invoke-DbcCheck:SqlCredential" = $cred } # a single tag from each of the groups <# $Code = Get-DbcCheck -Group Instance | ForEach-Object { "Invoke-DbcCheck -Check {0} -Show Detailed" -f $_.UniqueTag } $code | scb $Code = Get-DbcCheck -Group Database | ForEach-Object { "Invoke-DbcCheck -Check {0} -Show Detailed" -f $_.UniqueTag } $code | scb $Code = Get-DbcCheck -Group Agent | ForEach-Object { "Invoke-DbcCheck -Check {0} -Show Detailed" -f $_.UniqueTag } $code | scb #> #region Instance Invoke-DbcCheck -Check InstanceConnection -Show Detailed Invoke-DbcCheck -Check SqlEngineServiceAccount -Show Detailed Invoke-DbcCheck -Check TempDbConfiguration -Show Detailed Invoke-DbcCheck -Check AdHocWorkload -Show Detailed Invoke-DbcCheck -Check BackupPathAccess -Show Detailed Invoke-DbcCheck -Check DefaultFilePath -Show Detailed Invoke-DbcCheck -Check DAC -Show Detailed Invoke-DbcCheck -Check NetworkLatency -Show Detailed Invoke-DbcCheck -Check LinkedServerConnection -Show Detailed Invoke-DbcCheck -Check MaxMemory -Show Detailed Invoke-DbcCheck -Check OrphanedFile -Show Detailed Invoke-DbcCheck -Check ServerNameMatch -Show Detailed Invoke-DbcCheck -Check MemoryDump -Show Detailed Invoke-DbcCheck -Check SupportedBuild -Show Detailed Invoke-DbcCheck -Check SaRenamed -Show Detailed Invoke-DbcCheck -Check SaDisabled -Show Detailed Invoke-DbcCheck -Check SaExist -Show Detailed Invoke-DbcCheck -Check DefaultBackupCompression -Show Detailed Invoke-DbcCheck -Check XESessionStopped -Show Detailed Invoke-DbcCheck -Check XESessionRunning -Show Detailed Invoke-DbcCheck -Check XESessionRunningAllowed -Show Detailed Invoke-DbcCheck -Check OLEAutomation -Show Detailed Invoke-DbcCheck -Check WhoIsActiveInstalled -Show Detailed Invoke-DbcCheck -Check ModelDbGrowth -Show Detailed Invoke-DbcCheck -Check ADUser -Show Detailed Invoke-DbcCheck -Check ErrorLog -Show Detailed Invoke-DbcCheck -Check ErrorLogCount -Show Detailed Invoke-DbcCheck -Check MaxDopInstance -Show Detailed Invoke-DbcCheck -Check TwoDigitYearCutoff -Show Detailed Invoke-DbcCheck -Check TraceFlagsExpected -Show Detailed Invoke-DbcCheck -Check TraceFlagsNotExpected -Show Detailed Invoke-DbcCheck -Check CLREnabled -Show Detailed Invoke-DbcCheck -Check CrossDBOwnershipChaining -Show Detailed Invoke-DbcCheck -Check AdHocDistributedQueriesEnabled -Show Detailed Invoke-DbcCheck -Check XpCmdShellDisabled -Show Detailed Invoke-DbcCheck -Check ScanForStartupProceduresDisabled -Show Detailed Invoke-DbcCheck -Check DefaultTrace -Show Detailed Invoke-DbcCheck -Check OLEAutomationProceduresDisabled -Show Detailed Invoke-DbcCheck -Check RemoteAccessDisabled -Show Detailed Invoke-DbcCheck -Check LatestBuild -Show Detailed Invoke-DbcCheck -Check BuiltInAdmin -Show Detailed Invoke-DbcCheck -Check LocalWindowsGroup -Show Detailed Invoke-DbcCheck -Check LoginAuditFailed -Show Detailed Invoke-DbcCheck -Check LoginAuditSuccessful -Show Detailed Invoke-DbcCheck -Check SqlAgentProxiesNoPublicRole -Show Detailed Invoke-DbcCheck -Check HideInstance -Show Detailed Invoke-DbcCheck -Check EngineServiceAdmin -Show Detailed Invoke-DbcCheck -Check AgentServiceAdmin -Show Detailed Invoke-DbcCheck -Check FullTextServiceAdmin -Show Detailed Invoke-DbcCheck -Check LoginCheckPolicy -Show Detailed Invoke-DbcCheck -Check LoginPasswordExpiration -Show Detailed Invoke-DbcCheck -Check LoginMustChange -Show Detailed Invoke-DbcCheck -Check SuspectPageLimit -Show Detailed Invoke-DbcCheck -Check SQLMailXPsDisabled -Show Detailed Invoke-DbcCheck -Check PublicPermission -Show Detailed Invoke-DbcCheck -Check SqlBrowserServiceAccount -Show Detailed #endregion #region Database Invoke-DbcCheck -Check Database -Show Detailed -Verbose Invoke-DbcCheck -Check DatabaseCollation,SuspectPage Invoke-DbcCheck -Check SuspectPage -Show Detailed Invoke-DbcCheck -Check TestLastBackup -Show Detailed Invoke-DbcCheck -Check TestLastBackupVerifyOnly -Show Detailed Invoke-DbcCheck -Check ValidDatabaseOwner -Show Detailed Invoke-DbcCheck -Check InvalidDatabaseOwner -Show Detailed Invoke-DbcCheck -Check LastGoodCheckDb -Show Detailed Invoke-DbcCheck -Check IdentityUsage -Show Detailed Invoke-DbcCheck -Check RecoveryModel -Show Detailed Invoke-DbcCheck -Check DuplicateIndex -Show Detailed Invoke-DbcCheck -Check UnusedIndex -Show Detailed Invoke-DbcCheck -Check DisabledIndex -Show Detailed Invoke-DbcCheck -Check DatabaseGrowthEvent -Show Detailed Invoke-DbcCheck -Check PageVerify -Show Detailed Invoke-DbcCheck -Check AutoClose -Show Detailed Invoke-DbcCheck -Check AutoShrink -Show Detailed Invoke-DbcCheck -Check LastFullBackup -Show Detailed Invoke-DbcCheck -Check LastDiffBackup -Show Detailed Invoke-DbcCheck -Check LastLogBackup -Show Detailed Invoke-DbcCheck -Check LogfilePercentUsed -Show Detailed Invoke-DbcCheck -Check VirtualLogFile -Show Detailed Invoke-DbcCheck -Check LogfileCount -Show Detailed Invoke-DbcCheck -Check LogfileSize -Show Detailed Invoke-DbcCheck -Check FutureFileGrowth -Show Detailed Invoke-DbcCheck -Check FileGroupBalanced -Show Detailed Invoke-DbcCheck -Check CertificateExpiration -Show Detailed Invoke-DbcCheck -Check AutoCreateStatistics -Show Detailed Invoke-DbcCheck -Check AutoUpdateStatistics -Show Detailed Invoke-DbcCheck -Check AutoUpdateStatisticsAsynchronously -Show Detailed Invoke-DbcCheck -Check DatafileAutoGrowthType -Show Detailed Invoke-DbcCheck -Check Trustworthy -Show Detailed Invoke-DbcCheck -Check OrphanedUser -Show Detailed Invoke-DbcCheck -Check PseudoSimple -Show Detailed Invoke-DbcCheck -Check CompatibilityLevel -Show Detailed Invoke-DbcCheck -Check FKCKTrusted -Show Detailed Invoke-DbcCheck -Check MaxDopDatabase -Show Detailed Invoke-DbcCheck -Check DatabaseStatus -Show Detailed Invoke-DbcCheck -Check DatabaseExists -Show Detailed Invoke-DbcCheck -Check ContainedDBAutoClose -Show Detailed Invoke-DbcCheck -Check CLRAssembliesSafe -Show Detailed Invoke-DbcCheck -Check GuestUserConnect -Show Detailed Invoke-DbcCheck -Check AsymmetricKeySize -Show Detailed Invoke-DbcCheck -Check SymmetricKeyEncryptionLevel -Show Detailed Invoke-DbcCheck -Check ContainedDBSQLAuth -Show Detailed Invoke-DbcCheck -Check QueryStoreEnabled -Show Detailed Invoke-DbcCheck -Check QueryStoreDisabled -Show Detailed #endregion #region Agent Invoke-DbcCheck -Check DatabaseMailEnabled -Show Detailed Invoke-DbcCheck -Check AgentServiceAccount -Show Detailed Invoke-DbcCheck -Check DbaOperator -Show Detailed Invoke-DbcCheck -Check FailsafeOperator -Show Detailed Invoke-DbcCheck -Check DatabaseMailProfile -Show Detailed Invoke-DbcCheck -Check AgentMailProfile -Show Detailed Invoke-DbcCheck -Check FailedJob -Show Detailed Invoke-DbcCheck -Check ValidJobOwner -Show Detailed Invoke-DbcCheck -Check AgentAlert -Show Detailed Invoke-DbcCheck -Check JobHistory -Show Detailed Invoke-DbcCheck -Check LongRunningJob -Show Detailed Invoke-DbcCheck -Check LastJobRunTime -Show Detailed #endregion # multiple tags same group Invoke-DbcCheck -Check AutoClose -Show All $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $Sqlinstances = 'localhost,7401','localhost,7402','localhost,7403' $sql1 = Connect-DbaInstance -SqlInstance $Sqlinstances[0] -SqlCredential $cred $sql2 = Connect-DbaInstance -SqlInstance $Sqlinstances[1] -SqlCredential $cred $sql3 = Connect-DbaInstance -SqlInstance $Sqlinstances[2] -SqlCredential $cred Get-DbcConfig -Name agent.validjobowner.name Set-DbcConfig -Name agent.validjobowner.name -Value 'NotRob','NotGrilliam','ProperJobOwnerAccount','OldNamingConventionJobAccount' Invoke-DbcCheck -SqlInstance $sql1 -Check ValidJobOwner -SqlCredential $cred New-DbaLogin $sql1,$sql2,$sql3 -Login Monica New-DbaLogin $sql1,$sql2,$sql3 -Login 'ProperJobOwnerAccount' Set-DbaAgentJobOwner -SqlInstance $sql1,$sql2,$sql3 -Job 'IndexOptimize - USER_DATABASES' -Login Monica Set-DbaAgentJobOwner -SqlInstance $sql1,$sql2,$sql3 -Login 'NotGrilliam' # Dirks Bye, I am leaving script Set-DbaAgentJobOwner -SqlInstance $sql1 -Login 'ProperJobOwnerAccount' Invoke-DbcCheck -SqlInstance $Sqlinstances[0] -Check ValidJobOwner -SqlCredential $cred ================================================ FILE: developing/Archive/tests/Help.Exceptions.ps1 ================================================ # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQURIsqjzNuCvaywTsb60Hh+CAY # Y4qgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTFUYzHsE17PItd1Khf0qg2Dqat # 9jANBgkqhkiG9w0BAQEFAASCAQAPdXXxD4YAvhd8nAB7d7SWo7VQrWSjvcJRaLFk # iuH9VepbSVt1kv2FGKtnKalps+vdeELzRXZRnAuBRfN5wv6UDaD8dCAhiEK0IIf2 # NIGvdGS9h0NXE72y/Hvu43Pxt/IP561v6Fg/9XDkpiWixjlNxxeviFjz3xvRBUH6 # Fy2qndHhkUy7bsk9L9VJNxdvgq9ntGik+wo0InpBs2u4WxlDKaDWAUJWWit3F3CA # /l7L8r0YPyx1SDJy7vp3doHfwDBXyFFXtgF1feB4jXPtoOIkTxw91Ocsoz1/3mcR # meUXyjJ6SaZAha9WiiVvgbwbKy+ulVMff77Rn4DEKjpntovl # SIG # End signature block ================================================ FILE: developing/Archive/tests/InModule.Help.Exceptions.ps1 ================================================ [cmdletbinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '', Justification='Because scoping is hard')] Param() $global:FunctionHelpTestExceptions = @( "TabExpansion2" ) $global:HelpTestEnumeratedArrays = @( "Sqlcollaborative.Dbatools.Connection.ManagementConnectionType[]" ) $global:HelpTestSkipParameterType = @{ "Get-DbaCmObject" = @("DoNotUse") "Test-DbaCmConnection" = @("Type") "Get-DbaService" = @("DoNotUse") } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUNNIazwQfl2xajO7JyHJo7cPI # CpugggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQFFwaLnMUX0kiOXOYGtmz1bk+d # IzANBgkqhkiG9w0BAQEFAASCAQAm/TbPQzhs+uJgI6y3GFK/IwC7E6Llai9KErbT # eDHP7rRtHKC0mHBXskco8xG6qnNYGq02jB9zBbbRHyJ6IVPAZoFCa1J1yzNYK9RV # 8T3Fy4/PbEpmB3QrmlD0BDVePYofI1CIDaX21+FiGPCKe6awT4J0c/RbUjpe7Ftc # nGzdhWdrXzir6DDG3zIIIyEzBcRrRPRBw+deNcU8BhqpjswHncbpZVutCs/9yuxQ # 2yOus5rRm5cbPZJHo7spdc18Cn8+cvz6dusa/OOrXhtVspZ3QiQMmlQVY5kZbmzs # fuCoDFIc6gr/O7pIfaCQmX5GpgxVvGBRYXPxCuvz/pS8GFc9 # SIG # End signature block ================================================ FILE: developing/Archive/tests/InModule.Help.Tests.ps1 ================================================ [cmdletbinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '', Justification='Because scoping is hard')] Param() <# .NOTES =========================================================================== Created with: SAPIEN Technologies, Inc., PowerShell Studio 2016 v5.2.119 Created on: 4/12/2016 1:11 PM Created by: June Blender Organization: SAPIEN Technologies, Inc Filename: *.Help.Tests.ps1 =========================================================================== .DESCRIPTION To test help for the commands in a module, place this file in the module folder. To test any module from any path, use https://github.com/juneb/PesterTDD/Module.Help.Tests.ps1 #> if ($SkipHelpTest) { return } . "$PSScriptRoot\InModule.Help.Exceptions.ps1" $ModuleBase = Split-Path -Parent $MyInvocation.MyCommand.Path # This should stop people making breaking changes to the tests without first altering the test Remove-Module dbachecks -Force -ErrorAction SilentlyContinue Import-Module $ModuleBase\..\dbachecks.psd1 $includedNames = (Get-ChildItem "$PSScriptRoot\..\functions" | Where-Object Name -like "*.ps1" ).BaseName $commands = Get-Command -Module (Get-Module dbachecks) -CommandType Cmdlet, Function | Where-Object Name -in $includedNames ## When testing help, remember that help is cached at the beginning of each session. ## To test, restart session. foreach ($command in $commands) { $commandName = $command.Name # Skip all functions that are on the exclusions list if ($global:FunctionHelpTestExceptions -contains $commandName) { continue } # The module-qualified command fails on Microsoft.PowerShell.Archive cmdlets $Help = Get-Help $commandName -ErrorAction SilentlyContinue $testhelperrors = 0 $testhelpall = 0 Describe "Test help for $commandName" -Tag Help{ $testhelpall += 1 if ($Help.Synopsis -like '*`[``]*') { # If help is not found, synopsis in auto-generated help is the syntax diagram It "should not be auto-generated" { $Help.Synopsis | Should Not BeLike '*`[``]*' } $testhelperrors += 1 } $testhelpall += 1 if ([String]::IsNullOrEmpty($Help.Description.Text)) { # Should -Be a description for every function It "gets description for $commandName" { $Help.Description | Should Not BeNullOrEmpty } $testhelperrors += 1 } $testhelpall += 1 if ([String]::IsNullOrEmpty(($Help.Examples.Example | Select-Object -First 1).Code)) { # Should -Be at least one example It "gets example code from $commandName" { ($Help.Examples.Example | Select-Object -First 1).Code | Should Not BeNullOrEmpty } $testhelperrors += 1 } $testhelpall += 1 if ([String]::IsNullOrEmpty(($Help.Examples.Example.Remarks | Select-Object -First 1).Text)) { # Should -Be at least one example description It "gets example help from $commandName" { ($Help.Examples.Example.Remarks | Select-Object -First 1).Text | Should Not BeNullOrEmpty } $testhelperrors += 1 } if ($testhelperrors -eq 0) { It "Ran silently $testhelpall tests" { $testhelperrors | Should -Be 0 } } $testparamsall = 0 $testparamserrors = 0 Context "Test parameter help for $commandName" { $Common = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable', 'Confirm', 'WhatIf' $parameters = $command.ParameterSets.Parameters | Where-Object {$psitem.IsDynamic -eq $false} | Sort-Object -Property Name -Unique | Where-Object Name -notin $common $parameterNames = $parameters.Name $HelpParameterNames = ($Help.Parameters.Parameter | Sort-Object -Unique | Where-Object Name -notin $common).Name foreach ($parameter in $parameters) { $parameterName = $parameter.Name $parameterHelp = $Help.parameters.parameter | Where-Object Name -EQ $parameterName $testparamsall += 1 if ([String]::IsNullOrEmpty($parameterHelp.Description.Text)) { # Should -Be a description for every parameter It "gets help for parameter: $parameterName : in $commandName" { $parameterHelp.Description.Text | Should Not BeNullOrEmpty } $testparamserrors += 1 } $testparamsall += 1 $codeMandatory = $parameter.IsMandatory.toString() if ($parameterHelp.Required -ne $codeMandatory) { # Required value in Help should match IsMandatory property of parameter It "help for $parameterName parameter in $commandName has correct Mandatory value" { $parameterHelp.Required | Should -Be $codeMandatory } $testparamserrors += 1 } if ($HelpTestSkipParameterType[$commandName] -contains $parameterName) { continue } $codeType = $parameter.ParameterType.Name $testparamsall += 1 if ($parameter.ParameterType.IsEnum) { # Enumerations often have issues with the typename not being reliably available $names = $parameter.ParameterType::GetNames($parameter.ParameterType) if ($parameterHelp.parameterValueGroup.parameterValue -ne $names) { # Parameter type in Help should match code It "help for $commandName has correct parameter type for $parameterName" { $parameterHelp.parameterValueGroup.parameterValue | Should -Be $names } $testparamserrors += 1 } } elseif ($parameter.ParameterType.FullName -in $HelpTestEnumeratedArrays) { # Enumerations often have issues with the typename not being reliably available $names = [Enum]::GetNames($parameter.ParameterType.DeclaredMembers[0].ReturnType) if ($parameterHelp.parameterValueGroup.parameterValue -ne $names) { # Parameter type in Help should match code It "help for $commandName has correct parameter type for $parameterName" { $parameterHelp.parameterValueGroup.parameterValue | Should -Be $names } $testparamserrors += 1 } } else { # To avoid calling Trim method on a null object. $helpType = if ($parameterHelp.parameterValue) { $parameterHelp.parameterValue.Trim() } if ($helpType -ne $codeType ) { # Parameter type in Help should match code It "help for $commandName has correct parameter type for $parameterName" { $helpType | Should -Be $codeType } $testparamserrors += 1 } } } foreach ($helpParm in $HelpParameterNames) { $testparamsall += 1 if ($helpParm -notin $parameterNames) { # Shouldn't find extra parameters in help. It "finds help parameter in code: $helpParm" { $helpParm -in $parameterNames | Should -BeTrue } $testparamserrors += 1 } } if ($testparamserrors -eq 0) { It "Ran silently $testparamsall tests" { $testparamserrors | Should -Be 0 } } } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUOQn6XAVOZu8FeBq7y4vF/V80 # Ql+gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBSpQbpEdfnW1M5JjD64yU8Znowk # wDANBgkqhkiG9w0BAQEFAASCAQAoX/M2RgLM/kBzs2Xur4w685CT6/OQDx62w/zb # 3xAswvDioABnxZmhjIbszBFRjn7rTxtoPa67GlPl2BI4OD+LZNv8aTVkep+PxrZW # ZzJ4XcYQHgdIlT3AGmLVYQseeLNbJBaeWNNuxTFkRhvk6lGHT30K/jMBjYr776LX # 2qJxNeGLQP/JZxjLWRTalPZxxanrG+hsnM3n+soVhLnLZndIJ6CP+JLzDti9U4+z # j5XoyG1wIIEL1gbqAplNc6g/2xbqburtmZVhkG/4mczp7FWyhIWnSaNG/aX8Z+1G # O8Q4dkiV7eMLQgeMopXUJWxVNBv/dVVL31QaQu76S77SI4jX # SIG # End signature block ================================================ FILE: developing/Archive/tests/Integration/DockerTests.ps1 ================================================ [cmdletbinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification='Because they are used just parsed')] Param() <# # Need to create a credential to be saved using user sa and password Password0! by running Get-Credential | Export-Clixml -Path $CredentialPath #> $CredentailPath = 'C:\MSSQL\BACKUP\KEEP\sacred.xml' $dbacheckslocalpath = 'GIT:\dbachecks\' #region setup Write-PSFMessage "Removing Modules" -Level Significant Remove-Module dbatools, dbachecks, PSFramework -ErrorAction SilentlyContinue Write-PSFMessage "Importing from source control" -Level Significant Import-Module $dbacheckslocalpath\dbachecks.psd1 Write-PSFMessage "Resetting dbachecks config" -Level Significant $null = Reset-DbcConfig $PSDefaultParameterValues += @{ 'Write-PSFMessage:Level' = 'Output'} # setting for messages to screen Set-Location $dbacheckslocalpath\tests\Integration Write-PSFMessage "resetting docker-compose to save Rob from troubleshooting for hours because the containers already existed" docker-compose down Write-PSFMessage "Starting containers" try { $ErrorActionPreference = 'Stop' docker-compose up -d $ErrorActionPreference = 'Continue' } catch { $ErrorActionPreference = 'Continue' Return } $containers = 'localhost,15589', 'localhost,15588', 'localhost,15587', 'localhost,15586' $cred = Import-Clixml $CredentailPath Write-PSFMessage "Setting default configs" $null = Set-DbcConfig -Name app.sqlinstance $containers $null = Set-DbcConfig -Name policy.connection.authscheme -Value SQL $null = Set-DbcConfig -Name policy.network.latencymaxms -Value 150 # because the containers run a bit slow! $null = Set-DbcConfig -Name skip.connection.auth -Value $true ## Ensure that SQLAgent is started - SQL2014 agent wont start in container Write-PSFMessage "Starting SQL Agent on all containers except SQL2014" docker exec -ti integration_sql2012_1 powershell start-service SQLSERVERAGENT docker exec -ti integration_sql2016_1 powershell start-service SQLSERVERAGENT docker exec -ti integration_sql2017_1 powershell start-service SQLSERVERAGENT #endregion #region Pester Functions function Invoke-DefaultCheck { It "All Checks should pass with default for $Check" { $Tests = get-variable "$($Check)default" -ValueOnly $Tests.FailedCount | Should -Be 0 -Because "We expect all of the checks to run and pass with default setting (Yes we may set some values before but you get my drift)" } } function Invoke-ConfigCheck { It "All Checks should fail when config changed for $Check" { $Tests = get-variable "$($Check)configchanged" -ValueOnly $Tests.PassedCount | Should -Be 0 -Because "We expect all of the checks to run and fail when we have changed the config values" } } function Invoke-ValueCheck { It "All Checks should pass when setting changed for $Check" { $Tests = get-variable "$($Check)valuechanged" -ValueOnly $Tests.FailedCount | Should -Be 0 -Because "We expect all of the checks to run and pass when we have changed the settings to match the config values" } } #endregion # make sure the containers are up and running Write-PSFMessage "Default connectivity check" $ConnectivityTests = Invoke-DbcCheck -SqlCredential $cred -Check Connectivity -Show None -PassThru #region error Log Count - PR 583 # default test Write-PSFMessage "Checking ErrorLogCount default" $errorlogscountdefault = Invoke-DbcCheck -SqlCredential $cred -Check ErrorLogCount -Show None -PassThru # set a value and then it will fail Write-PSFMessage "Checking ErrorLogCount config changed" $null = Set-DbcConfig -Name policy.errorlog.logcount -Value 10 $errorlogscountconfigchanged = Invoke-DbcCheck -SqlCredential $cred -Check ErrorLogCount -Show None -PassThru # set the value and then it will pass Write-PSFMessage "Checking ErrorLogCount value changed" $null = Set-DbaErrorLogConfig -SqlInstance $containers -SqlCredential $cred -LogCount 10 $errorlogscountvaluechanged = Invoke-DbcCheck -SqlCredential $cred -Check ErrorLogCount -Show None -PassThru #endregion #region Job History Count PR 582 # run the checks against these instances (SQL2014 agent wont start :-( )) Write-PSFMessage "Checking JobHistory default" $null = Set-DbcConfig -Name app.sqlinstance $containers.Where{$_ -ne 'localhost,15588'} # by default all tests should pass on default instance settings $jobhistorydefault = Invoke-DbcCheck -SqlCredential $cred -Check JobHistory -Show None -PassThru #Change the configuration to test that the checks fail Write-PSFMessage "Checking JobHistory config changed" $null = Set-DbcConfig -Name agent.history.maximumjobhistoryrows -value 1000 $null = Set-DbcConfig -Name agent.history.maximumhistoryrows -value 10000 $jobhistoryconfigchanged = Invoke-DbcCheck -SqlCredential $cred -Check JobHistory -Show None -PassThru Write-PSFMessage "Checking JobHistory value changed" $setDbaAgentServerSplat = @{ MaximumJobHistoryRows = 1000 MaximumHistoryRows = 10000 SqlInstance = $containers.Where{$_ -ne 'localhost,15588'} SqlCredential = $cred } $null = Set-DbaAgentServer @setDbaAgentServerSplat $jobhistoryvaluechanged = Invoke-DbcCheck -SqlCredential $cred -Check JobHistory -Show None -PassThru #endregion #region BackupPathAccess # run the checks against these instances Write-PSFMessage "Checking BackupPathAccess default" $null = Set-DbcConfig -Name app.sqlinstance $containers # by default all tests should pass on default instance settings $BackupPathAccessdefault = Invoke-DbcCheck -SqlCredential $cred -Check BackupPathAccess -Show None -PassThru #Change the configuration to test that the checks fail Write-PSFMessage "Checking BackupPathAccess config changed" $null = Set-DbcConfig -Name policy.storage.backuppath -value 'C:\Windows\temp\a' ## Setting to an invalid unaccessible folder $BackupPathAccessconfigchanged = Invoke-DbcCheck -SqlCredential $cred -Check BackupPathAccess -Show None -PassThru Write-PSFMessage "Checking BackupPathAccess value changed" foreach ($container in $containers) { $Instance = Connect-DbaInstance -SqlInstance $container -SqlCredential $cred $Instance.BackupDirectory = 'C:\Windows\temp\' $Instance.Alter() } $null = Set-DbcConfig -Name policy.storage.backuppath -value 'C:\Windows\temp\' $BackupPathAccessvaluechanged = Invoke-DbcCheck -SqlCredential $cred -Check BackupPathAccess -Show None -PassThru #endregion #region DAC # run the checks against these instances Write-PSFMessage "Checking DAC default" $null = Set-DbcConfig -Name app.sqlinstance $containers foreach($container in $containers){ $null = Set-DbaSpConfigure -SqlInstance $container -SqlCredential $cred -Name RemoteDACConnectionsEnabled -Value 1 ## because it is set to false by default but dbachecks uses true as default } # by default all tests should pass on default instance settings $DACdefault = Invoke-DbcCheck -SqlCredential $cred -Check DAC -Show None -PassThru #Change the configuration to test that the checks fail Write-PSFMessage "Checking DAC config changed" $null = Set-DbcConfig -Name policy.dacallowed -value $false $DACconfigchanged = Invoke-DbcCheck -SqlCredential $cred -Check DAC -Show None -PassThru Write-PSFMessage "Checking DAC value changed" foreach($container in $containers){ $null = Set-DbaSpConfigure -SqlInstance $container -SqlCredential $cred -Name RemoteDACConnectionsEnabled -Value 0 } $DACvaluechanged = Invoke-DbcCheck -SqlCredential $cred -Check DAC -Show None -PassThru #endregion Write-PSFMessage "Running Pester Tests ........." Describe "Testing the checks are running as expected" -Tag Integration { Context "Connectivity Checks" { It "All Tests should pass" { $ConnectivityTests.FailedCount | Should -Be 0 -Because "We expect all of the checks to run and pass with default settings" } } $TestingTheChecks = @('errorlogscount', 'jobhistory', 'BackupPathAccess', 'DAC') Foreach ($Check in $TestingTheChecks) { Context "$Check Checks" { Invoke-DefaultCheck Invoke-ConfigCheck INvoke-ValueCheck } } } Write-PSFMessage "Finished running Pester Tests" # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUoCglQhb3cpQGiNZYDTV1Zn/l # ovSgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTKEaVMVkW7Jpz69FG46ZV+gDZt # PzANBgkqhkiG9w0BAQEFAASCAQAzXtLiTNHXRqbcTmsc3msXu0zewS4iyx5HYrN8 # /RAVu8JCx5SgRScDYgTQt35k4VpmDMF2fPXnPnpGjmg+VmghYKNFVXE+h+l+3Ale # bKQb7pnLVkPqjtU2JMdSvJd1rKHePV7PBNIHTtsyM19c4tVH3CGupUzGrRWL09CZ # K2K8FmSU9cPypWrNcuzHA4fAqxuBRecps48NIdEWtjKxFmwXUo6pPOTpwRSL3hxU # 0eDp8woA0JrH0ao4JcJ2/epKewiOb9XQKV0GdhAIJUczK7jA9lA5U083INMIf4jc # jx2+VHF4IAtbrA+q78L9MEjfLHqmdHMS9jTdvGbFyFH/plce # SIG # End signature block ================================================ FILE: developing/Archive/tests/Integration/docker-compose.yml ================================================ version: '3.7' services: sql2012: image: dbafromthecold/sqlserver2012dev:sp4 ports: - "15589:1433" environment: SA_PASSWORD: "Password0!" ACCEPT_EULA: "Y" sql2014: image: dbafromthecold/sqlserver2014dev:sp2 ports: - "15588:1433" environment: SA_PASSWORD: "Password0!" ACCEPT_EULA: "Y" sql2016: image: dbafromthecold/sqlserver2016dev:sp2 ports: - "15587:1433" environment: SA_PASSWORD: "Password0!" ACCEPT_EULA: "Y" sql2017: image: microsoft/mssql-server-windows-developer:2017-latest ports: - "15586:1433" environment: SA_PASSWORD: "Password0!" ACCEPT_EULA: "Y" ================================================ FILE: developing/Archive/tests/Project.Tests.ps1 ================================================ $packages = get-package if ($packages.Name -contains "PSScriptAnalyzer") { #PSScriptAnalyzer is installed on the system } else { Write-Output "Installing latest version of PSScriptAnalyzer" #install PSScriptAnalyzer Install-Package PSScriptAnalyzer -Force -Scope CurrentUser } $script:ModuleName = 'dbachecks' # Removes all versions of the module from the session before importing Get-Module $ModuleName | Remove-Module $ModuleBase = Split-Path -Parent $MyInvocation.MyCommand.Path $FunctionHelpTestExceptions = Get-Content -Path "$ModuleBase\Help.Exceptions.ps1" # For tests in .\Tests subdirectory if ((Split-Path $ModuleBase -Leaf) -eq 'Tests') { $ModuleBase = Split-Path $ModuleBase -Parent } Import-Module $ModuleBase\$ModuleName.psd1 -PassThru -ErrorAction Stop | Out-Null Describe "PSScriptAnalyzer rule-sets" -Tag Build , ScriptAnalyzer { $Rules = Get-ScriptAnalyzerRule $scripts = Get-ChildItem $ModuleBase -Include *.ps1, *.psm1, *.psd1 -Recurse | Where-Object fullname -notmatch 'classes' # Get last commit that was merged from master $lastCommit = git log --grep="Updated Version Number and docs from master" -1 --format='%H' # Get the files that have been altered in since the last merge from master $scripts= git diff --name-only $lastCommit HEAD | Where-Object {$psitem.EndsWith('ps1')} foreach ( $Script in $scripts ) { if (-not (Test-Path "$ModuleBase\$script")){continue} Context "Checking PSScriptAnalyzer on Script '$script'" { foreach ( $rule in $rules ) { # Skip all rules that are on the exclusions list if ($FunctionHelpTestExceptions -contains $rule.RuleName) { continue } It "The Script Analyzer Rule [$rule] Should not fail" { $rulefailures = Invoke-ScriptAnalyzer -Path "$ModuleBase\$script" -IncludeRule $rule.RuleName -Settings $ModuleBase\PSScriptAnalyzerSettings.psd1 $message = ($rulefailures | Select-Object Message -Unique).Message $lines = $rulefailures.Line -join ',' $rulefailures.Count | Should -Be 0 -Because "Script Analyzer says the rules have been broken on lines $lines with Message '$message' Check in VSCode Problems tab or Run Invoke-ScriptAnalyzer -Script $ModuleBase\$script -Settings $ModuleBase\PSScriptAnalyzerSettings.psd1" } } } } } Describe "General project validation: $moduleName" -Tags Build { BeforeAll { Get-Module $ModuleName | Remove-Module } It "Module '$moduleName' can import cleanly" { {Import-Module $ModuleBase\$ModuleName.psd1 -force } | Should Not Throw } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUxwL6BlbCJrUPKh9/064YSyLQ # bH6gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTyAuclgIYUbsmTj2tRBEmsq+b5 # fDANBgkqhkiG9w0BAQEFAASCAQB8n0L9j9FDdOLpm+9ydGQ7GwDoJNHKMn8xBpqm # HPfgeDJM6BRq1l6FErFjOqd7iDh2fFn+5OAii9WrYRq3gOl4dmwiTS0pKPo4xeq5 # +jWt12+CRtWjFKfQW3XPLsVi7cmKivVLdSzzU6Uu59V42sCARQSIDyJ4ggiV1TLh # baZduC65AZhvauATaLUfId0zKOih5f3RXtLoNqUgXYhyZNlHzWUXJ48mXiBMz4nu # Q2nmbpYhfBx8bmapW5p9VFj3bcTUR9hvLQNRH2/+7NA7UQJ89szX3oQS29P1tcuC # Qp9Kwel0cjYJrSqmvEa7kS3VDAKjzBuarTlr1L/M1MNGPrKN # SIG # End signature block ================================================ FILE: developing/Archive/tests/Reset-DbcConfig.Tests.ps1 ================================================ [cmdletbinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingInvokeExpression', '', Justification='because rightnow I cant be bothered to look at it')] Param() $testSettingsDefinition = ' # config needed for testing Set-PSFConfig -Module dbachecks -Name testing.samplesettingforunittest.a -Value "DefaultValueA" -Initialize -Description "This setting is only to validate Reset-DbcConfig" Set-PSFConfig -Module dbachecks -Name testing.samplesettingforunittest.b -Value "DefaultValueB" -Initialize -Description "This setting is only to validate Reset-DbcConfig" Set-PSFConfig -Module dbachecks -Name testing.samplesettingforunittest.group.a -Value "DefaultValueA" -Initialize -Description "This setting is only to validate Reset-DbcConfig" Set-PSFConfig -Module dbachecks -Name testing.samplesettingforunittest.group.b -Value "DefaultValueB" -Initialize -Description "This setting is only to validate Reset-DbcConfig" ' Invoke-Expression $testSettingsDefinition Describe "Testing Reset-DbcConfig" { InModuleScope -Module dbachecks { Mock Invoke-ConfigurationScript { Invoke-Expression ' # config needed for testing Set-PSFConfig -Module dbachecks -Name testing.samplesettingforunittest.a -Value "DefaultValueA" -Initialize -Description "This setting is only to validate Reset-DbcConfig" Set-PSFConfig -Module dbachecks -Name testing.samplesettingforunittest.b -Value "DefaultValueB" -Initialize -Description "This setting is only to validate Reset-DbcConfig" Set-PSFConfig -Module dbachecks -Name testing.samplesettingforunittest.group.a -Value "DefaultValueA" -Initialize -Description "This setting is only to validate Reset-DbcConfig" Set-PSFConfig -Module dbachecks -Name testing.samplesettingforunittest.group.b -Value "DefaultValueB" -Initialize -Description "This setting is only to validate Reset-DbcConfig" ' } It "Resetting specific setting works" { Set-DbcConfig -Name testing.samplesettingforunittest.a -Value "newvalue" (Get-DbcConfigValue -Name testing.samplesettingforunittest.a) | Should -Be "newvalue" Reset-DbcConfig -Name testing.samplesettingforunittest.a (Get-DbcConfigValue -Name testing.samplesettingforunittest.a) | Should -Be "DefaultValueA" } It "Resetting specific setting doesn't change anything else" { Set-DbcConfig -Name testing.samplesettingforunittest.a -Value "newvalue" Set-DbcConfig -Name testing.samplesettingforunittest.b -Value "customvalue" (Get-DbcConfigValue -Name testing.samplesettingforunittest.b) | Should -Be "customvalue" Reset-DbcConfig -Name testing.samplesettingforunittest.a (Get-DbcConfigValue -Name testing.samplesettingforunittest.a) | Should -Be "DefaultValueA" (Get-DbcConfigValue -Name testing.samplesettingforunittest.b) | Should -Be "customvalue" } It "Resetting with wildcard resets all matching settings" { Set-DbcConfig -Name testing.samplesettingforunittest.group.a -Value "newvalue1" Set-DbcConfig -Name testing.samplesettingforunittest.group.b -Value "newvalue2" Set-DbcConfig -Name testing.samplesettingforunittest.b -Value "customvalue" (Get-DbcConfigValue -Name testing.samplesettingforunittest.group.a) | Should -Be "newvalue1" (Get-DbcConfigValue -Name testing.samplesettingforunittest.group.b) | Should -Be "newvalue2" (Get-DbcConfigValue -Name testing.samplesettingforunittest.b) | Should -Be "customvalue" Reset-DbcConfig -Name "testing.samplesettingforunittest.group.*" (Get-DbcConfigValue -Name testing.samplesettingforunittest.group.a) | Should -Be "DefaultValueA" (Get-DbcConfigValue -Name testing.samplesettingforunittest.group.b) | Should -Be "DefaultValueB" (Get-DbcConfigValue -Name testing.samplesettingforunittest.b) | Should -Be "customvalue" } It "Resetting with wildcard resets only matching settings" { Set-DbcConfig -Name testing.samplesettingforunittest.b -Value "customvalue" (Get-DbcConfigValue -Name testing.samplesettingforunittest.b) | Should -Be "customvalue" Reset-DbcConfig -Name testing.samplesettingforunittest.group.* (Get-DbcConfigValue -Name testing.samplesettingforunittest.b) | Should -Be "customvalue" } Mock Get-DbcConfig { param([string]$Name = "*") process { $results = [PSFramework.Configuration.ConfigurationHost]::Configurations.Values | Where-Object { ($_.Name.startswith("testing.samplesettingforunittest.")) -and ($_.Name -like $Name) -and ($_.Module -like "dbachecks") } | Sort-Object Module, Name return $results | Select-Object Name, Value, Description } } It "Resetting all resets really all" { Set-DbcConfig -Name testing.samplesettingforunittest.group.a -Value "newvalue1" Set-DbcConfig -Name testing.samplesettingforunittest.group.b -Value "newvalue2" Set-DbcConfig -Name testing.samplesettingforunittest.b -Value "customvalue" (Get-DbcConfigValue -Name testing.samplesettingforunittest.group.a) | Should -Be "newvalue1" (Get-DbcConfigValue -Name testing.samplesettingforunittest.group.b) | Should -Be "newvalue2" (Get-DbcConfigValue -Name testing.samplesettingforunittest.b) | Should -Be "customvalue" Reset-DbcConfig (Get-DbcConfigValue -Name testing.samplesettingforunittest.group.a) | Should -Be "DefaultValueA" (Get-DbcConfigValue -Name testing.samplesettingforunittest.group.b) | Should -Be "DefaultValueB" (Get-DbcConfigValue -Name testing.samplesettingforunittest.b) | Should -Be "DefaultValueB" } } } # cleanup, we don't want those test configuration options left in the system # the cleanup from within AfterAll did not work, so it is here Reset-DbcConfig -Name testing.samplesettingforunittest.a Reset-DbcConfig -Name testing.samplesettingforunittest.b Reset-DbcConfig -Name testing.samplesettingforunittest.group.a Reset-DbcConfig -Name testing.samplesettingforunittest.group.b # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU3hbO6CI8W/M1qcw++tNBCLs0 # vnOgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBSXgbRjet+5yJGfXYhbhMNZOBK2 # jzANBgkqhkiG9w0BAQEFAASCAQAzbYMqyxH8pyY80OhG5yhxH1F0G1YABQR+agNM # ZDlwgakLEornYun9zdbxFOI4e3S3PiK3upnN8Cf0tDOCETqgS6Dmkj6SFPfXoGn+ # 2mWGtQjZjpD3mrO6s2YgvWozshBP1o5tJEL0S/JrEeXIqfo8aM9TEjIC8lcLMzSl # XYbBsja49DYbVMqEXDoWoGqF/mErfnSoA6aNJiY8Zw2quN+occ0RpSycTG3iOeLd # t/bdzOSB5qfAGuY/eSJ9ir6ApAAsXyOsjTqJihU9zpcVYzdRmi8ps4OPbFT0xEwD # uhdTxdncViT4yprsk1mKg8ESh5q3p2gEsRayDWOu9ybkrTtJ # SIG # End signature block ================================================ FILE: developing/Archive/tests/Test-SingleFile.ps1 ================================================ param( [Parameter(Mandatory = $true)] [string] $FileToTest ) $FileToTest = Resolve-Path $FileToTest $fileName = Split-Path $FileToTest -leaf Write-Verbose "File to test = $FileToTest" if ($FileName -like "*.tests.ps1") { $filename = $fileName -replace "tests\.ps1$", "ps1" $sourceDir = Join-Path $PSScriptRoot "Source" $functionFile = Get-ChildItem $sourceDir -Filter $fileName -Recurse | Select-Object -First 1 -ExpandProperty FullName $testFile = $FileToTest } else { $fileName = $fileName -replace ".ps1$", ".tests.ps1" $testFile = (Join-Path $PSScriptRoot "../Tests/functions/$fileName") $functionFile = $FileToTest } Invoke-Pester -Script $testFile -ExcludeTag Integration -CodeCoverage $functionFile -CodeCoverageOutputFile "$PSScriptRoot\cov.xml" # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUpB5aqYqtq9Xdt7AI7hSp9/E1 # UFygggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQigsELcdjhHQ3tbsquYEBMa/ni # qjANBgkqhkiG9w0BAQEFAASCAQCIbziIa15P9j/f52eqbXeA56/aPRMgfQaPIhl0 # pYOD22oW2MPTiTFroNc7XjBYu+T3d6FEryO6H7OBxAs2rVsYf9vKbVcPyfrE0v39 # /3xRAvhhlEV2+4VLHbE+YCnSayJnMJgXxruqqmVIXWcJKKmKKDlAFWTDzXMeA852 # f95wZ/r7Kd7styOrqn+JgKUTE9iqHdwDl04zJSVbau1AxD8JRw8MTcoNnDXdTuzK # qDj94G+fETrQQbvQ+tdMWHVqQ0IGD4sdrKFzt+BVOyBFfrsOR92MX05FEpK3UQuS # Tve0ZN+52pNYmlCic8zUxQbb5l3VrIa7BYHvy9+JPFOdDzOJ # SIG # End signature block ================================================ FILE: developing/Archive/tests/Unit.Tests.ps1 ================================================ $ModuleBase = Split-Path -Parent $MyInvocation.MyCommand.Path # For tests in .\Tests subdirectory if ((Split-Path $ModuleBase -Leaf) -eq 'Tests') { $ModuleBase = Split-Path $ModuleBase -Parent } # This should stop people making breaking changes to the tests without first altering the test Remove-Module dbachecks -Force -ErrorAction SilentlyContinue Import-Module $ModuleBase\dbachecks.psd1 $tokens = $null $errors = $null Describe "Checking that each dbachecks Pester test is correctly formatted for Power Bi and Coded correctly" -Tags UnitTest { $Checks = (Get-ChildItem $ModuleBase\checks) #.Where{$PSItem.Name -eq 'Agent.Tests.ps1'} $Checks.ForEach{ $CheckName = $psitem.Name $Check = Get-Content $PSItem.FullName -Raw Context "$($PSItem.Name) - Checking Describes titles and tags" { $UniqueTags = (Get-DbcCheck).UniqueTag ## This gets all of the code with a describe $Describes = [Management.Automation.Language.Parser]::ParseInput($check, [ref]$tokens, [ref]$errors). FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast.CommandElements -and $ast.CommandElements[0].Value -eq 'describe' }, $true) | ForEach-Object { $CE = $PSItem.CommandElements $secondString = ($CE | Where-Object { $PSItem.StaticType.name -eq 'string' })[1] $tagIdx = $CE.IndexOf(($CE | Where-Object ParameterName -eq 'Tags')) + 1 $tags = if ($tagIdx -and $tagIdx -lt $CE.Count) { $CE[$tagIdx].Extent } New-Object PSCustomObject -Property @{ Name = $secondString Tags = $tags } } @($describes).ForEach{ $title = $PSItem.Name.ToString().Trim('"').Trim('''') It "The Describe Title - $title - Should Use a double quote after the Describe" { $PSItem.Name.ToString().Startswith('"') | Should -BeTrue -Because 'You need to alter the title of the Describe - We need use double quotes for titles' $PSItem.Name.ToString().Endswith('"') | Should -BeTrue -Because 'You need to alter the title of the Describe - We need use double quotes for titles' } It "The Describe Title - $title - should use a plural for tags" { $PSItem.Tags | Should -Not -BeNullOrEmpty -Because 'You need to alter the tags parameter of the Describe - We use the plural of Tags' } # a simple test for no esses apart from statistics and Access!! if ($null -ne $PSItem.Tags) { $PSItem.Tags.Text.Split(',').Trim().Where{ ($PSItem -ne '$filename') -and ($PSItem -notlike '*statistics*') -and ($PSItem -notlike '*BackupPathAccess*') -and ($PSItem -notlike '*OlaJobs*') -and ($PSItem -notlike '*status*') -and ($PSItem -notlike '*exists') -and ($PSItem -notlike '*Ops') }.ForEach{ It "The Describe Title - $title - Tags parameter $PSItem should be Singular" { $PSItem.ToString().Endswith('s') | Should -BeFalse -Because 'You need to alter the tags for this Describe OR alter this test if the tag makes sense - Our coding standards say tags should be singular' } } It "The Describe Title - $title - The first Tag $($PSItem.Tags.Text.Split(',')[0]) should be in the unique Tags returned from Get-DbcCheck" { $UniqueTags | Should -Contain $PSItem.Tags.Text.Split(',')[0].ToString() -Because 'We need a unique tag for each test - Format should be -Tags space UniqueTag comma - Also if you are running this on a machine where dbachecks has already been imported previously try running reset-dbcconfig, which will create a new checks.json for Get-DbcCheck' } } else { It "The Describe Title - $title - You haven't used the Tags Parameter so we can't check the tags" { $false | Should -BeTrue -Because 'You need to alter the Describe - We use the Tags parameter' } } } } Context "$($PSItem.Name) - Checking Contexts" { ## Find the Contexts $Contexts = [Management.Automation.Language.Parser]::ParseInput($check, [ref]$tokens, [ref]$errors). FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast.CommandElements -and $ast.CommandElements[0].Value -eq 'Context' }, $true) | ForEach-Object { $CE = $PSItem.CommandElements $secondString = ($CE | Where-Object { $PSItem.StaticType.name -eq 'string' })[1] New-Object PSCustomObject -Property @{ Name = $secondString } } @($Contexts).ForEach{ $title = $PSItem.Name.ToString().Trim('"').Trim('''') It "The Context Title - $Title - Should end with `$PSItem (or `$clustername) So that the PowerBi will work correctly" { $PSItem.Name.ToString().Endswith('psitem"') -or $PSItem.Name.ToString().Endswith('clustername"') -or $PSItem.Name.ToString().Endswith('SqlInstance"') | Should -BeTrue -Because 'You need to alter the title of the Context - This helps the PowerBi to parse the data' } } } Context "$($PSItem.Name) - Checking the Its" { $CheckName = $psitem.Name ## Find the Its $Its = [Management.Automation.Language.Parser]::ParseInput($check, [ref]$tokens, [ref]$errors). FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast.CommandElements -and $ast.CommandElements[0].Value -eq 'It' }, $true) | ForEach-Object { $CE = $PSItem.CommandElements $secondString = ($CE | Where-Object { $PSItem.StaticType.name -eq 'string' })[1] New-Object PSCustomObject -Property @{ Name = $secondString } } @($Its).ForEach{ $title = $PSItem.Name.ToString().Trim('"').Trim('''') It "The It Title - $Title - Should end with the right ending so that the PowerBi will work correctly" { $Lower = $PSItem.Name.ToString().ToLower() $Lower.Endswith('psitem"') -or $Lower.Endswith('clustername"') -or $Lower.EndsWith('server)"') -or $Lower.EndsWith('name)"') -or $Lower.EndsWith('name"') -or $Lower.EndsWith('instance"') -or $Lower.EndsWith('instance)"') -or $Lower.EndsWith('domain)"') -or $Lower.EndsWith('domain"') -or $Lower.EndsWith('replica)"') | Should -BeTrue -Because 'You need to alter the title of the It, it should end with the instance name or computername - This helps the PowerBi to parse the data' } if ($CheckName -eq 'Database.Tests.ps1') { It "The It Title - $Title - Should begin with - Database" { $PSItem.Name.ToString().StartsWith('"Database') -or $PSItem.Name.ToString().StartsWith('"Can') | Should -BeTrue -Because 'You need to alter the It Title to start with Database (or Can t Connect) - For the database checks we can parse them and make magic' } } } } Context "$($PSItem.Name) - Checking Code" { $CheckName = $psitem.Name ## This just grabs all the code $AST = [System.Management.Automation.Language.Parser]::ParseInput($Check, [ref]$null, [ref]$null) $Statements = $AST.EndBlock.statements.Extent ## Ignore the filename line @($Statements.Where{ $PSItem.StartLineNumber -ne 1 }).ForEach{ # make sure we only regex if the title contains a describe if ($PSItem.Text -match 'Describe') { $title = [regex]::matches($PSItem.text, "Describe(.*)-Tag").groups[1].value.Replace('"', '').Replace('''', '').trim() if ($title -ne 'Cluster $clustername Health using Node $clustervm') { It "Describe - $title - Should Use Get-Instance or Get-ComputerName" { ($PSItem.text -Match 'Get-Instance') -or ($PSItem.text -match 'Get-ComputerName') | Should -BeTrue -Because 'These are the commands to use to get Instances or Computers' } } if ($title -ne 'Cluster $clustername Health using Node $clustervm') { It "Describe - $title Should use the ForEach Method" { ($PSItem.text -match 'Get-Instance\).ForEach{' ) -or ($Psitem.text -match 'Get-ComputerName\).ForEach{' ) | Should -BeTrue # use the \ to escape the ) -Because 'We use the ForEach method in our coding standards' } } It "Describe - $title Should not use `$_" { ($PSItem.text -match '$_' ) | Should -BeFalse -Because '¬$psitem is the correct one to use' } if ($CheckName -ne 'Agent.Tests.ps1') { It "Describe - $title Should Contain a Context Block" { $PSItem.text -match 'Context' | Should -BeTrue -Because 'This helps the Power BI' } } else { $Contexts = [Management.Automation.Language.Parser]::ParseInput($check, [ref]$tokens, [ref]$errors). FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast.CommandElements -and $ast.CommandElements[0].Value -eq 'Context' }, $true) | ForEach-Object { $CE = $PSItem.CommandElements $secondString = ($CE | Where-Object { $PSItem.StaticType.name -eq 'string' })[1] New-Object PSCustomObject -Property @{ Name = $secondString } } It "$CheckName should have the right number of Context blocks as the AST doesnt parse how I like and I cant be bothered to fix it right now"{ $Contexts.Count | Should -Be 27 -Because "There should be 27 context blocks in the Agent checks file" } } } } } } (Get-DbcCheck).ForEach{ It "Should have one Unique Tag for each check" { $psitem.UniqueTag.Count | Should -Be 1 -Because "You need to check that the tags for this check - We want to only have one Unique Tag per test and we got $($psitem.UniqueTag) instead" } } } Describe "Checking that there is a description for each check" -Tags UnitTest { (Get-DbcCheck).ForEach{ It "$($psitem.UniqueTag) Should have a description in the DbcCheckDescriptions.json" { $psitem.description | Should -Not -BeNullOrEmpty -Because "We need a description in the .\internal\configurations\DbcCheckDescriptions.json for $($psitem.uniquetag) so that Get-DbcCheck shows it" } } } Describe "Each Config referenced in a check should exist" -Tags UnitTest { $dbcConfig = (Get-DbcConfig).Name ((Get-DbcCheck).Config.Split(' ') | Sort-Object -Unique).Where{ $Psitem -ne '' }.ForEach{ It "Config Value $psitem Should exist in Get-DbcConfig" { $Psitem | Should -BeIn $dbcConfig -Because "You need to look at the configurations as there appears to not be a unique tag" } } } Describe "Database Tests Exclusions" { $DbChecks = (Get-ChildItem $ModuleBase\checks).Where{ $PSItem.Name -eq 'Database.Tests.ps1' } $Check = Get-Content $DbChecks.FullName -Raw $Describes = [Management.Automation.Language.Parser]::ParseInput($check, [ref]$tokens, [ref]$errors). FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast.CommandElements -and $ast.CommandElements[0].Value -eq 'describe' }, $true) | ForEach-Object { $CE = $PSItem.CommandElements $secondString = ($CE | Where-Object { $PSItem.StaticType.name -eq 'string' })[1] [PSCustomObject] @{ Name = $secondString.Value Extent = $secondString.Parent.Extent.Text } } $Describes.ForEach{ It "$($Psitem.Name) should reference the global exclude configuration" { $psitem.Extent -like "*`$ExcludedDatabases*" | Should -BeTrue -Because "We need to exclude the databases specified in the config command.invokedbccheck.excludedatabases" } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUnG8fYYQ+n/6teg5vWZsCC5Ga # 1y6gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRJ2yB4Tm6Zaxb+gZab7tFGYsxW # 9TANBgkqhkiG9w0BAQEFAASCAQCCIcStyAb/yxOlY9t7GWaqEVgSZydVqjfbx/9O # m0TxalifwzRAVoMFufzivmRJdC4eCEHwa52JRQuFil0Ucmu0H/ITZk44NkhNjZk3 # FmV0EHKtkhhuMyEObzeVqzz4htjDobLbjfsu/IvP7NEAznq5MrDRgfFz/L4Ndyyt # wD53mmsQtGoX9OWgL14gKxQZhxbzNJV72f9VFfBWcZ5Zcxh4foerG2jikAtyeH93 # vfeEiPewVvTtR9NzKQmRz9nqKtRTUaZCPHeYIoGX0Sq2HdCfY6fRNt/cSOhrOr1N # JdrpoTCNdFA6oeEN7GMQ056XIjQCcYwaFWExQrqridnObxYu # SIG # End signature block ================================================ FILE: developing/Archive/tests/build/Initialize-VstsAgentOnWindowsServerCoreContainer.ps1 ================================================ ################################################################################################################## # Script Disclaimer ################################################################################################################## # This script is not supported under any Microsoft standard support program or service. # This script is provided AS IS without warranty of any kind. # Microsoft disclaims all implied warranties including, without limitation, any implied warranties of # merchantability or of fitness for a particular purpose. The entire risk arising out of the use or # performance of this script and documentation remains with you. In no event shall Microsoft, its authors, # or anyone else involved in the creation, production, or delivery of this script be liable for any damages # whatsoever (including, without limitation, damages for loss of business profits, business interruption, # loss of business information, or other pecuniary loss) arising out of the use of or inability to use # this script or documentation, even if Microsoft has been advised of the possibility of such damages. <# .SYNOPSIS This script creates ACI container instance(s) which run the Azure DevOps (formerly VSTS) Agent, alongside with the requested PowerShell modules, json2hcl and Terraform to enable Azure resource build automation from Azure DevOps CI/CD pipelines. .DESCRIPTION This script is used as a wrapper of the container configuration script ("Install-VstsAgentOnWindowsServerCoreContainer.ps1") to create ACI container instance(s) which run the Azure DevOps Agent, alongside with the requested PowerShell modules, json2hcl and Terraform to enable Azure resource build automation from Azure DevOps CI/CD pipelines. It copies the container configuration script to a publicly available storage container of the requested Storage Account, it creates a new Resource Group (if one doesn't exist with the provided name), removes any pre-existing ACI containers with the same name, within the same Resource Group, then creates new ACI container instance(s) based on the provided names and invokes the container configuration script inside the container(s). This script is designed and tested to be run from Azure Cloud Shell. Prerequisites: - Azure Subscription, with an existing Storage Account - You need to have **admin rights** : - to create a storage container within the already existing Storage Account *- OR -* you need to have a storage container which has its public access type configured to the type of "Blob", - to create a new Resource Group *- OR -* an existing Resource Group for the Azure Container Instances, - to create resources in the selected Resource Group. - Azure DevOps account with the requested Agent Pool has to exist. - Permission in the Azure DevOps account to add Agents to the chosen Agent Pool. - A PAT token. .PARAMETER SubscriptionName Name of the Subscription. .PARAMETER ResourceGroupName Name of the Resource Group. .PARAMETER ContainerName Name of the ACI container(s). .PARAMETER ReplaceExistingContainer Switch to replace existing container(s) with the same name(s) provided. .PARAMETER MemoryInGB Amount of memory in GBs. .PARAMETER Cpu Number of CPU cores. .PARAMETER Location Region of the Azure resources. .PARAMETER StorageAccountName Name of the Storage Account to upload the script file to, which is then invoke by this wrapper. .PARAMETER StorageContainerName Name of the storage container to upload the script file to be invoked by this wrapper. .PARAMETER ScriptPublicUrl Publicly available URL of the internal script file to be invoked by this wrapper. This can be used optionally, instead of defining the Storage Account name. You need to make the internal script available on this URL as a prerequisite. .PARAMETER ScriptFileName Name of the script file to invoke by this wrapper. .PARAMETER VSTSAccountName Name of the Azure Devops account - formerly Visual Studio Team Services (VSTS) account, e.g. https://.visualstudio.com - OR - https://dev.azure.com// .PARAMETER PATToken PPAT token generated by the user who is configuring the container to be used by Azure Devops. .PARAMETER PoolName Name of the Agent pool. It defaults to the "Default" pool when not defined. .PARAMETER RequiredPowerShellModules List of the required PowerShell modules, e.g. Az, AzureAD, Pester .PARAMETER ContainerImage Fully qualified name of the container image, optionally including tags. .PARAMETER AcrPassword Access password to the Azure Container Registry (ACR) .PARAMETER InstallAzureCli Switch to define whether or not you want to install the Azure CLI on your container. .PARAMETER InstallPowerShellCore Switch to define whether or not you want to install Azure PowerShell Core on your container. .PARAMETER UseChocolatey Switch to define whether or not Chocolatey should be used to install the supported components .EXAMPLE .\Initialize-VstsAgentOnWindowsServerCoreContainer.ps1 -SubscriptionName "" -ResourceGroupName "" -ContainerName "", "" -Location "" -StorageAccountName "" -VSTSAccountName "" -PATToken "" This uploads the container configuration script to the default "publicvstsscript" storage container of the requested Storage Account and then creates 2 Azure Container Instances, with the default settings (Default Agent Pool 1 GB RAM, 1 CPU core, PowerShell modules installed: "Az", "AzureAD", "Pester"). .EXAMPLE .\Initialize-VstsAgentOnWindowsServerCoreContainer.ps1 -SubscriptionName "" -ResourceGroupName "" -ContainerName "", "" -Location "" -VSTSAccountName "" -PATToken "" This downloads the container configuration script directly from its default location on GitHub, and then creates 2 Azure Container Instances, with the default settings (Default Agent Pool 1 GB RAM, 1 CPU core, PowerShell modules installed: "Az", "AzureAD", "Pester"). .EXAMPLE .\Initialize-VstsAgentOnWindowsServerCoreContainer.ps1 -SubscriptionName "" -ResourceGroupName "" -ContainerName "", "" -Location "" -VSTSAccountName "" -PATToken "" -ScriptPublicUrl "" This downloads the container configuration script directly from the provided location (this can be anything, e.g. GitHub, a public Storage Account, or any publicly available URL), and then creates 2 Azure Container Instances, with the default settings (Default Agent Pool 1 GB RAM, 1 CPU core, PowerShell modules installed: "Az", "AzureAD", "Pester"). .EXAMPLE .\Initialize-VstsAgentOnWindowsServerCoreContainer.ps1 -SubscriptionName "" -ResourceGroupName "" -ContainerName "", "" -Location "" -StorageAccountName "" -StorageContainerName "publicvstsscript" -MemoryInGB 1 -Cpu 1 -ScriptFileName "Install-VstsAgentOnWindowsServerCoreContainer.ps1" -VSTSAccountName "" -PATToken "" -PoolName "" -RequiredPowerShellModules "Az", "AzureAD", "Pester" This installs 2 Azure Container Instances with all the possible values manually defined. .EXAMPLE .\Initialize-VstsAgentOnWindowsServerCoreContainer.ps1 -SubscriptionName "" -ResourceGroupName "" -ContainerName "", "" -Location "" -StorageAccountName "" -VSTSAccountName "" -PATToken "" -PoolName "" -ReplaceExistingContainer This removes any existing ACI containers with the provided names, then creates new ones with the requested values. .EXAMPLE .\Initialize-VstsAgentOnWindowsServerCoreContainer.ps1 -SubscriptionName "" -ResourceGroupName "" -ContainerName "", "" -Location "" -StorageAccountName "" -VSTSAccountName "" -PATToken "" -ContainerImage -AcrPassword This uploads the container configuration script to the default "publicvstsscript" storage container of the requested Storage Account and then creates 2 Azure Container Instances, based on the custom image provided, with the default settings (Default Agent Pool 1 GB RAM, 1 CPU core, PowerShell modules installed: "Az", "AzureAD", "Pester"). .INPUTS .OUTPUTS .NOTES Version: 1.0 Author: Mate Barabas Creation Date: 2018-08-29 #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] [CmdletBinding()] param( [Parameter(Mandatory = $true, HelpMessage = "Name of the Subscription.")] [ValidateNotNullOrEmpty()] [string]$SubscriptionName, [Parameter(Mandatory = $true, HelpMessage = "Name of the Resource Group.")] [ValidateNotNullOrEmpty()] [string]$ResourceGroupName, [Parameter(Mandatory = $false, HelpMessage = "Name of the ACI container(s).")] [ValidateNotNullOrEmpty()] [array]$ContainerName, [Parameter(Mandatory = $false, HelpMessage = "Switch to replace existing container(s) with the same name(s) provided.")] [ValidateNotNullOrEmpty()] [switch]$ReplaceExistingContainer, [Parameter(Mandatory = $false, HelpMessage = "Amount of memory in GBs.")] [ValidateNotNullOrEmpty()] [int]$MemoryInGB = 1, [Parameter(Mandatory = $false, HelpMessage = "Number of CPU cores.")] [ValidateNotNullOrEmpty()] [int]$Cpu = 1, [Parameter(Mandatory = $true, HelpMessage = "Region of the Azure resources.")] [ValidateNotNullOrEmpty()] [string]$Location, [Parameter(Mandatory = $false, HelpMessage = "Name of the Storage Account to upload the script file to, which is then invoke by this wrapper.")] [ValidateNotNullOrEmpty()] [string]$StorageAccountName, [Parameter(Mandatory = $false, HelpMessage = "Name of the Storage Account Resource Group")] [ValidateNotNullOrEmpty()] [string]$StorageAccountResourceGroupName, [Parameter(Mandatory = $false, HelpMessage = "Name of the storage container to upload the scriptfile to be invoked by this wrapper.")] [ValidateNotNullOrEmpty()] [string]$StorageContainerName = "publicvstsscript", [Parameter(Mandatory = $false, HelpMessage = "Publicly available URL of the internal script file to be invoked by this wrapper. This can be used optionally, instead of defining the Storage Account name. You need to make the internal script available on this URL as a prerequisite.")] [ValidateNotNullOrEmpty()] [string]$ScriptPublicUrl = "https://raw.githubusercontent.com/matebarabas/azure/master/scripts/AzureDevOpsAgentOnACI/Install-VstsAgentOnWindowsServerCoreContainer.ps1", [Parameter(Mandatory = $false, HelpMessage = "Name of the script file to invoke by this wrapper.")] [ValidateNotNullOrEmpty()] [string]$ScriptFileName = "Install-VstsAgentOnWindowsServerCoreContainer.ps1", [Parameter(Mandatory = $false, HelpMessage = "Path to the file - if script not running in same directory")] [ValidateNotNullOrEmpty()] [string]$ScriptFilePath = ".\", [Parameter(Mandatory = $true, HelpMessage = "Name of the Visual Studio Team Services Account (VSTS), e.g. https://.visualstudio.com")] [ValidateNotNullOrEmpty()] [string]$VSTSAccountName, [Parameter(Mandatory = $true, HelpMessage = "PAT token generated by the user who is configuring the container to be used by VSTS.")] [ValidateNotNullOrEmpty()] [string]$PATToken, [Parameter(Mandatory = $false, HelpMessage = "Name of the Agent pool. It defaults to the ""Default"" pool when not defined.")] [ValidateNotNullOrEmpty()] [string]$PoolName = "Default", [Parameter(Mandatory = $false, HelpMessage = "List of the required PowerShell modules, e.g. Az, AzureAD, Pester")] [ValidateNotNullOrEmpty()] [array]$RequiredPowerShellModules = @("Az", "AzureAD", "Pester"), [Parameter(Mandatory = $false, HelpMessage = "Access password to the Azure Container Registry (ACR)")] [ValidateNotNullOrEmpty()] [string]$AcrPassword, [Parameter(Mandatory = $false, HelpMessage = "Fully qualified name of the container image, optionally including tags.")] [ValidateNotNullOrEmpty()] [string]$ContainerImage, # e.g. "microsoft/dotnet-framework:4.7.2-runtime-20190212-windowsservercore-ltsc2016" or "microsoft/windowsservercore:10.0.14393.2791" or "mcr.microsoft.com/windows/servercore:ltsc2016" [Parameter(Mandatory = $false, HelpMessage = "Switch to define whether or not you want to install the Azure CLI on your container.")] [ValidateNotNullOrEmpty()] [bool]$InstallAzureCli = $false, [Parameter(Mandatory = $false, HelpMessage = "Switch to define whether or not you want to install Azure PowerShell Core on your container.")] [ValidateNotNullOrEmpty()] [bool]$InstallPowerShellCore = $false, [Parameter(Mandatory = $false, HelpMessage = "Switch to define whether or not Chocolatey should be used to install the supported components")] [ValidateNotNullOrEmpty()] [bool]$UseChocolatey = $false ) #region Functions function Set-AzureContext { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] param ( [Parameter(Mandatory = $false)][string]$SubscriptionName ) # Select the desired Subscription based on the Subscription name provided if ($SubscriptionName) { $Subscription = (Get-AzureRmSubscription | Where-Object { $_.Name -eq $SubscriptionName }) if (-not $Subscription) { Write-Error "There's no Subscription available with the provided name." return } else { $SubscriptionId = $Subscription.Id Select-AzureRmSubscription -SubscriptionId $SubscriptionId | Out-Null Write-Output "The following subscription was selected: ""$SubscriptionName""" } } # If no Subscription name was provided select the active Subscription based on the existing context else { $SubscriptionName = (Get-AzureRmContext).Subscription.Name $Subscription = (Get-AzureRmSubscription | Where-Object { $_.Name -eq $SubscriptionName }) Write-Output "The following subscription was selected: ""$SubscriptionName""" } if ($Subscription.Count -gt 1) { Write-Error "You have more then 1 Subscription with the same name. Exiting..." return } } if (-not $StorageAccountResourceGroupName) { $StorageAccountResourceGroupName = $ResourceGroupName } function Copy-ScriptToStorageAccount { param ( [Parameter(Mandatory = $true)][string]$StorageAccountName, [Parameter(Mandatory = $true)][string]$StorageAccountResourceGroupName, [Parameter(Mandatory = $false)][string]$StorageContainerName = "publicvstsscript", [Parameter(Mandatory = $false)][string]$ScriptFileName = "Install-VstsAgentOnWindowsServerCoreContainer.ps1" ) # Check if the Install-VstsAgentOnWindowsServerCoreContainer.ps1 script exists within the same folder if (-not (Get-Item -Path "$ScriptFilePath\$ScriptFileName" -ErrorAction SilentlyContinue)) { Write-Error "The script to be uploaded to the Storage Account ($ScriptFilePath\$ScriptFileName) does not exist in the same folder. Make sure that it is copied to the same folder along with the Initialize-VstsAgentOnWindowsServerCoreContainer.ps1 script. Exiting..." break } if (-not (Get-AzureRmStorageAccount -ResourceGroupName $StorageAccountResourceGroupName -Name $StorageAccountName -ErrorAction SilentlyContinue)) { New-AzureRmStorageAccount -ResourceGroupName $StorageAccountResourceGroupName -Name $StorageAccountName -Location "West Europe" -SkuName "Standard_GRS" } # Getting Storage Account Key Write-Output "Getting Storage Account Key..." $StorageKey = Get-AzureRmStorageAccountKey -ResourceGroupName $StorageAccountResourceGroupName -Name $StorageAccountName # Setting storage context Write-Output "Setting storage context..." $ctx = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageKey[0].Value # Checking if the container exists, creating if it doesn't $StorageContainer = Get-AzureStorageContainer -Context $ctx -Name $StorageContainerName -ErrorAction SilentlyContinue if (-not $StorageContainer) { Write-Output "Storage container ""$StorageContainerName"" does not exist in the ""$StorageAccountName"" Storage Account. Creating storage container with public access..." New-AzureStorageContainer -Context $ctx -Name $StorageContainerName -Permission Blob | Out-Null Write-Output "Wait 10 seconds..." Start-Sleep -Seconds 10 } else { Write-Output "Storage container ""$StorageContainerName"" exists in the ""$StorageAccountName"" Storage Account." $PublicAccess = (Get-AzureStorageContainerAcl -Name $StorageContainerName -Context $ctx).PublicAccess if ($PublicAccess -ne "Blob") { Write-Output "Public Access was configured to $PublicAccess. Resetting it to ""Blob"" (public access)." Set-AzureStorageContainerAcl -Name $StorageContainerName -Permission Blob Write-Output "Wait 10 seconds..." Start-Sleep -Seconds 10 } } # Check if container creation was successful $StorageContainer = Get-AzureStorageContainer -Context $ctx -Name $StorageContainerName -ErrorAction SilentlyContinue if (-not $StorageContainer) { Write-Error "Storage container ($StorageContainerName) could not be created in the $StorageAccountName Storage Account. Exiting..." break } # Uploading CSV file Write-Output "Uploading the Install-VstsAgentOnWindowsServerCoreContainer.ps1 script to the Storage Account..." Set-AzureStorageBlobContent -Container $StorageContainerName -File "$ScriptFilePath\$ScriptFileName" -Blob $ScriptFileName -context $ctx -Force | Out-Null # Checking success $Blob = Get-AzureStorageBlob -Context $ctx -Container $StorageContainerName -Blob $ScriptFileName -ErrorAction SilentlyContinue if ($Blob) { Write-Output "The script file ($ScriptFileName) was successfully uploaded to the ""$StorageContainerName"" container of the ""$StorageAccountName"" Storage Account in the ""$StorageAccountResourceGroupName"" Resource Group." } else { Write-Error "The script file ($ScriptFileName) could not be uploaded to the ""$StorageContainerName"" container of the ""$StorageAccountName"" Storage Account in the ""$StorageAccountResourceGroupName"" Resource Group. Exiting..." break } } function New-Container { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] param ( [Parameter(Mandatory = $false)][string]$AcrPassword, [Parameter(Mandatory = $true)][string]$ContainerImage ) # Create & Install containers if ($StorageAccountName) { #if you want to upload the internal script to a Storage Account $ScriptURL = "https://$StorageAccountName.blob.core.windows.net/$StorageContainerName/$ScriptFileName" } else { # if you want to use the internal script from a public location (e.g. GitHub) $ScriptURL = $ScriptPublicUrl } foreach ($Name in $ContainerName) { $CanCreateContainerWithProvidedName = $true $ExistingContainer = Get-AzureRmContainerGroup -ResourceGroupName $ResourceGroupName -Name $Name -ErrorAction SilentlyContinue if ($ExistingContainer) { Write-Warning "ACI container with the requested name ($Name) already exists in the given Resource Group ($ResourceGroupName)." $CanCreateContainerWithProvidedName = $false if ($ReplaceExistingContainer.IsPresent) { Write-Warning "Deleting the existing container instance ($Name)..." Remove-AzureRmContainerGroup -ResourceGroupName $ResourceGroupName -Name $Name -Confirm:$false Write-Warning "Unregistering existing container instance ($Name) from Agent pool ($PoolName)..." Remove-AzureDevOpsAgentFromPool -PatToken $PatToken -AzureDevOpsAccountName $VSTSAccountName -AgentPoolName $PoolName -ContainerName $ContainerName $ContainerDeletetionWasRequired = $true $CanCreateContainerWithProvidedName = $true Write-Output "Waiting 10 seconds..." Start-Sleep -Seconds 10 } else { Write-Output "Existing container with the name of $Name is being kept." } } if ($CanCreateContainerWithProvidedName) { $CreateAtLeastOneContainer = $true Write-Output "Creating ACI container ($Name) with the image of $ContainerImage..." Write-Output "Instantiating a container can take a few minutes, depending on the image size and whether or not the container image is cached in the ACI platform." if ($RequiredPowerShellModules.Count -gt 1) { $RequiredPowerShellModules = $RequiredPowerShellModules -join "," } if ($AcrPassword) { $SecPasswd = ConvertTo-SecureString $AcrPassword -AsPlainText -Force $RegistryName = $ContainerImage.Split(".")[0] $MyCred = New-Object System.Management.Automation.PSCredential ($RegistryName, $SecPasswd) if ($PSVersionTable.PSEdition -eq "Core") { # The AZ CLI has to be used, as the required -Command parameter is not available in the core version of the related AzureRM PowerShell module in Azure Cloud Shell. # When running in Cloud Shell, login is not required (has already happened) if ($null -ne $env:ACC_CLOUD) { az container create --resource-group $ResourceGroupName --name $Name --image $ContainerImage --registry-password $AcrPassword --location $Location --os-type Windows --cpu $Cpu --memory $MemoryInGB --restart-policy Always --command-line "powershell Start-Sleep -Seconds 20; Invoke-WebRequest -Uri $ScriptURL -OutFile $ScriptFileName -UseBasicParsing; & .\\$ScriptFileName -VSTSAccountName $VSTSAccountName -PATToken $PATToken -AgentNamePrefix $Name -PoolName $PoolName -InstallPowerShellCore $InstallPowerShellCore -InstallAzureCli $InstallAzureCli -UseChocolatey $UseChocolatey -RequiredPowerShellModules $RequiredPowerShellModules" --subscription $SubscriptionName --output none } } elseif ($PSVersionTable.PSEdition -eq "Desktop") { # Alternative option, using AzureRM PowerShell commandlet (this doesn't work in Azure Cloud Shell, as the -Command parameter is not available in the core version of this cmdlet) New-AzureRmContainerGroup -ResourceGroupName $ResourceGroupName ` -Name $Name ` -Image $ContainerImage ` -Location $Location ` -OsType Windows ` -Cpu $Cpu ` -MemoryInGB $MemoryInGB ` -RestartPolicy Always ` -RegistryCredential $MyCred ` -Command "powershell Start-Sleep -Seconds 20; Invoke-WebRequest -Uri $ScriptURL -OutFile $ScriptFileName -UseBasicParsing; & .\$ScriptFileName -VSTSAccountName $VSTSAccountName -PATToken $PATToken -AgentNamePrefix $Name -PoolName $PoolName -RequiredPowerShellModules $RequiredPowerShellModules -InstallAzureCli $InstallAzureCli -UseChocolatey $UseChocolatey -InstallPowerShellCore $InstallPowerShellCore" | Out-null } else { Write-Error "PowerShell version could not be defined. Exiting..." return } } else { if ($PSVersionTable.PSEdition -eq "Core") { # The AZ CLI has to be used, as the required -Command parameter is note available in the core version of the related AzureRM PowerShell module in Azure Cloud Shell. # When running in Cloud Shell, login is not required (has already happened) if ($null -ne $env:ACC_CLOUD) { az container create --resource-group $ResourceGroupName --name $Name --image $ContainerImage --location $Location --os-type Windows --cpu $Cpu --memory $MemoryInGB --restart-policy Always --command-line "powershell Start-Sleep -Seconds 20; Invoke-WebRequest -Uri $ScriptURL -OutFile $ScriptFileName -UseBasicParsing; & .\\$ScriptFileName -VSTSAccountName $VSTSAccountName -PATToken $PATToken -AgentNamePrefix $Name -PoolName $PoolName -RequiredPowerShellModules $RequiredPowerShellModules -InstallAzureCli $InstallAzureCli -UseChocolatey $UseChocolatey -InstallPowerShellCore $InstallPowerShellCore" --subscription $SubscriptionName --output none } } elseif ($PSVersionTable.PSEdition -eq "Desktop") { # Alternative option, using AzureRM PowerShell commandlet (this doesn't work in Azure Cloud Shell, as the -Command parameter is not available in the core version of this cmdlet) New-AzureRmContainerGroup -ResourceGroupName $ResourceGroupName ` -Name $Name ` -Image $ContainerImage ` -Location $Location ` -OsType Windows ` -Cpu $Cpu ` -MemoryInGB $MemoryInGB ` -RestartPolicy Always ` -Command "powershell Start-Sleep -Seconds 20; Invoke-WebRequest -Uri $ScriptURL -OutFile $ScriptFileName -UseBasicParsing; & .\$ScriptFileName -VSTSAccountName $VSTSAccountName -PATToken $PATToken -AgentNamePrefix $Name -PoolName $PoolName -RequiredPowerShellModules $RequiredPowerShellModules -InstallAzureCli $InstallAzureCli -UseChocolatey $UseChocolatey -InstallPowerShellCore $InstallPowerShellCore" | Out-null } else { Write-Error "PowerShell version could not be defined. Exiting..." return } } } else { Write-Warning "ACI container could not be created, as there's another container instance with the same name in the same Resource Group. If you want to remove the existing intance first, run the script again by using the -ReplaceExistingContainer switch." } } if ($CreateAtLeastOneContainer) { Write-Output "ACI container creation tasks have been submitted. When using a cached image, it usually takes about 10 minutes to fully provision a container." Write-Output "New ACI container(s) are being built..." # Periodically check if all containers have been configured $ConfiguredContainers = @() $NotificationTracker = @{ } while ($ConfiguredContainers.Count -ne $ContainerName.Count) { Start-Sleep -Seconds 10 foreach ($Name in $ContainerName) { if ($ConfiguredContainers -notcontains $Name) { $LogEntries = Get-AzureRmContainerInstanceLog -ResourceGroupName $ResourceGroupName -ContainerGroupName $Name -ErrorAction SilentlyContinue $RestartCount = (Get-AzureRmContainerGroup -ResourceGroupName $ResourceGroupName -Name $Name).Containers.restartcount # Show restart counts, avoid repeating the same entry if ($RestartCount -gt 0) { $Key = "$Name-$RestartCount" if ($NotificationTracker[$Key] -ne "MessageAlreadyShown") { Write-Output "The creation of the ACI container ""$Name"" was restarted $RestartCount time(s). Note that a few retries are acceptable, however each iteration increases the overall creation time." $NotificationTracker.Add($Key, "MessageAlreadyShown") } } # Trigger on success if ($LogEntries) { # Check if the last line of the log is "Container successfully configured." $Success = $LogEntries.Split("`n")[-4] -eq "Container successfully configured." # Do NOT change this value, as the wrapper script is triggered based on this. if ($Success) { $ConfiguredContainers += $Name Write-Output "ACI container ""$Name"" successfully configured" } } } } } # Print results if ($ConfiguredContainers.Count -eq $ContainerName.Count) { Write-Output "All requested containers have been successfully deployed and configured." Write-Output "Check if VSTS agents have been registered under the requested Agent Pool on the VSTS portal." $TimeSpan = (New-TimeSpan -Start $StartDate -End (Get-Date)) Write-Output "Finished at $(Get-Date)" Write-Output "It took $($TimeSpan.Minutes) minutes and $($TimeSpan.Seconds) seconds to initialize the requested containers." if ($ContainerDeletetionWasRequired) { Write-Warning "One or more containers have been deleted. " } } } else { Write-Output "No ACI containers have been created, as there were conflicts with existing intances and the -ReplaceExistingContainer was not used." } } function Get-LatestCachedImageVersion { # This function returns the name of the latest version of the # microsoft/windowsservercore image that is cached in the ACI platform # This is needed, because Microsoft no longer uses the ":latest" tag on their images # See more details here: https://techcommunity.microsoft.com/t5/Containers/Removing-the-latest-Tag-An-Update-on-MCR/ba-p/393045 # Authenticate to invoke Azure REST API $azProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile $currentAzureContext = Get-AzureRmContext $profileClient = New-Object Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient($azProfile) $token = $profileClient.AcquireAccessToken($currentAzureContext.Tenant.TenantId) $accessToken = $token.AccessToken $RestCall = @{ Method = "Get" Uri = "https://management.azure.com/subscriptions/$($currentAzureContext.Subscription)/providers/Microsoft.ContainerInstance/locations/$Location/cachedImages?api-version=2018-10-01" Headers = @{ Authorization = "Bearer " + $AccessToken } } $result = Invoke-RestMethod @RestCall $LatestCachedImage = (($result.value | Where-Object { $_.image -like "microsoft/*dotnet*windowsservercore*" } | Sort-Object image)[-1]).image return $LatestCachedImage } function Remove-AzureDevOpsAgentFromPool { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] Param( [string]$PatToken, #Personal access token [string]$AzureDevOpsAccountName, #Azure DevOps account name [string]$AgentPoolName, #Azure DevOps Agent pool name [array]$ContainerName #Azure DevOps Agent pool name ) $base64AuthInfo = [System.Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($PatToken)")) $Header = @{Authorization = ("Basic $base64AuthInfo") } # Get Agent Pool Write-Output "Getting Agent Pool ($AgentPoolName)..." $uri = "https://dev.azure.com/$AzureDevOpsAccountName/_apis/distributedtask/pools" $result = Invoke-RestMethod -Uri $uri -Method GET -ContentType "application/json" -Headers $Header $AgentPool = $result.value | Where-Object { $_.Name -eq "$AgentPoolName" } $AgentPoolId = $AgentPool.id if (-not $AgentPoolId) { Write-Error "The Agent Pool ($AgentPoolName) doesn't exist!" } else { # Get Agents Write-Output "Getting Agents from Pool..." $uri = "https://dev.azure.com/$AzureDevOpsAccountName/_apis/distributedtask/pools/$AgentPoolId/agents?includeCapabilities=false&includeAssignedRequest=true" $result = Invoke-RestMethod -Uri $uri -Method GET -ContentType "application/json" -Headers $Header $Agents = $result.value if (-not $Agents) { Write-Output "There are no Agents in this Agent Pool" } else { Write-Output "The following agents were found:" foreach ($Agent in $Agents) { $AgentName = $Agent.name $AgentStatus = $Agent.status Write-Output "$AgentName ($AgentStatus)" } # Delete Agent(s) from Pool foreach ($Name in $ContainerName) { Write-Output "Attempting to remove any Agent(s) that belonged to this ACI container: $Name..." foreach ($Agent in $Agents) { $AgentName = $Agent.name if ($AgentName -match "^$Name-") { # Delete Agent $AgentIds = $Agent.id foreach ($AgentId in $AgentIds) { Write-Output "Deleting Agent ($AgentName) - (Agent ID: $AgentId)..." $uri = "https://dev.azure.com/$AzureDevOpsAccountName/_apis/distributedtask/pools/$AgentPoolId/agents/$($AgentId)?api-version=5.0" $result = Invoke-RestMethod -Uri $uri -Method DELETE -ContentType "application/json" -Headers $Header # Check success Write-Output "Checking if the Agent ($AgentName) - (Agent ID: $AgentId) is still there..." $uri = "https://dev.azure.com/$AzureDevOpsAccountName/_apis/distributedtask/pools/$AgentPoolId/agents?includeCapabilities=false&includeAssignedRequest=true" $result = Invoke-RestMethod -Uri $uri -Method GET -ContentType "application/json" -Headers $Header $AgentStillThere = $result.value.id -contains $AgentId if ($AgentStillThere) { Write-Warning "Agent ($AgentName) could not be deleted. Don't forget to clean your Agent pool in Azure Devops (remove any agents that were created in a previous iteration and are now offline)!" } else { Write-Output "Agent ($AgentName) successfully deleted." } } } } } } } } #endregion #region Main # Report start time $StartDate = Get-Date Write-Output "Started at $StartDate..." # Login to Azure and select Subscription Set-AzureContext -SubscriptionName $SubscriptionName if ($StorageAccountName) { # Upload the configuration script to a Storage Account Copy-ScriptToStorageAccount -StorageAccountResourceGroupName $ResourceGroupName -StorageAccountName $StorageAccountName -StorageContainerName $StorageContainerName -ScriptFileName $ScriptFileName } Write-Output "Ready For creating Resource Group for containers" <# # Create Resource Group for containers if (-not (Get-AzureRmResourceGroup -Name $ResourceGroupName -ErrorAction SilentlyContinue)) { Write-Output "Resource Group ""$ResourceGroupName"" does not exist for ACI containers. Creating..." New-AzureRmResourceGroup -Name $ResourceGroupName -Location $Location | Out-Null } #> Write-Output "Ready For creating containers" # Create containers if (-not $ContainerImage) { $ContainerImage = Get-LatestCachedImageVersion Write-Output "Container Image = $ContainerImage" } New-Container -ContainerImage $ContainerImage #endregion # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUag+tQogpqd0EKtkbuuzLmtQU # xrSgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQodToNMwK9wGq1pq5gEafK/pkI # 6TANBgkqhkiG9w0BAQEFAASCAQA1cWGaoOtYK7Aj0+voFm8NBPFXUyBfFFFMBUBK # np8giAMSvASbzXSUPR/hae6LR/UzZFdXqH3ZhAbA//BItAjM5EC8fhbZMHGzqXmx # IxU7YxzuXJvrLd7yVjLRRhu+kclMVGSGELBFIfEAm8nMtrhWAKGhXPlzFTJtwOiD # qREulLuvtEBb/LBk/mT/vw8499Jzj9fE5oXYkqcJiodToaagGEpe2fZC03s8rbm9 # kl3n3H39/j7y4PwJHt0BEhtT4koNVod5d3Jx42hpJIN77vLCmJ3DtVhckArrkftc # UPdWInKb/H47AJCuP3+chRgiGmEGdlnVVM13FJfzIkHxDxpA # SIG # End signature block ================================================ FILE: developing/Archive/tests/build/Install-VstsAgentOnWindowsServerCoreContainer.ps1 ================================================ ######################################################################################################################## # Script Disclaimer ######################################################################################################################## # This script is not supported under any Microsoft standard support program or service. # This script is provided AS IS without warranty of any kind. # Microsoft disclaims all implied warranties including, without limitation, any implied warranties of # merchantability or of fitness for a particular purpose. The entire risk arising out of the use or # performance of this script and documentation remains with you. In no event shall Microsoft, its authors, # or anyone else involved in the creation, production, or delivery of this script be liable for any damages # whatsoever (including, without limitation, damages for loss of business profits, business interruption, # loss of business information, or other pecuniary loss) arising out of the use of or inability to use # this script or documentation, even if Microsoft has been advised of the possibility of such damages. <# .SYNOPSIS This scripts configures a Windows Server Core based container with Terraform, json2hcl, the selected PowerShell modules and installs and configures the Visual Studio Team Services build agent on it. .DESCRIPTION This scripts configures a Windows Server Core based container (with the latest version of the microsoft/windowsservercore LTSC image available on Docker Hub), with the latest version of the Azure DevOps agent, Terraform, json2hcl and the selected PowerShell modules (by default Az, AzureAD, Pester). This container is intended to be run as an Azure Container Instance. After the successfully configuration, it prints the available disk space, and keeps periodically checking of the vstsagent service is in a running state, keeping the container alive by that. .PARAMETER VSTSAccountName Name of the Azure DevOps account - formerly Visual Studio Team Services (VSTS) account, e.g. https://.visualstudio.com - OR - https://dev.azure.com// .PARAMETER PATToken PAT token generated by the user who is configuring the container to be used by VSTS. .PARAMETER AgentNamePrefix Prefix of the name of the agent shown on the Azure DevOps (VSTS) portal. .PARAMETER PoolName Name of the Agent pool. It defaults to the "Default" pool when not defined. .PARAMETER RequiredPowerShellModules List of the required PowerShell modules, e.g. Az, AzureAD, Pester .PARAMETER InstallAzureCli Switch to define whether or not you want to install the Azure CLI on your container. .PARAMETER InstallPowerShellCore Switch to define whether or not you want to install Azure PowerShell Core on your container. .PARAMETER UseChocolatey Switch to define whether or not Chocolatey should be used to install the supported components .EXAMPLE .\Install-VstsAgentWindowsServerCoreContainer.ps1 -VSTSAccountName "" -PATToken "" This installs all the components with the default configuration (Default Agent Pool, "Az", "AzureAD", "Pester" PowerShell modules, randomly generated agent name). .EXAMPLE .\Install-VstsAgentWindowsServerCoreContainer.ps1 -VSTSAccountName "" -PATToken "" -AgentNamePrefix "" -PoolName "CoreContainers" This installs all the components with the defined Agent name, and Pool name, with the default PowerShell modules. .EXAMPLE .\Install-VstsAgentWindowsServerCoreContainer.ps1 -VSTSAccountName "" -PATToken "" -AgentNamePrefix "" -PoolName "CoreContainers" -RequiredPowerShellModules "Az", "AzureAD", "Pester" This installs all the components with the defined Agent name, Pool name, and PowerShell modules. .INPUTS .OUTPUTS .NOTES Version: 1.0 Author: Mate Barabas, Andrew Auret Creation Date: 2018-08-23 References: The Install-VstsAgent function is a slightly modified version of the provisioning script available as part of Azure DevTest Labs (available in August 2018). #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUsernameAndPasswordParams", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseCompatibleCommands", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWMICmdlet", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWriteHost", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidTrailingWhiteSpace", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = "Name of the Visual Studio Team Services Account (VSTS), e.g. https://.visualstudio.com")] [ValidateNotNullOrEmpty()] [string]$VSTSAccountName, [Parameter(Mandatory = $true, HelpMessage = "PAT token generated by the user who is configuring the container to be used by VSTS.")] [ValidateNotNullOrEmpty()] [string]$PATToken, [Parameter(Mandatory = $false, HelpMessage = "Prefix of the name of the agent shown on the VSTS portal.")] [ValidateNotNullOrEmpty()] [string]$AgentNamePrefix, [Parameter(Mandatory = $false, HelpMessage = "Name of the Agent pool. It defaults to the ""Default"" pool when not defined.")] [ValidateNotNullOrEmpty()] [string]$PoolName = "Default", [Parameter(Mandatory = $false, HelpMessage = "List of the required PowerShell modules, e.g. Az, AzureAD, Pester")] [ValidateNotNullOrEmpty()] [array]$RequiredPowerShellModules = @("Az", "AzureAD", "Pester"), [Parameter(Mandatory = $false, HelpMessage = "Switch to define whether or not you want to install the Azure CLI on your container.")] [ValidateNotNullOrEmpty()] [string]$InstallAzureCli, [Parameter(Mandatory = $false, HelpMessage = "Switch to define whether or not you want to install Azure PowerShell Core on your container.")] [ValidateNotNullOrEmpty()] [string]$InstallPowerShellCore, [Parameter(Mandatory = $false, HelpMessage = "Switch to define whether or not Chocolatey should be used to install the supported components")] [ValidateNotNullOrEmpty()] [string]$UseChocolatey ) #region Variable conversion (from text to boolean) $InstallAzureCli = switch ($InstallAzureCli) { '1' { $true } 'true' { $true } '$true' { $true } '0' { $false } 'false' { $false } '$false' { $false } Default { $false } } $InstallPowerShellCore = switch ($InstallPowerShellCore) { '1' { $true } 'true' { $true } '$true' { $true } '0' { $false } 'false' { $false } '$false' { $false } Default { $false } } $UseChocolatey = switch ($UseChocolatey) { '1' { $true } 'true' { $true } '$true' { $true } '0' { $false } 'false' { $false } '$false' { $false } Default { $false } } #endregion #region Functions function Install-Nuget { if (-not (Get-PackageProvider -Name "Nuget" -ListAvailable -ErrorAction SilentlyContinue)) { Write-Output "-----------------------------------------------------------------------------------" $NewPackageProvider = Find-PackageProvider -Name "Nuget" $NewPackageProviderVersion = $NewPackageProvider.Version.ToString() Write-Output "Installing Nuget package provider ($NewPackageProviderVersion)..." Install-PackageProvider -Name "Nuget" -Force -Confirm:$false | Out-Null if (Get-PackageProvider "Nuget") { Write-Output "Nuget package provider ($NewPackageProviderVersion) successfully installed." } else { Write-Error "Nuget package provider ($NewPackageProviderVersion) installation failed." } Write-Output "Waiting 10 seconds..." Start-Sleep -Seconds 10 } } function Install-PowerShellModules { param ( [array]$RequiredModules ) Write-Output "-----------------------------------------------------------------------------------" Write-Output "PowerShell modules to install: $($RequiredModules -join ", ")" foreach ($Module in $RequiredModules) { if (-not (Get-Module $Module -ErrorAction SilentlyContinue)) { Write-Output "-----------------------------------------------------------------------------------" Write-Output "Getting $Module module..." $NewModule = Find-Module $Module $NewModuleVersion = $NewModule.Version.ToString() Write-Output "Installing $Module ($NewModuleVersion) module..." Install-Module -Name $Module -Force -Confirm:$false -SkipPublisherCheck -AllowClobber } } if (Get-Module -ListAvailable | Where-Object { $_.Name -eq "Az.Accounts" }) { Write-Output "Enabling AzureRm compatibility mode" Enable-AzureRmAlias -Scope LocalMachine -Confirm:$false } } function Install-Choco { Write-Output "-----------------------------------------------------------------------------------" Write-Output "Installing Chocolatey..." Invoke-WebRequest -Uri "https://chocolatey.org/install.ps1" -OutFile "c:\chochoinstall.ps1" .\chochoinstall.ps1 | Out-Null } function Install-ChocoTerraform { Write-Output "-----------------------------------------------------------------------------------" Write-Output "Installing Terraform with Chocolatey..." choco install terraform -y --limit-output --no-progress } function Install-Terraform { param ( [Parameter(Mandatory = $false, HelpMessage = "Use this parameter to decide if the absolute latest or the latest stable Terraform release should be installed.")] [ValidateNotNullOrEmpty()] [bool]$SkipNonStableReleases = $true ) # Get the list of available Terraform versions $Response = Invoke-WebRequest -Uri "https://releases.hashicorp.com/terraform" -UseBasicParsing # Find the latest version if ($SkipNonStableReleases -eq $true) { $Links = $Response.Links | Where-Object { $_.href.Split("/")[2] -match "^(\d|\d\d)\.(\d|\d\d)\.(\d|\d\d)$" } $LatestTerraformVersion = $Links[0].href.Split("/")[2] } else { $LatestTerraformVersion = $Response.Links[1].href.Split("/")[2] } $Version = $LatestTerraformVersion # Find the download URL for the latest version $Response = Invoke-WebRequest -Uri "https://releases.hashicorp.com/terraform/$Version" -UseBasicParsing $RelativePath = ($Response.Links | Where-Object { $_.href -like "*windows_amd64*" }).href # URL will be similar to this: "https://releases.hashicorp.com/terraform/0.11.8/terraform_0.11.8_windows_amd64.zip" $URL = "https://releases.hashicorp.com$RelativePath" # Create folder $FileName = Split-Path $url -Leaf $FolderPath = "C:\terraform" $FilePath = "$FolderPath\$FileName" New-Item -ItemType Directory -Path $FolderPath -ErrorAction SilentlyContinue | Out-Null # Download and extract Terraform, remove the temporary zip file Write-Output "-----------------------------------------------------------------------------------" Write-Output "Downloading Terraform ($Version) to $FolderPath..." Start-BitsTransfer -Source $URL -Destination $FilePath Expand-Archive -LiteralPath $FilePath -DestinationPath $FolderPath Remove-Item -Path $FilePath # Setting PATH environmental variable for Terraform Write-Output "Setting PATH environmental variable for Terraform..." # Get the PATH environmental Variable $Path = (Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path # Create New PATH environmental Variable $NewPath = $Path + ";" + $FolderPath # Set the New PATH environmental Variable Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $NewPath $env:Path += $NewPath # Verify the Path # (Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path } function Install-Json2Hcl { # Get the list of available Terraform versions $Response = Invoke-WebRequest -Uri "https://github.com/kvz/json2hcl/releases" -UseBasicParsing # Find the latest version $RelativePathToLatestVersion = (($Response.Links | Where-Object { $_.href -like "*windows_amd64*" }).href)[0] $Version = $RelativePathToLatestVersion.Split("/")[-2] # URL will be similar to this: "https://github.com/kvz/json2hcl/releases/download/v0.0.6/json2hcl_v0.0.6_windows_amd64.exe" $URL = "https://github.com/$RelativePathToLatestVersion" # Create folder $FileName = Split-Path $url -Leaf $FolderPath = "C:\json2hcl" $FilePath = "$FolderPath\$FileName" New-Item -ItemType Directory -Path $FolderPath -ErrorAction SilentlyContinue | Out-Null # Download and extract Json2HCL Write-Output "-----------------------------------------------------------------------------------" Write-Output "Downloading Json2HCL ($Version) to $FolderPath..." $WebClient = New-Object System.Net.WebClient $WebClient.DownloadFile($URL, $FilePath) Rename-Item -Path $FolderPath\$FileName -NewName "json2hcl.exe" # Setting PATH environmental variable Write-Output "Setting PATH environmental variable for Json2HCL..." # Get the PATH environmental Variable $Path = (Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path # Create New PATH environmental Variable $NewPath = $Path + ";" + $FolderPath # Set the New PATH environmental Variable Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $NewPath $env:Path += $NewPath } function Install-ChocoAzureCli { Write-Output "-----------------------------------------------------------------------------------" Write-Output "Installing Azure CLI with Chocolatey..." choco install azure-cli -y --limit-output --no-progress } function Install-AzureCli { Write-Output "-----------------------------------------------------------------------------------" Write-Output "Searching for the latest version of Azure CLI" $AzureCliUrl = "https://aka.ms/installazurecliwindows" $AzureCliInstallerFullPath = "C:\azurecli.msi" $response = Invoke-WebRequest -UseBasicParsing -Uri $AzureCliUrl -Method Head $AzureCliInstallerFileName = $response.BaseResponse.ResponseUri.AbsolutePath.Split("/")[-1] Write-Output "Downloading Azure CLI installer ($AzureCliInstallerFileName)" $WebClient = New-Object System.Net.WebClient $WebClient.DownloadFile($AzureCliUrl, $AzureCliInstallerFullPath) if (Test-Path $AzureCliInstallerFullPath) { Write-Output "Installing Azure CLI ($AzureCliInstallerFileName)" Start-Process msiexec.exe -Wait -ArgumentList "/i $AzureCliInstallerFullPath /quiet /passive /qn" $AzureCli = (Get-WmiObject -Class win32_product) | Where-Object { $_.name -like "*Microsoft Azure CLI*" } if ($AzureCli) { Write-Output "Azure CLI (version $($AzureCli.Version)) was successfully installed" Remove-Item -Path $AzureCliInstallerFullPath -Force -Confirm:$false # Setting PATH environmental variable Write-Output "Setting PATH environmental variable for Azure CLI..." # Get the PATH environmental Variable $Path = (Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path # Create New PATH environmental Variable $NewPath = $Path + ";" + "C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin" # Set the New PATH environmental Variable Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $NewPath $env:Path += $NewPath } else { Write-Error "Azure CLI could not be installed" } } } function Install-ChocoPowerShellCore { Write-Output "-----------------------------------------------------------------------------------" Write-Output "Installing PowerShell Core with Chocolatey..." choco install pwsh -y --limit-output --no-progress } function Install-PowerShellCore { Write-Output "-----------------------------------------------------------------------------------" Write-Output "Searching for the latest version of PowerShell Core" $PwshInstallerFullPath = "c:\pwsh.msi" $response = Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/PowerShell/PowerShell/releases" $PwshInstallerRelativeUrl = ($response.Links.href | Where-Object { $_ -like "*win-x64.msi" -and $_ -notlike "*preview*" -and $_ -notlike "*rc*" })[0] $PwshInstallerFileName = $PwshInstallerRelativeUrl.Split("/")[-1] Write-Output "Downloading PowerShell Core ($PwshInstallerFileName)" $PwshInstallerUrl = "https://github.com" + $PwshInstallerRelativeUrl # Download PowerShell Core $WebClient = New-Object System.Net.WebClient $WebClient.DownloadFile($PwshInstallerUrl, $PwshInstallerFullPath) if (Test-Path $PwshInstallerFullPath) { Write-Output "Installing PowerShell Core ($PwshInstallerFileName)" Start-Process msiexec.exe -Wait -ArgumentList "/i $PwshInstallerFullPath /quiet /passive /qn" $Pwsh = (Get-WmiObject -Class win32_product) | Where-Object { $_.name -like "*PowerShell*-x64" } if ($Pwsh) { Write-Output "PowerShell Core (version $($Pwsh.Version) was successfully installed)" Remove-Item -Path $PwshInstallerFullPath -Force -Confirm:$false # Setting PATH environmental variable Write-Output "Setting PATH environmental variable for Azure CLI..." # Get the PATH environmental Variable $Path = (Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path # Create New PATH environmental Variable $NewPath = $Path + ";" + "c:\Program Files\PowerShell\6\" # Set the New PATH environmental Variable Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $NewPath $env:Path += $NewPath } else { Write-Error "PowerShell Core could not be installed" } } } function Install-ChocoVstsAgent { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUsernameAndPasswordParams", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] # Downloads the Visual Studio Online Build Agent, installs on the new machine, registers with the Visual # Studio Online account, and adds to the specified build agent pool [CmdletBinding()] param( [Parameter(Mandatory = $true)][string]$vstsAccount, [Parameter(Mandatory = $true)][string]$vstsUserPassword, [Parameter(Mandatory = $true)][string]$agentName, [Parameter(Mandatory = $false)][string]$agentNameSuffix, [Parameter(Mandatory = $true)][string]$poolName, [Parameter(Mandatory = $true)][string]$windowsLogonAccount, [Parameter(Mandatory = $false)][string]$windowsLogonPassword, [Parameter(Mandatory = $true)][ValidatePattern("[c-zC-Z]")][ValidateLength(1, 1)][string]$driveLetter, [Parameter(Mandatory = $false)][string]$workDirectory, [Parameter(Mandatory = $true)][boolean]$runAsAutoLogon ) $AgentPreparationStartTime = Get-Date Write-Output "-----------------------------------------------------------------------------------" Write-Output "Installing Azure Devops Agent with Chocolatey..." choco install azure-pipelines-agent -y --limit-output --no-progress ################################################################################################### # if the agentName is empty, use %COMPUTERNAME% as the value if ([String]::IsNullOrWhiteSpace($agentName)) { $agentName = $env:COMPUTERNAME } # if the agentNameSuffix has a value, add this to the end of the agent name if (![String]::IsNullOrWhiteSpace($agentNameSuffix)) { $agentName = $agentName + $agentNameSuffix } # # PowerShell configurations # # NOTE: Because the $ErrorActionPreference is "Stop", this script will stop on first failure. # This is necessary to ensure we capture errors inside the try-catch-finally block. $ErrorActionPreference = "Stop" # Ensure we set the working directory to that of the script. Push-Location $PSScriptRoot # Configure strict debugging. Set-PSDebug -Strict ################################################################################################### # # Functions used in this script. # function Show-LastError { [CmdletBinding()] param( ) $message = $error[0].Exception.Message if ($message) { Write-Host -Object "ERROR: $message" -ForegroundColor Red } # IMPORTANT NOTE: Throwing a terminating error (using $ErrorActionPreference = "Stop") still # returns exit code zero from the PowerShell script when using -File. The workaround is to # NOT use -File when calling this script and leverage the try-catch-finally block and return # a non-zero exit code from the catch block. exit -1 } function Test-Parameters { [CmdletBinding()] param( [string] $VstsAccount, [string] $WorkDirectory ) if ($VstsAccount -match "https*://" -or $VstsAccount -match "visualstudio.com") { Write-Error "Azure DevOps account '$VstsAccount' should not be the URL, just the account name." } if (![string]::IsNullOrWhiteSpace($WorkDirectory) -and !(Test-ValidPath -Path $WorkDirectory)) { Write-Error "Work directory '$WorkDirectory' is not a valid path." } } function Test-ValidPath { param( [string] $Path ) $isValid = Test-Path -Path $Path -IsValid -PathType Container try { [IO.Path]::GetFullPath($Path) | Out-Null } catch { $isValid = $false } return $isValid } function Test-AgentExists { [CmdletBinding()] param( [string] $InstallPath, [string] $AgentName ) $agentConfigFile = Join-Path $InstallPath '.agent' if (Test-Path $agentConfigFile) { Write-Error "Agent $AgentName is already configured in this machine" } } function New-AgentInstallPath { [CmdletBinding()] param( [string] $DriveLetter, [string] $AgentName ) [string] $agentInstallPath = $null # Construct the agent folder under the specified drive. $agentInstallDir = $DriveLetter + ":" try { # Create the directory for this agent. $agentInstallPath = Join-Path -Path $agentInstallDir -ChildPath $AgentName New-Item -ItemType Directory -Force -Path $agentInstallPath | Out-Null } catch { $agentInstallPath = $null Write-Error "Failed to create the agent directory at $installPathDir." } return $agentInstallPath } function Get-AgentInstaller { param( [string] $InstallPath ) $agentTempFolderName = "C:\agent" if (!(Test-Path $InstallPath)) { Write-Error "Agent install path doesn't exist: $InstallPath" } else { $agentExePath = Join-Path $agentTempFolderName "config.cmd" if (!(Test-Path $agentExePath)) { Write-Error "Agent installer file not found: $agentExePath" } } return $agentExePath } function Set-MachineForAutologon { param( $Config ) if ([string]::IsNullOrWhiteSpace($Config.WindowsLogonPassword)) { Write-Error "Windows logon password was not provided. Please retry by providing a valid windows logon password to enable autologon." } # Create a PS session for the user to trigger the creation of the registry entries required for autologon $computerName = "localhost" $password = ConvertTo-SecureString $Config.WindowsLogonPassword -AsPlainText -Force if ($Config.WindowsLogonAccount.Split("\").Count -eq 2) { $domain = $Config.WindowsLogonAccount.Split("\")[0] $userName = $Config.WindowsLogonAccount.Split('\')[1] } else { $domain = $Env:ComputerName $userName = $Config.WindowsLogonAccount } $credentials = New-Object System.Management.Automation.PSCredential("$domain\\$userName", $password) Enter-PSSession -ComputerName $computerName -Credential $credentials Exit-PSSession try { # Check if the HKU drive already exists Get-PSDrive -PSProvider Registry -Name HKU | Out-Null $canCheckRegistry = $true } catch [System.Management.Automation.DriveNotFoundException] { try { # Create the HKU drive New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS | Out-Null $canCheckRegistry = $true } catch { # Ignore the failure to create the drive and go ahead with trying to set the agent up Write-Warning "Moving ahead with agent setup as the script failed to create HKU drive necessary for checking if the registry entry for the user's SId exists.\n$_" } } # 120 seconds timeout $timeout = 120 # Check if the registry key required for enabling autologon is present on the machine, if not wait for 120 seconds in case the user profile is still getting created while ($timeout -ge 0 -and $canCheckRegistry) { $objUser = New-Object System.Security.Principal.NTAccount($Config.WindowsLogonAccount) $securityId = $objUser.Translate([System.Security.Principal.SecurityIdentifier]) $securityId = $securityId.Value if (Test-Path "HKU:\\$securityId") { if (!(Test-Path "HKU:\\$securityId\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run")) { New-Item -Path "HKU:\\$securityId\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run" -Force Write-Host "Created the registry entry path required to enable autologon." } break } else { $timeout -= 10 Start-Sleep(10) } } if ($timeout -lt 0) { Write-Warning "Failed to find the registry entry for the SId of the user, this is required to enable autologon. Trying to start the agent anyway." } } function Install-Agent { param( $Config ) try { # Set the current directory to the agent dedicated one previously created. Push-Location -Path $Config.AgentInstallPath if ($Config.RunAsAutoLogon) { Set-MachineForAutologon -Config $Config # Arguements to run agent with autologon enabled $agentConfigArgs = "--unattended", "--url", $Config.ServerUrl, "--auth", "PAT", "--token", $Config.VstsUserPassword, "--pool", $Config.PoolName, "--agent", $Config.AgentName, "--runAsAutoLogon", "--overwriteAutoLogon", "--windowslogonaccount", $Config.WindowsLogonAccount } else { # Arguements to run agent as a service $agentConfigArgs = "--unattended", "--url", $Config.ServerUrl, "--auth", "PAT", "--token", $Config.VstsUserPassword, "--pool", $Config.PoolName, "--agent", $Config.AgentName, "--runasservice", "--windowslogonaccount", $Config.WindowsLogonAccount } if (-not [string]::IsNullOrWhiteSpace($Config.WindowsLogonPassword)) { $agentConfigArgs += "--windowslogonpassword", $Config.WindowsLogonPassword } if (-not [string]::IsNullOrWhiteSpace($Config.WorkDirectory)) { $agentConfigArgs += "--work", $Config.WorkDirectory } & $Config.AgentExePath $agentConfigArgs if ($LASTEXITCODE -ne 0) { Write-Error "Agent configuration failed with exit code: $LASTEXITCODE" } } finally { Pop-Location } } ################################################################################################### # # Handle all errors in this script. # trap { # NOTE: This trap will handle all errors. There should be no need to use a catch below in this # script, unless you want to ignore a specific error. Show-LastError } ################################################################################################### # # Main execution block. # try { Write-Host 'Validating agent parameters' Test-Parameters -VstsAccount $vstsAccount -WorkDirectory $workDirectory Write-Host 'Preparing agent installation location' $agentInstallPath = New-AgentInstallPath -DriveLetter $driveLetter -AgentName $agentName Write-Host 'Checking for previously configured agent' Test-AgentExists -InstallPath $agentInstallPath -AgentName $agentName Write-Host "Getting agent installer path $agentInstallPath" $agentExePath = Get-AgentInstaller -InstallPath $agentInstallPath # Call the agent with the configure command and all the options (this creates the settings file) # without prompting the user or blocking the cmd execution. Write-Host 'Installing agent' $config = @{ AgentExePath = $agentExePath AgentInstallPath = $agentInstallPath AgentName = $agentName PoolName = $poolName ServerUrl = "https://$VstsAccount.visualstudio.com" VstsUserPassword = $vstsUserPassword RunAsAutoLogon = $runAsAutoLogon WindowsLogonAccount = $windowsLogonAccount WindowsLogonPassword = $windowsLogonPassword WorkDirectory = $workDirectory } Install-Agent -Config $config Write-Host 'Done' } finally { Pop-Location } } function Install-VstsAgent { # Downloads the Visual Studio Online Build Agent, installs on the new machine, registers with the Visual # Studio Online account, and adds to the specified build agent pool [CmdletBinding()] param( [Parameter(Mandatory = $true)][string]$vstsAccount, [Parameter(Mandatory = $true)][string]$vstsUserPassword, [Parameter(Mandatory = $true)][string]$agentName, [Parameter(Mandatory = $false)][string]$agentNameSuffix, [Parameter(Mandatory = $true)][string]$poolName, [Parameter(Mandatory = $true)][string]$windowsLogonAccount, [Parameter(Mandatory = $false)][string]$windowsLogonPassword, [Parameter(Mandatory = $true)][ValidatePattern("[c-zC-Z]")][ValidateLength(1, 1)][string]$driveLetter, [Parameter(Mandatory = $false)][string]$workDirectory, [Parameter(Mandatory = $true)][boolean]$runAsAutoLogon ) Write-Output "-----------------------------------------------------------------------------------" Write-Output "Installing VSTS Agent..." ################################################################################################### # if the agentName is empty, use %COMPUTERNAME% as the value if ([String]::IsNullOrWhiteSpace($agentName)) { $agentName = $env:COMPUTERNAME } # if the agentNameSuffix has a value, add this to the end of the agent name if (![String]::IsNullOrWhiteSpace($agentNameSuffix)) { $agentName = $agentName + $agentNameSuffix } # # PowerShell configurations # # NOTE: Because the $ErrorActionPreference is "Stop", this script will stop on first failure. # This is necessary to ensure we capture errors inside the try-catch-finally block. $ErrorActionPreference = "Stop" # Ensure we set the working directory to that of the script. Push-Location $PSScriptRoot # Configure strict debugging. Set-PSDebug -Strict ################################################################################################### # # Functions used in this script. # function Show-LastError { [CmdletBinding()] param( ) $message = $error[0].Exception.Message if ($message) { Write-Host -Object "ERROR: $message" -ForegroundColor Red } # IMPORTANT NOTE: Throwing a terminating error (using $ErrorActionPreference = "Stop") still # returns exit code zero from the PowerShell script when using -File. The workaround is to # NOT use -File when calling this script and leverage the try-catch-finally block and return # a non-zero exit code from the catch block. exit -1 } function Test-Parameters { [CmdletBinding()] param( [string] $VstsAccount, [string] $WorkDirectory ) if ($VstsAccount -match "https*://" -or $VstsAccount -match "visualstudio.com") { Write-Error "VSTS account '$VstsAccount' should not be the URL, just the account name." } if (![string]::IsNullOrWhiteSpace($WorkDirectory) -and !(Test-ValidPath -Path $WorkDirectory)) { Write-Error "Work directory '$WorkDirectory' is not a valid path." } } function Test-ValidPath { param( [string] $Path ) $isValid = Test-Path -Path $Path -IsValid -PathType Container try { [IO.Path]::GetFullPath($Path) | Out-Null } catch { $isValid = $false } return $isValid } function Test-AgentExists { [CmdletBinding()] param( [string] $InstallPath, [string] $AgentName ) $agentConfigFile = Join-Path $InstallPath '.agent' if (Test-Path $agentConfigFile) { Write-Error "Agent $AgentName is already configured in this machine" } } function Get-AgentPackage { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUsernameAndPasswordParams", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] [CmdletBinding()] param( [string] $VstsAccount, [string] $VstsUserPassword ) # Create a temporary directory where to download from VSTS the agent package (agent.zip). $agentTempFolderName = Join-Path $env:temp ([System.IO.Path]::GetRandomFileName()) New-Item -ItemType Directory -Force -Path $agentTempFolderName | Out-Null $agentPackagePath = "$agentTempFolderName\agent.zip" $serverUrl = "https://$VstsAccount.visualstudio.com" $vstsAgentUrl = "$serverUrl/_apis/distributedtask/packages/agent/win-x64?`$top=1&api-version=3.0" $vstsUser = "AzureDevTestLabs" $maxRetries = 3 $retries = 0 do { try { $basicAuth = ("{0}:{1}" -f $vstsUser, $vstsUserPassword) $basicAuth = [System.Text.Encoding]::UTF8.GetBytes($basicAuth) $basicAuth = [System.Convert]::ToBase64String($basicAuth) $headers = @{ Authorization = ("Basic {0}" -f $basicAuth) } $agentList = Invoke-RestMethod -Uri $vstsAgentUrl -Headers $headers -Method Get -ContentType application/json $agent = $agentList.value if ($agent -is [Array]) { $agent = $agentList.value[0] } Invoke-WebRequest -Uri $agent.downloadUrl -Headers $headers -Method Get -OutFile "$agentPackagePath" -UseBasicParsing | Out-Null break } catch { $exceptionText = ($_ | Out-String).Trim() if (++$retries -gt $maxRetries) { Write-Error "Failed to download agent due to $exceptionText" } Start-Sleep -Seconds 1 } } while ($retries -le $maxRetries) return $agentPackagePath } function New-AgentInstallPath { [CmdletBinding()] param( [string] $DriveLetter, [string] $AgentName ) [string] $agentInstallPath = $null # Construct the agent folder under the specified drive. $agentInstallDir = $DriveLetter + ":" try { # Create the directory for this agent. $agentInstallPath = Join-Path -Path $agentInstallDir -ChildPath $AgentName New-Item -ItemType Directory -Force -Path $agentInstallPath | Out-Null } catch { $agentInstallPath = $null Write-Error "Failed to create the agent directory at $installPathDir." } return $agentInstallPath } function Get-AgentInstaller { param( [string] $InstallPath ) $agentExePath = [System.IO.Path]::Combine($InstallPath, 'config.cmd') if (![System.IO.File]::Exists($agentExePath)) { Write-Error "Agent installer file not found: $agentExePath" } return $agentExePath } function Set-MachineForAutologon { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUsernameAndPasswordParams", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] [cmdletbinding()] param( $Config ) if ([string]::IsNullOrWhiteSpace($Config.WindowsLogonPassword)) { Write-Error "Windows logon password was not provided. Please retry by providing a valid windows logon password to enable autologon." } # Create a PS session for the user to trigger the creation of the registry entries required for autologon $computerName = "localhost" $password = ConvertTo-SecureString $Config.WindowsLogonPassword -AsPlainText -Force if ($Config.WindowsLogonAccount.Split("\").Count -eq 2) { $domain = $Config.WindowsLogonAccount.Split("\")[0] $userName = $Config.WindowsLogonAccount.Split('\')[1] } else { $domain = $Env:ComputerName $userName = $Config.WindowsLogonAccount } $credentials = New-Object System.Management.Automation.PSCredential("$domain\\$userName", $password) Enter-PSSession -ComputerName $computerName -Credential $credentials Exit-PSSession try { # Check if the HKU drive already exists Get-PSDrive -PSProvider Registry -Name HKU | Out-Null $canCheckRegistry = $true } catch [System.Management.Automation.DriveNotFoundException] { try { # Create the HKU drive New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS | Out-Null $canCheckRegistry = $true } catch { # Ignore the failure to create the drive and go ahead with trying to set the agent up Write-Warning "Moving ahead with agent setup as the script failed to create HKU drive necessary for checking if the registry entry for the user's SId exists.\n$_" } } # 120 seconds timeout $timeout = 120 # Check if the registry key required for enabling autologon is present on the machine, if not wait for 120 seconds in case the user profile is still getting created while ($timeout -ge 0 -and $canCheckRegistry) { $objUser = New-Object System.Security.Principal.NTAccount($Config.WindowsLogonAccount) $securityId = $objUser.Translate([System.Security.Principal.SecurityIdentifier]) $securityId = $securityId.Value if (Test-Path "HKU:\\$securityId") { if (!(Test-Path "HKU:\\$securityId\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run")) { New-Item -Path "HKU:\\$securityId\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run" -Force Write-Host "Created the registry entry path required to enable autologon." } break } else { $timeout -= 10 Start-Sleep(10) } } if ($timeout -lt 0) { Write-Warning "Failed to find the registry entry for the SId of the user, this is required to enable autologon. Trying to start the agent anyway." } } function Install-Agent { param( $Config ) try { # Set the current directory to the agent dedicated one previously created. Push-Location -Path $Config.AgentInstallPath if ($Config.RunAsAutoLogon) { Set-MachineForAutologon -Config $Config # Arguements to run agent with autologon enabled $agentConfigArgs = "--unattended", "--url", $Config.ServerUrl, "--auth", "PAT", "--token", $Config.VstsUserPassword, "--pool", $Config.PoolName, "--agent", $Config.AgentName, "--runAsAutoLogon", "--overwriteAutoLogon", "--windowslogonaccount", $Config.WindowsLogonAccount } else { # Arguements to run agent as a service $agentConfigArgs = "--unattended", "--url", $Config.ServerUrl, "--auth", "PAT", "--token", $Config.VstsUserPassword, "--pool", $Config.PoolName, "--agent", $Config.AgentName, "--runasservice", "--windowslogonaccount", $Config.WindowsLogonAccount } if (-not [string]::IsNullOrWhiteSpace($Config.WindowsLogonPassword)) { $agentConfigArgs += "--windowslogonpassword", $Config.WindowsLogonPassword } if (-not [string]::IsNullOrWhiteSpace($Config.WorkDirectory)) { $agentConfigArgs += "--work", $Config.WorkDirectory } & $Config.AgentExePath $agentConfigArgs if ($LASTEXITCODE -ne 0) { Write-Error "Agent configuration failed with exit code: $LASTEXITCODE" } } finally { Pop-Location } } ################################################################################################### # # Handle all errors in this script. # trap { # NOTE: This trap will handle all errors. There should be no need to use a catch below in this # script, unless you want to ignore a specific error. Show-LastError } ################################################################################################### # # Main execution block. # try { Write-Host 'Validating agent parameters' Test-Parameters -VstsAccount $vstsAccount -WorkDirectory $workDirectory Write-Host 'Preparing agent installation location' $agentInstallPath = New-AgentInstallPath -DriveLetter $driveLetter -AgentName $agentName Write-Host 'Checking for previously configured agent' Test-AgentExists -InstallPath $agentInstallPath -AgentName $agentName Write-Host 'Downloading agent package' $agentPackagePath = Get-AgentPackage -VstsAccount $vstsAccount -VstsUserPassword $vstsUserPassword Write-Host 'Extracting agent package contents' Expand-Archive -LiteralPath $agentPackagePath -DestinationPath $agentInstallPath Write-Host 'Getting agent installer path' $agentExePath = Get-AgentInstaller -InstallPath $agentInstallPath # Call the agent with the configure command and all the options (this creates the settings file) # without prompting the user or blocking the cmd execution. Write-Host 'Installing agent' $config = @{ AgentExePath = $agentExePath AgentInstallPath = $agentInstallPath AgentName = $agentName PoolName = $poolName ServerUrl = "https://$VstsAccount.visualstudio.com" VstsUserPassword = $vstsUserPassword RunAsAutoLogon = $runAsAutoLogon WindowsLogonAccount = $windowsLogonAccount WindowsLogonPassword = $windowsLogonPassword WorkDirectory = $workDirectory } Install-Agent -Config $config Write-Host 'Done' } finally { Pop-Location } } function Get-SystemData { # Get available Volume size $LogicalDisk = Get-WmiObject -Class win32_logicaldisk -Property * $FreeSpace = $LogicalDisk.FreeSpace / 1GB $Size = $LogicalDisk.Size / 1GB Write-Output "$($FreeSpace.ToString("#.##")) of $($Size.ToString("#.##")) GB disk space available" } function Watch-VstsAgentService { Write-Output "This container will keep running as long as the Azure DevOps agent (vstsagent) service in it is not interrupted for longer than 3 minutes." $TryCount = 0 while ($true) { if ((Get-Service "vstsagent*").Status -eq "Running") { Start-Sleep -Seconds 60 | Out-Null # Test-Connection -ComputerName localhost -Quiet -Delay 60 | Out-Null } else { $TryCount++ } if ($TryCount -gt 3) { break } } } #endregion #region Main # Record start time $StartDate = Get-Date Write-Output "-----------------------------------------------------------------------------------" Write-Host "Configuration started at $StartDate" # Set SSL version preference [Net.ServicePointManager]::SecurityProtocol = "Tls12, Tls11, Tls" # Original: Ssl3, Tls # Install Chocolatey $ChocoInstallStart = Get-Date if ($UseChocolatey -eq $true) { Install-Choco $ChocoInstallEnd = Get-Date $ChocoInstallDuration = New-TimeSpan -Start $ChocoInstallStart -End $ChocoInstallEnd Write-Host "Chocolatey installation took $($ChocoInstallDuration.Hours.ToString("00")):$($ChocoInstallDuration.Minutes.ToString("00")):$($ChocoInstallDuration.Seconds.ToString("00")) (HH:mm:ss)" } # Install Terraform $TerraformInstallStart = Get-Date if ($UseChocolatey -eq $true) { Install-ChocoTerraform } else { Install-Terraform } $TerraformInstallEnd = Get-Date $TerraformInstallDuration = New-TimeSpan -Start $TerraformInstallStart -End $TerraformInstallEnd Write-Host "Terraform installation took $($TerraformInstallDuration.Hours.ToString("00")):$($TerraformInstallDuration.Minutes.ToString("00")):$($TerraformInstallDuration.Seconds.ToString("00")) (HH:mm:ss)" # Install Json2HCL $Json2HclInstallStart = Get-Date Install-Json2Hcl $Json2HclInstallEnd = Get-Date $Json2HclInstallDuration = New-TimeSpan -Start $Json2HclInstallStart -End $Json2HclInstallEnd Write-Host "Json2HCL installation took $($Json2HclInstallDuration.Hours.ToString("00")):$($Json2HclInstallDuration.Minutes.ToString("00")):$($Json2HclInstallDuration.Seconds.ToString("00")) (HH:mm:ss)" # Install Nuget $NugetInstallStart = Get-Date Install-Nuget $NugetInstallEnd = Get-Date $NugetInstallDuration = New-TimeSpan -Start $NugetInstallStart -End $NugetInstallEnd Write-Host "Nuget installation took $($NugetInstallDuration.Hours.ToString("00")):$($NugetInstallDuration.Minutes.ToString("00")):$($NugetInstallDuration.Seconds.ToString("00")) (HH:mm:ss)" # Install Powershell Modules $PoShModuleInstallStart = Get-Date Install-PowerShellModules -RequiredModules $RequiredPowerShellModules $PoShModuleInstallEnd = Get-Date $PoShModuleInstallDuration = New-TimeSpan -Start $PoShModuleInstallStart -End $PoShModuleInstallEnd Write-Host "PowerShell module installation took $($PoShModuleInstallDuration.Hours.ToString("00")):$($PoShModuleInstallDuration.Minutes.ToString("00")):$($PoShModuleInstallDuration.Seconds.ToString("00")) (HH:mm:ss)" # Install Azure CLI $AzureCliInstallStart = Get-Date if ($InstallAzureCli -eq $true) { if ($UseChocolatey -eq $true) { Install-ChocoAzureCli } else { Install-AzureCli } $AzureCliInstallEnd = Get-Date $AzureCliInstallDuration = New-TimeSpan -Start $AzureCliInstallStart -End $AzureCliInstallEnd Write-Output "Azure CLI installation took $($AzureCliInstallDuration.Hours.ToString("00")):$($AzureCliInstallDuration.Minutes.ToString("00")):$($AzureCliInstallDuration.Seconds.ToString("00")) (HH:mm:ss)" } # Install PowerShell Core $PoShCoreInstallStart = Get-Date if ($InstallPowerShellCore -eq $true) { if ($UseChocolatey -eq $true) { Install-ChocoPowerShellCore } else { Install-PowerShellCore } $PoShCoreInstallEnd = Get-Date $PoShCoreInstallDuration = New-TimeSpan -Start $PoShCoreInstallStart -End $PoShCoreInstallEnd Write-Output "PowerShell Core installation took $($PoShCoreInstallDuration.Hours.ToString("00")):$($PoShCoreInstallDuration.Minutes.ToString("00")):$($PoShCoreInstallDuration.Seconds.ToString("00")) (HH:mm:ss)" } # Install VSTS Agent $AgentInstallStart = Get-Date $AgentName = "$AgentNamePrefix-$(Get-Date -Format yyyyMMdd-HHmmss)" if ($UseChocolatey -eq $true) { Install-ChocoVstsAgent -vstsAccount $VSTSAccountName -vstsUserPassword $PATToken -agentName $AgentName -poolName $PoolName -windowsLogonAccount "NT AUTHORITY\NetworkService" -driveLetter "C" -runAsAutoLogon:$false } else { Install-VstsAgent -vstsAccount $VSTSAccountName -vstsUserPassword $PATToken -agentName $AgentName -poolName $PoolName -windowsLogonAccount "NT AUTHORITY\NetworkService" -driveLetter "C" -runAsAutoLogon:$false } $AgentInstallEnd = Get-Date $AgentInstallDuration = New-TimeSpan -Start $AgentInstallStart -End $AgentInstallEnd Write-Host "Agent installation took $($AgentInstallDuration.Hours.ToString("00")):$($AgentInstallDuration.Minutes.ToString("00")):$($AgentInstallDuration.Seconds.ToString("00")) (HH:mm:ss)" # Get available Volume size, RAM Write-Output "-----------------------------------------------------------------------------------" Get-SystemData # Calculate duration $OverallDuration = New-TimeSpan -Start $StartDate -End (Get-Date) Write-Output "-----------------------------------------------------------------------------------" Write-Host "It took $($OverallDuration.Hours.ToString("00")):$($OverallDuration.Minutes.ToString("00")):$($OverallDuration.Seconds.ToString("00")) (HH:mm:ss) to install the required components." Write-Host "Installation finished at $(Get-Date)" Write-Host "Container successfully configured." # Do NOT change this text, as this is the success criteria for the wrapper script. # Keep the container running by checking if the VSTS service is up Write-Output "-----------------------------------------------------------------------------------" Watch-VstsAgentService #endregion # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUu1cpQ9vh4J+hzFU/c3YW9C4J # flugggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBR53uHcZr/UgRVwXu6uR9unXJ4R # CzANBgkqhkiG9w0BAQEFAASCAQCNRzZa1SvIfzZvGCNW5Q5mwByTNfEwWIQsJ4Wc # 2uOc3opBj4QNotkaVi+isoR6Kco+SeRJ6XNmrf3G/GDkfwhSCaFw8Gu7TnTHAR29 # LXeHbRSl1ibDgygrlX+Ag6E7VMS2E5STqDleLzsx2XUK0tenV4p7MKs9hHja1kev # HUHcAMbKR3OOsLPi1laI1vCwWroECRk3SLIzh5CUg+9zPKzDsQ2IA3qfW70ES6p4 # 3bg++PAN4SC/2D5LfrUUlpieZlMEfVuOcUCRPuPMiIon/+zcWB7JKjmD4sh5sXDB # AkGUPvm0VR2GzeD+PkwZYM97lIt1ID8V6+e/bTWTwiT1INdf # SIG # End signature block ================================================ FILE: developing/Archive/tests/build/Remove-VstsAgentOnWindowsServerCoreContainer.ps1 ================================================ ######################################################################################################################## # Script Disclaimer ######################################################################################################################## # This script is not supported under any Microsoft standard support program or service. # This script is provided AS IS without warranty of any kind. # Microsoft disclaims all implied warranties including, without limitation, any implied warranties of # merchantability or of fitness for a particular purpose. The entire risk arising out of the use or # performance of this script and documentation remains with you. In no event shall Microsoft, its authors, # or anyone else involved in the creation, production, or delivery of this script be liable for any damages # whatsoever (including, without limitation, damages for loss of business profits, business interruption, # loss of business information, or other pecuniary loss) arising out of the use of or inability to use # this script or documentation, even if Microsoft has been advised of the possibility of such damages. <# .SYNOPSIS This script removes the selected Azure Container Instance(s). .DESCRIPTION This script removes the selected Azure Container Instance(s). It leaves the Resource Group (and other resources within it) intact. This script is designed and tested to be run from Azure Cloud Shell. .PARAMETER SubscriptionName Name of the Subscription. .PARAMETER ResourceGroupName Name of the Resource Group. .PARAMETER ContainerName Name of the ACI container(s). .PARAMETER PatToken PAT token required to log in to Azure DevOps to delete the Agent's registration from the pool. .PARAMETER AzureDevOpsAccountName Name of the Azure DevOps account that the Agent is registered to. .PARAMETER AgentPoolName Name of the Agent Pool that holds the Agent to delete. .EXAMPLE .\Remove-VstsAgentOnWindowsServerCoreContainer.ps1 -SubscriptionName "" -ResourceGroupName "" -ContainerName "", "" -PatToken "" -AzureDevOpsAccountName "" -AgentPoolName "" This removes the 2 requested containers and their registrations from Azure DevOps. It leaves the Resource Group (and other resources within) intact. .INPUTS .OUTPUTS .NOTES Version: 1.1 Author: Mate Barabas Creation Date: 2018-08-29 Change log: - v1.1 (2019-04-06): the script now removes the Agent's registration from the Agent pool #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUsernameAndPasswordParams", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidTrailingWhiteSpace", "")] param( [Parameter(Mandatory = $true)][string]$SubscriptionName, [Parameter(Mandatory = $true)][string]$ResourceGroupName, [Parameter(Mandatory = $true)][array]$ContainerName, [Parameter(Mandatory = $true)][string]$PatToken, #Personal access token [Parameter(Mandatory = $true)][string]$AzureDevOpsAccountName, #Azure DevOps account name [Parameter(Mandatory = $true)][string]$AgentPoolName #Azure DevOps Agent pool name ) #region Functions function Set-AzureContext { param ( [Parameter(Mandatory = $false)][string]$SubscriptionName ) # Select the desired Subscription based on the Subscription name provided if ($SubscriptionName) { $Subscription = (Get-AzureRmSubscription | Where-Object { $_.Name -eq $SubscriptionName }) if (-not $Subscription) { Write-Error "There's no Subscription available with the provided name." return } else { $SubscriptionId = $Subscription.Id Select-AzureRmSubscription -SubscriptionId $SubscriptionId | Out-Null Write-Output "The following subscription was selected: ""$SubscriptionName""" } } # If no Subscription name was provided select the active Subscription based on the existing context else { $SubscriptionName = (Get-AzureRmContext).Subscription.Name $Subscription = (Get-AzureRmSubscription | Where-Object { $_.Name -eq $SubscriptionName }) Write-Output "The following subscription was selected: ""$SubscriptionName""" } if ($Subscription.Count -gt 1) { Write-Error "You have more then 1 Subscription with the same name. Exiting..." return } } function Remove-Container { param ( [Parameter(Mandatory = $true)][array]$ContainerName ) foreach ($Name in $ContainerName) { $Container = Get-AzureRmContainerGroup -ResourceGroupName $ResourceGroupName -Name $Name -ErrorAction SilentlyContinue if (-not $Container) { Write-Warning "No ACI container exists with the provided name ($Name)." } else { Write-Warning "Removing selected ACI container ($Name)..." Remove-AzureRmContainerGroup -ResourceGroupName $ResourceGroupName -Name $Name -Confirm:$false # Check success $Container = Get-AzureRmContainerGroup -ResourceGroupName $ResourceGroupName -Name $Name -ErrorAction SilentlyContinue if ($null -eq $Container) { Write-Output "ACI container ""$Name"" successfully deleted." if (-not ($PatToken -and $AgentPoolName -and $AzureDevOpsAccountName)) { Write-Warning "One or more containers have been deleted. Don't forget to clean your Agent pool in Azure DevOps (remove any agents that were created in a previous iteration and are now offline)!" } } } } } function Remove-AzureDevOpsAgentFromPool { Param( [string]$PatToken, #Personal access token [string]$AzureDevOpsAccountName, #Azure DevOps account name [string]$AgentPoolName, #Azure DevOps Agent pool name [array]$ContainerName #Azure DevOps Agent pool name ) $base64AuthInfo = [System.Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($PatToken)")) $Header = @{Authorization = ("Basic $base64AuthInfo") } # Get Agent Pool Write-Output "Getting Agent Pool ($AgentPoolName)..." $uri = "https://dev.azure.com/$AzureDevOpsAccountName/_apis/distributedtask/pools" $result = Invoke-RestMethod -Uri $uri -Method GET -ContentType "application/json" -Headers $Header $AgentPool = $result.value | Where-Object { $_.Name -eq "$AgentPoolName" } $AgentPoolId = $AgentPool.id if (-not $AgentPoolId) { Write-Error "The Agent Pool ($AgentPoolName) doesn't exist!" } else { # Get Agents Write-Output "Getting Agents from Pool..." $uri = "https://dev.azure.com/$AzureDevOpsAccountName/_apis/distributedtask/pools/$AgentPoolId/agents?includeCapabilities=false&includeAssignedRequest=true" $result = Invoke-RestMethod -Uri $uri -Method GET -ContentType "application/json" -Headers $Header $Agents = $result.value if (-not $Agents) { Write-Output "There are no Agents in this Agent Pool" } else { Write-Output "The following agents were found:" foreach ($Agent in $Agents) { $AgentName = $Agent.name $AgentStatus = $Agent.status Write-Output "$AgentName ($AgentStatus)" } # Delete Agent(s) from Pool foreach ($Name in $ContainerName) { Write-Output "Attempting to remove any Agent(s) that belonged to this ACI container: $Name..." foreach ($Agent in $Agents) { $AgentName = $Agent.name if ($AgentName -match "^$Name-") { # Delete Agent $AgentIds = $Agent.id foreach ($AgentId in $AgentIds) { Write-Output "Deleting Agent ($AgentName) - (Agent ID: $AgentId)..." $uri = "https://dev.azure.com/$AzureDevOpsAccountName/_apis/distributedtask/pools/$AgentPoolId/agents/$($AgentId)?api-version=5.0" $result = Invoke-RestMethod -Uri $uri -Method DELETE -ContentType "application/json" -Headers $Header # Check success Write-Output "Checking if the Agent ($AgentName) - (Agent ID: $AgentId) is still there..." $uri = "https://dev.azure.com/$AzureDevOpsAccountName/_apis/distributedtask/pools/$AgentPoolId/agents?includeCapabilities=false&includeAssignedRequest=true" $result = Invoke-RestMethod -Uri $uri -Method GET -ContentType "application/json" -Headers $Header $AgentStillThere = $result.value.id -contains $AgentId if ($AgentStillThere) { Write-Warning "Agent ($AgentName) could not be deleted. Don't forget to clean your Agent pool in Azure Devops (remove any agents that were created in a previous iteration and are now offline)!" } else { Write-Output "Agent ($AgentName) successfully deleted." } } } } } } } } #endregion #region Main # Login to Azure and select Subscription Set-AzureContext -SubscriptionName $SubscriptionName # Delete selected containers Remove-Container -ContainerName $ContainerName # Delete Agent registration from Azure DevOps Agent pool Remove-AzureDevOpsAgentFromPool -PatToken $PatToken -AzureDevOpsAccountName $AzureDevOpsAccountName -AgentPoolName $AgentPoolName -ContainerName $ContainerName #endregion # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUqnC17MmjLJIModmCDDzDSlmd # OEGgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTRWXL978E8G0Ad7rqqqhCDE2a2 # WDANBgkqhkiG9w0BAQEFAASCAQAJLXwSjpFXNvsRTGaJCps/BdPTa4vslCLFIiqk # Hnk9YAdT4avJIEWFJeYPtNG9YYMueEQ778aigPyvFDwdIormXm5ECfm3Ijfo2Pn2 # RXd8zBwb/bNnAYsnmBLw1J9nCz0umVVqv2gGGDZWykclyZXFd4C+qZihRoRS6bUi # rDUDkSN61nPtcv3naa2a99NV8qcZeXEvXhivDxz7gqGSTqWCEDzt868q4dAN81gi # sWbrsiUCrNL313euZRW5zH6DICgmXLacqKam1gvIdWqLpYVX/OSfZh1DIR7UG/xm # CFMzSSJ0SeOYYEGQd6vzv9qz2woDmsQcsbnHqZjimWzEIeJa # SIG # End signature block ================================================ FILE: developing/Archive/tests/checks/AgentChecks.Tests.ps1 ================================================ # load all of the assertion functions (Get-ChildItem $PSScriptRoot/../../internal/assertions/).ForEach{. $Psitem.FullName} Describe "Checking Agent.Tests.ps1 checks" -Tag UnitTest, AgentAssertions { Context "Checking Database Mail XPs" { # Mock the version check for running tests Mock Connect-DbaInstance {} # Define test cases for the results to fail test and fill expected message # So the results of SPConfigure is 1, we expect $false but the result is true and the results of SPConfigure is 0, we expect $true but the result is false $TestCases = @{spconfig = 1; expected = $false; actual = $true}, @{spconfig = 0; expected = $true; actual = $false} It "Fails Check Correctly for Config and expected value " -TestCases $TestCases { Param($spconfig, $actual, $expected) Mock Get-DbaSpConfigure {@{"ConfiguredValue" = $spconfig}} {Assert-DatabaseMailEnabled -SQLInstance 'Dummy' -DatabaseMailEnabled $expected} | Should -Throw -ExpectedMessage "Expected `$$expected, because The Database Mail XPs setting should be set correctly, but got `$$actual" } $TestCases = @{spconfig = 0; expected = $false}, @{spconfig = 1; expected = $true; } It "Passes Check Correctly for Config and expected value " -TestCases $TestCases { Param($spconfig, $expected) Mock Get-DbaSpConfigure {@{"ConfiguredValue" = $spconfig}} Assert-DatabaseMailEnabled -SQLInstance 'Dummy' -DatabaseMailEnabled $expected } # Validate we have called the mock the correct number of times It "Should call the mocks" { $assertMockParams = @{ 'CommandName' = 'Get-DbaSpConfigure' 'Times' = 4 'Exactly' = $true } Assert-MockCalled @assertMockParams } } Context "Checking Job History" { # if configured value for MaximumHistoryRows is -1 and test value -1 it will pass It "Passes Check Correctly with Maximum History Rows disabled (-1)" { # Mock to pass Mock Get-DbaAgentServer { [PSCustomObject]@{ MaximumHistoryRows = -1; MaximumJobHistoryRows = 0; } } $AgentServer = Get-DbaAgentServer -SqlInstance "Dummy" -EnableException:$false Assert-JobHistoryRowsDisabled -AgentServer $AgentServer -minimumJobHistoryRows -1 } # if configured value for MaximumHistoryRows is -1 and test value -1 it will pass It "Fails Check Correctly with Maximum History Rows disabled (-1) but configured value is 1000" { # Mock to fail Mock Get-DbaAgentServer { [PSCustomObject]@{ MaximumHistoryRows = 1000; MaximumJobHistoryRows = 0; } } $AgentServer = Get-DbaAgentServer -SqlInstance "Dummy" -EnableException:$false { Assert-JobHistoryRowsDisabled -AgentServer $AgentServer -minimumJobHistoryRows -1 } | Should -Throw -ExpectedMessage "Expected '-1', because Maximum job history configuration should be disabled, but got 1000." } # if configured value for MaximumHistoryRows is 10000 and test value 10000 it will pass It "Passes Check Correctly with Maximum History Rows being 10000" { # Mock to pass Mock Get-DbaAgentServer { [PSCustomObject]@{ MaximumHistoryRows = 10000; MaximumJobHistoryRows = 0; } } $AgentServer = Get-DbaAgentServer -SqlInstance "Dummy" -EnableException:$false Assert-JobHistoryRows -AgentServer $AgentServer -minimumJobHistoryRows 10000 } # if configured value for MaximumHistoryRows is -1 and test value -1 it will pass It "Fails Check Correctly with Maximum History Rows being less than 10000" { # Mock to fail Mock Get-DbaAgentServer { [PSCustomObject]@{ MaximumHistoryRows = 1000; MaximumJobHistoryRows = 0; } } $AgentServer = Get-DbaAgentServer -SqlInstance "Dummy" -EnableException:$false { Assert-JobHistoryRows -AgentServer $AgentServer -minimumJobHistoryRows 10000 } | Should -Throw -ExpectedMessage "Expected the actual value to be greater than or equal to 10000, because We expect the maximum job history row configuration to be greater than the configured setting 10000, but got 1000." } # if configured value is 100 and test value 100 it will pass It "Passes Check Correctly with Maximum History Rows per job being 100" { # Mock to pass Mock Get-DbaAgentServer { [PSCustomObject]@{ MaximumHistoryRows = 1000; MaximumJobHistoryRows = 100; } } $AgentServer = Get-DbaAgentServer -SqlInstance "Dummy" -EnableException:$false Assert-JobHistoryRowsPerJob -AgentServer $AgentServer -minimumJobHistoryRowsPerJob 100 } # if configured value is -1 and test value -1 it will pass It "Fails Check Correctly with Maximum History Rows per job being less than 100" { # Mock to fail Mock Get-DbaAgentServer { [PSCustomObject]@{ MaximumHistoryRows = 100; MaximumJobHistoryRows = 50; } } $AgentServer = Get-DbaAgentServer -SqlInstance "Dummy" -EnableException:$false { Assert-JobHistoryRowsPerJob -AgentServer $AgentServer -minimumJobHistoryRowsPerJob 100 } | Should -Throw -ExpectedMessage "Expected the actual value to be greater than or equal to 100, because We expect the maximum job history row configuration per agent job to be greater than the configured setting 100, but got 50." } # Validate we have called the mock the correct number of times It "Should call the mocks" { $assertMockParams = @{ 'CommandName' = 'Get-DbaAgentServer' 'Times' = 6 'Exactly' = $true } Assert-MockCalled @assertMockParams } } Context "Checking running jobs"{ It "Should pass when the running job duration is less than the average job duration" { # Mock to pass $runningjob = @{ JobName = 'Waiting for 5 seconds' AvgSec = 38 StartDate = '30/07/2019 12:17:25' RunningSeconds = 24 Diff = -14 } $runningjobpercentage = 50 Assert-LongRunningJobs -runningjob $runningjob -runningjobpercentage $runningjobpercentage } It "Should pass when the running job duration is the same as the average job duration" { # Mock to pass $runningjob = @{ JobName = 'Waiting for 5 seconds' AvgSec = 38 StartDate = '30/07/2019 12:17:25' RunningSeconds = 38 Diff = 0 } $runningjobpercentage = 50 Assert-LongRunningJobs -runningjob $runningjob -runningjobpercentage $runningjobpercentage } It "Should pass when the running job duration is more than the average job duration but the percentage difference is less than the specified" { # Mock to pass $runningjob = @{ JobName = 'Waiting for 5 seconds' AvgSec = 38 StartDate = '30/07/2019 12:17:25' RunningSeconds = 50 Diff = 12 } $runningjobpercentage = 50 Assert-LongRunningJobs -runningjob $runningjob -runningjobpercentage $runningjobpercentage } It "Should fail when the running job duration is more than the average job duration and the percentage difference is more than the specified" { # Mock to fail $runningjob = @{ JobName = 'Waiting for 5 seconds' AvgSec = 38 StartDate = '30/07/2019 12:17:25' RunningSeconds = 78 Diff = 40 } $runningjobpercentage = 50 {Assert-LongRunningJobs -runningjob $runningjob -runningjobpercentage $runningjobpercentage} | Should -Throw -ExpectedMessage "Expected the actual value to be less than 50, because The current running job Waiting for 5 seconds has been running for 40 seconds longer than the average run time. This is more than the 50 % specified as the maximum, but got 105" } } Context "Checking last run time"{ It "Should pass when the last job run duration is less than the average job duration" { # Mock to pass $lastagentjobrun = @{ JobName = 'Waiting for 5 seconds' AvgSec = 38 Duration = 25 Diff = -13 } $runningjobpercentage = 50 Assert-LastJobRun -lastagentjobrun $lastagentjobrun -runningjobpercentage $runningjobpercentage } It "Should pass when the last job run duration is the same as the average job duration" { # Mock to pass $lastagentjobrun = @{ JobName = 'Waiting for 5 seconds' AvgSec = 38 Duration = 38 Diff = 0 } $runningjobpercentage = 50 Assert-LastJobRun -lastagentjobrun $lastagentjobrun -runningjobpercentage $runningjobpercentage } It "Should pass when the last job run duration is more than the average job duration but the percentage difference is less than the specified" { # Mock to pass $lastagentjobrun = @{ JobName = 'Waiting for 5 seconds' AvgSec = 38 Duration = 48 Diff = 10 } $runningjobpercentage = 50 Assert-LastJobRun -lastagentjobrun $lastagentjobrun -runningjobpercentage $runningjobpercentage } It "Should fail when the last job run duration is more than the average job duration and the percentage difference is more than the specified" { # Mock to fail $lastagentjobrun = @{ JobName = 'Waiting for 5 seconds' AvgSec = 38 Duration = 68 Diff = 30 } $runningjobpercentage = 50 {Assert-LastJobRun -lastagentjobrun $lastagentjobrun -runningjobpercentage $runningjobpercentage} | Should -Throw -ExpectedMessage "Expected the actual value to be less than 50, because The last run of job Waiting for 5 seconds was 68 seconds. This is more than the 50 % specified as the maximum variance, but got 79" } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUmTZjTQTwNKqPz7pIbT43TLIZ # 0v6gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRSvI7x6L3/fpX5iK+Xgh4DyYnE # mjANBgkqhkiG9w0BAQEFAASCAQBaNJ/Z2YcItSXpTK4hl1OChr4Ww93vSVksSuRE # KMxy6CvCqVcl/JRsIzeUAI77ENcACimQ10ZU+MCoekM96etiLQgrh/d2DKK37REk # EVISOtdWAbMnaR0LJklQxBDekSIwW325gL14Y3+UmaZeaT53hrX1xR28YtCRKoUm # Z3ERnfgS3FveVS8XPkKNA1YbkZzkmk4RhISinT4urcE7f/mxxDnvwiHra9N0+YSz # fKIpJHvLyyqvyatEuR94raYmXeZPZjX2SCCTOfz5VJAGhqzkhHnLbQVZLzpcEExq # qtzPMo00dgZOFmeObTxJytfN5EMaBr4XBr4ojbq5ID1FFcgy # SIG # End signature block ================================================ FILE: developing/Archive/tests/checks/DatabaseChecks.Tests.ps1 ================================================ [cmdletbinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '', Justification='stupid implicit aliasing')] Param() # load all of the assertion functions . /../internal/assertions/Database.Assertions.ps1 Describe "Checking Database.Assertions.ps1 assertions" -Tag UnitTest, Assertions, DatabaseAssertions { Context "Testing Get-Database" { It "Should have a Instance parameter" { (Get-Command Get-Database).Parameters['Instance'] | Should -Not -BeNullOrEmpty -Because "We Need to pass the instance in" } It "Should have a ExcludedDbs parameter" { (Get-Command Get-Database).Parameters['ExcludedDbs'] | Should -Not -BeNullOrEmpty -Because "We need to pass in the Excluded Databases - Don't forget that the ExcludedDatabases parameter is set by default so dont use that" } It "Should have a Requiredinfo parameter" { (Get-Command Get-Database).Parameters['Requiredinfo'] | Should -Not -BeNullOrEmpty -Because "We want to be able to choose the information we return" } It "Should have a Exclusions parameter" { (Get-Command Get-Database).Parameters['Exclusions'] | Should -Not -BeNullOrEmpty -Because "We need to be able to excluded databases for various reasons like readonly etc" } Mock Connect-DbaInstance { [PSCustomObject]@{ Databases = @( [PSCustomObject]@{ Name = 'Dummy1'; ReadOnly = $False; Status = 'Normal'; IsAccessible = $True; }, [PSCustomObject]@{ Name = 'Dummy2'; ReadOnly = $False; Status = 'Normal'; IsAccessible = $false; } ); } } It "Should return the Database Names with the Requiredinfo switch parameter value Name" { Get-Database -Instance Dummy -Requiredinfo Name | Should -Be 'Dummy1', 'Dummy2' } It "Should Exclude Databases that are specified for the Name Required Info" { Get-Database -Instance Dummy -Requiredinfo Name -ExcludedDbs Dummy1 | Should -Be 'Dummy2' } It "Should Exclude none accessible databases if the NotAccessible value for Exclusions parameter is used" { Get-Database -Instance Dummy -Requiredinfo Name -Exclusions NotAccessible | Should -Be 'Dummy1' } It "Should call the Mocks" { $assertMockParams = @{ 'CommandName' = 'Connect-DbaInstance' 'Times' = 3 'Exactly' = $true } Assert-MockCalled @assertMockParams } } Context "Testing Assert-DatabaseMaxDop " { ## Mock for Passing Mock Test-DbaMaxDop { @{Database = 'N/A'; DatabaseMaxDop = 'N/A'}, @{Database = 'Dummy1'; DatabaseMaxDop = '1'} } @(Test-DbaMaxDop -SqlInstance Dummy).Where{$_.Database -ne 'N/A'}.ForEach{ It "Passes the test successfully" { Assert-DatabaseMaxDop -MaxDop $PsItem -MaxDopValue 1 } } ## Mock for Failing Mock Test-DbaMaxDop { @{Database = 'N/A'; DatabaseMaxDop = 'N/A'}, @{Database = 'Dummy1'; DatabaseMaxDop = '5'} } @(Test-DbaMaxDop -SqlInstance Dummy).Where{$_.Database -ne 'N/A'}.ForEach{ It "Fails the test successfully" { {Assert-DatabaseMaxDop -MaxDop $PsItem -MaxDopValue 4} | Should -Throw -ExpectedMessage "Expected 4, because We expect the Database MaxDop Value to be the specified value 4, but got '5'." } } It "Calls the Mocks successfully" { $assertMockParams = @{ 'CommandName' = 'Test-DbaMaxDop' 'Times' = 2 'Exactly' = $true } Assert-MockCalled @assertMockParams } } Context "Testing Assert-DatabaseStatus " { #mock for passing Mock Connect-DbaInstance { [PSCustomObject]@{ Databases = @( [PSCustomObject]@{ Name = 'Dummy1'; ReadOnly = $False; Status = 'Normal'; }, [PSCustomObject]@{ Name = 'Dummy2'; ReadOnly = $False; Status = 'Normal'; } ); } } It "It Should Pass when all databases are ok" { Assert-DatabaseStatus Dummy } # Mock for readonly failing Mock Connect-DbaInstance { [PSCustomObject]@{ Databases = @( [PSCustomObject]@{ Name = 'Dummy1'; ReadOnly = $False; Status = 'Normal'; IsDatabaseSnapshot = $false; }, [PSCustomObject]@{ Name = 'Dummy2'; ReadOnly = $True; Status = 'Normal'; IsDatabaseSnapshot = $false; } ); } } It "It Should Fail for a database that is readonly" { { Assert-DatabaseStatus Dummy} | Should -Throw -ExpectedMessage "Expected 'True' to not be found in collection @(`$false, `$true), because We expect that there will be no Read-Only databases except for those specified, but it was found." } It "It Should Not Fail for a database that is readonly when it is excluded" { Assert-DatabaseStatus -Instance Dummy -ExcludeReadOnly 'Dummy2' } It "It Should Not Fail for a snapshots" { Mock Connect-DbaInstance { [PSCustomObject]@{ Databases = @( [PSCustomObject]@{ Name = 'Dummy1'; ReadOnly = $False; Status = 'Normal'; IsDatabaseSnapshot = $false; }, [PSCustomObject]@{ Name = 'Dummy2'; ReadOnly = $True; Status = 'Normal'; IsDatabaseSnapshot = $true; } ); } } Assert-DatabaseStatus -Instance Dummy } # Mock for offline failing Mock Connect-DbaInstance { [PSCustomObject]@{ Databases = @( [PSCustomObject]@{ Name = 'Dummy1'; ReadOnly = $False; Status = 'Offline, AutoClosed'; }, [PSCustomObject]@{ Name = 'Dummy2'; ReadOnly = $False; Status = 'Normal'; } ); } } It "It Should Fail for a database that is offline" { { Assert-DatabaseStatus Dummy} | Should -Throw -ExpectedMessage "Expected regular expression 'Offline' to not match 'Offline, AutoClosed', because We expect that there will be no offline databases except for those specified, but it did match." } It "It Should Not Fail for a database that is offline when it is excluded" { Assert-DatabaseStatus Dummy -ExcludeOffline 'Dummy1' } # Mock for restoring failing Mock Connect-DbaInstance { [PSCustomObject]@{ Databases = @( [PSCustomObject]@{ Name = 'Dummy1'; ReadOnly = $False; Status = 'Restoring'; }, [PSCustomObject]@{ Name = 'Dummy2'; ReadOnly = $False; Status = 'Normal'; } ); } } It "It Should Fail for a database that is restoring" { { Assert-DatabaseStatus Dummy} | Should -Throw -ExpectedMessage "Expected regular expression 'Restoring' to not match 'Restoring', because We expect that there will be no databases in a restoring state except for those specified, but it did match." } It "It Should Not Fail for a database that is restoring when it is excluded" { Assert-DatabaseStatus Dummy -ExcludeRestoring 'Dummy1' } # Mock for recovery failing Mock Connect-DbaInstance { [PSCustomObject]@{ Databases = @( [PSCustomObject]@{ Name = 'Dummy1'; ReadOnly = $False; Status = 'Recovering'; }, [PSCustomObject]@{ Name = 'Dummy2'; ReadOnly = $False; Status = 'Normal'; } ); } } It "It Should Fail for a database that is Recovering" { { Assert-DatabaseStatus Dummy} | Should -Throw -ExpectedMessage "Expected regular expression 'Recover' to not match 'Recovering', because We expect that there will be no databases going through the recovery process or in a recovery pending state, but it did match." } # Mock for recovery pending failing Mock Connect-DbaInstance { [PSCustomObject]@{ Databases = @( [PSCustomObject]@{ Name = 'Dummy1'; ReadOnly = $False; Status = 'RecoveryPending'; }, [PSCustomObject]@{ Name = 'Dummy2'; ReadOnly = $False; Status = 'Normal'; } ); } } It "It Should Fail for a database that is Recovery pending" { { Assert-DatabaseStatus Dummy} | Should -Throw -ExpectedMessage "Expected regular expression 'Recover' to not match 'RecoveryPending', because We expect that there will be no databases going through the recovery process or in a recovery pending state, but it did match." } # Mock for autoclosed failing Mock Connect-DbaInstance { [PSCustomObject]@{ Databases = @( [PSCustomObject]@{ Name = 'Dummy1'; ReadOnly = $False; Status = 'AutoClosed'; }, [PSCustomObject]@{ Name = 'Dummy2'; ReadOnly = $False; Status = 'Normal'; } ); } } It "It Should Fail for a database that is AutoClosed" { { Assert-DatabaseStatus Dummy} | Should -Throw -ExpectedMessage "Expected regular expression 'AutoClosed' to not match 'AutoClosed', because We expect that there will be no databases that have been auto closed, but it did match." } # Mock for EmergencyMode failing Mock Connect-DbaInstance { [PSCustomObject]@{ Databases = @( [PSCustomObject]@{ Name = 'Dummy1'; ReadOnly = $False; Status = 'EmergencyMode'; }, [PSCustomObject]@{ Name = 'Dummy2'; ReadOnly = $False; Status = 'Normal'; } ); } } It "It Should Fail for a database that is EmergencyMode" { { Assert-DatabaseStatus Dummy} | Should -Throw -ExpectedMessage "Expected regular expression 'Emergency' to not match 'EmergencyMode', because We expect that there will be no databases in EmergencyMode, but it did match." } # Mock for Suspect failing Mock Connect-DbaInstance { [PSCustomObject]@{ Databases = @( [PSCustomObject]@{ Name = 'Dummy1'; ReadOnly = $False; Status = 'Suspect'; }, [PSCustomObject]@{ Name = 'Dummy2'; ReadOnly = $False; Status = 'Normal'; } ); } } It "It Should Fail for a database that is Suspect" { { Assert-DatabaseStatus Dummy} | Should -Throw -ExpectedMessage "Expected regular expression 'Suspect' to not match 'Suspect', because We expect that there will be no databases in a Suspect state, but it did match." } # Mock for Standby failing Mock Connect-DbaInstance { [PSCustomObject]@{ Databases = @( [PSCustomObject]@{ Name = 'Dummy1'; ReadOnly = $False; Status = 'Standby'; }, [PSCustomObject]@{ Name = 'Dummy2'; ReadOnly = $False; Status = 'Normal'; } ); } } It "It Should Fail for a database that is Standby" { { Assert-DatabaseStatus Dummy} | Should -Throw -ExpectedMessage "Expected regular expression 'Standby' to not match 'Standby', because We expect that there will be no databases in Standby, but it did match." } It "Should Not Fail for databases that are excluded" { Assert-DatabaseStatus Dummy -Excludedbs 'Dummy1' } It "Should call the Mocks successfully" { $assertMockParams = @{ 'CommandName' = 'Connect-DbaInstance' 'Times' = 15 'Exactly' = $true } Assert-MockCalled @assertMockParams } } Context "Testing Assert-DatabaseDuplicateIndex" { #Mock for passing Mock Find-DbaDbDuplicateIndex {} It "Should pass when there are no Duplicate Indexes" { Assert-DatabaseDuplicateIndex -Instance Dummy -Database Dummy1 } # Mock for failing for 1 index Mock Find-DbaDbDuplicateIndex { [PSCustomObject]@{ DatabaseName = "msdb" TableName = "dbo.log_shipping_primary_databases" IndexName = "UQ__log_ship__2A5EF6DCB9BFAE2F" KeyColumns = "primary_database ASC" IncludedColumns = "" IndexType = "NONCLUSTERED" IndexSizeMB = "0.000000" CompressionDescription = "NONE" RowCount = "0" IsDisabled = "False" IsFiltered = "False" } } It "Should fail for one duplicate index" { {Assert-DatabaseDuplicateIndex -Instance Dummy -Database Dummy1 } | Should -Throw -ExpectedMessage 'Expected 0, because Duplicate indexes waste disk space and cost you extra IO, CPU, and Memory - Use Find-DbaDbDuplicateIndex to find them, but got 1.' } #Mock for failing for 2 indexes Mock Find-DbaDbDuplicateIndex { @([PSCustomObject]@{ DatabaseName = "msdb" TableName = "dbo.log_shipping_primary_databases" IndexName = "UQ__log_ship__2A5EF6DCB9BFAE2F" KeyColumns = "primary_database ASC" IncludedColumns = "" IndexType = "NONCLUSTERED" IndexSizeMB = "0.000000" CompressionDescription = "NONE" RowCount = "0" IsDisabled = "False" IsFiltered = "False" }, [PSCustomObject]@{ DatabaseName = "msdb" TableName = "dbo.log_shipping_primary_databases" IndexName = "UQ__log_ship__2A5EF6DCB9BFAE2F" KeyColumns = "primary_database ASC" IncludedColumns = "" IndexType = "NONCLUSTERED" IndexSizeMB = "0.000000" CompressionDescription = "NONE" RowCount = "0" IsDisabled = "False" IsFiltered = "False" } ) } It "Should fail for more than one duplicate index" { {Assert-DatabaseDuplicateIndex -Instance Dummy -Database Dummy1 } | Should -Throw -ExpectedMessage 'Expected 0, because Duplicate indexes waste disk space and cost you extra IO, CPU, and Memory - Use Find-DbaDbDuplicateIndex to find them, but got 2.' } } Context "Testing Assert-DatabaseExists" { It "Should have a Instance parameter" { (Get-Command Assert-DatabaseExists).Parameters['Instance'] | Should -Not -BeNullOrEmpty -Because "We Need to pass the instance in" } It "Should have a ExpectedDB parameter" { (Get-Command Assert-DatabaseExists).Parameters['ExpectedDB'] | Should -Not -BeNullOrEmpty -Because "We Need to pass the Expected DB in" } # Mock for Passing Mock Get-Database { @('Expected1','Expected2','Expected3','Expected4') } @('Expected1', 'Expected2', 'Expected3', 'Expected4').ForEach{ It "Should Pass when the database exists" { Assert-DatabaseExists -Instance Instance -ExpectedDb $psitem } } It "Should Fail when the database does not exist" { {Assert-DatabaseExists -Instance Instance -ExpectedDb NotThere} | Should -Throw -ExpectedMessage "We expect NotThere to be on Instance" } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUPgcaRfnImNd3g22AxhoOTA7s # s/2gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQvONhty9MasvcoHTA4QqQhp6X4 # WDANBgkqhkiG9w0BAQEFAASCAQAFBW2/JsbUG6TudyVtS3mAXLNSNfCSpWM17WrG # q0SndYWvx8xeduvDlH3Zv1tmHzhX6TM2uVOG2UXGP7Q91T4KH082bkDYEMZPcDA7 # NwmDZl6GF60zH3uIajno0xHXALZAiCWW/jvWpkb4fseed0k3WWZKl3st2L+Sa9Yw # X0+/1gcPJoqXLKujEM4yl5zyz2hh/0k8Di7MTSiifD47wpUwfuttJAprDybX52eV # pTbO0iEE8BLgkkK6CsvYY4c3DrlXTKalKEPdzKUGIAVh9TmFFrrE5wXu7BD90qqE # 2paTerM1+6VRveN01QC9xltlfijUxMDh/jXJ/jnztcJvyDG1 # SIG # End signature block ================================================ FILE: developing/Archive/tests/checks/InstanceChecks.Tests.ps1 ================================================ # load all of the assertion functions (Get-ChildItem $PSScriptRoot/../../internal/assertions/).ForEach{ . $Psitem.FullName } Describe "Checking Instance.Tests.ps1 checks" -Tag UnitTest { Context "Checking Backup Compression" { # Mock the version check for running tests Mock Connect-DbaInstance { @{Version = @{Major = 14 } } } # Define test cases for the results to fail test and fill expected message # So the results of SPConfigure is 1, we expect $false but the result is true and the results of SPConfigure is 0, we expect $true but the result is false $TestCases = @{spconfig = 1; expected = $false; actual = $true }, @{spconfig = 0; expected = $true; actual = $false } It "Fails Check Correctly for Config and expected value " -TestCases $TestCases { Param($spconfig, $actual, $expected) Mock Get-DbaSpConfigure { @{"ConfiguredValue" = $spconfig } } { Assert-BackupCompression -Instance 'Dummy' -defaultbackupcompression $expected } | Should -Throw -ExpectedMessage "Expected `$$expected, because The default backup compression should be set correctly, but got `$$actual" } $TestCases = @{spconfig = 0; expected = $false }, @{spconfig = 1; expected = $true; } It "Passes Check Correctly for Config and expected value " -TestCases $TestCases { Param($spconfig, $expected) Mock Get-DbaSpConfigure { @{"ConfiguredValue" = $spconfig } } Assert-BackupCompression -Instance 'Dummy' -defaultbackupcompression $expected } # Validate we have called the mock the correct number of times It "Should call the mocks" { $assertMockParams = @{ 'CommandName' = 'Get-DbaSpConfigure' 'Times' = 4 'Exactly' = $true } Assert-MockCalled @assertMockParams } <# It "Should not run for SQL 2005 and below"{ # Mock Get-Version function Get-Version {} Mock Get-Version {9} # Mock the version check for not running the tests Mock Get-DbaSpConfigure {@{"ConfiguredValue" = 1}} $Pester = Invoke-DbcCheck -SQLInstance Dummy -Check DefaultBackupCompression -PassThru -Show None # $Pester.TotalCount | Should -Be 1 # $Pester.SkippedCount | Should -Be 1 $assertMockParams = @{ 'CommandName' = 'Get-Version' 'Times' = 1 'Exactly' = $true } Assert-MockCalled @assertMockParams } #> } Context "Checking Instance MaxDop" { # if Userecommended it should pass if CurrentInstanceMaxDop property returned from Test-DbaMaxDop matches the RecommendedMaxDop property It "Passes Check Correctly with the use recommended parameter set to true" { # Mock to pass Mock Test-DbaMaxDop { @{"CurrentInstanceMaxDop" = 0; "RecommendedMaxDop" = 0 } } Assert-InstanceMaxDop -Instance 'Dummy' -UseRecommended } # if Userecommended it should fail if CurrentInstanceMaxDop property returned from Test-DbaMaxDop does not match the RecommendedMaxDop property It "Fails Check Correctly with the use recommended parameter set to true" { # Mock to fail Mock Test-DbaMaxDop { @{"CurrentInstanceMaxDop" = 0; "RecommendedMaxDop" = 5 } } { Assert-InstanceMaxDop -Instance 'Dummy' -UseRecommended } | Should -Throw -ExpectedMessage "Expected 5, because We expect the MaxDop Setting to be the recommended value 5" } $TestCases = @{"MaxDopValue" = 5 } # if not UseRecommended - it should pass if the CurrentInstanceMaxDop property returned from Test-DbaMaxDop matches the MaxDopValue parameter It "Passes Check Correctly with a specified value " -TestCases $TestCases { Param($MaxDopValue) # Mock to pass Mock Test-DbaMaxDop { @{"CurrentInstanceMaxDop" = 5; "RecommendedMaxDop" = $MaxDopValue } } Assert-InstanceMaxDop -Instance 'Dummy' -MaxDopValue $MaxDopValue } $TestCases = @{"MaxDopValue" = 5 }, @{"MaxDopValue" = 0 } # if not UseRecommended - it should fail if the CurrentInstanceMaxDop property returned from Test-DbaMaxDop does not match the MaxDopValue parameter It "Fails Check Correctly with with a specified value " -TestCases $TestCases { Param($MaxDopValue) # Mock to fail Mock Test-DbaMaxDop { @{"CurrentInstanceMaxDop" = 4; "RecommendedMaxDop" = 73 } } { Assert-InstanceMaxDop -Instance 'Dummy' -MaxDopValue $MaxDopValue } | Should -Throw -ExpectedMessage "Expected $MaxDopValue, because We expect the MaxDop Setting to be $MaxDopValue" } # Validate we have called the mock the correct number of times It "Should call the mocks" { $assertMockParams = @{ 'CommandName' = 'Test-DbaMaxDop' 'Times' = 5 'Exactly' = $true } Assert-MockCalled @assertMockParams } } Context "Checking tempdb size" { Mock Get-DbaDbFile { @( [PSCustomObject]@{ Type = 0 Size = [PSCustomObject]@{ Megabyte = 8 } }, [PSCustomObject]@{ Type = 0 Size = [PSCustomObject]@{ Megabyte = 8 } }, [PSCustomObject]@{ Type = 0 Size = [PSCustomObject]@{ Megabyte = 8 } }, [PSCustomObject]@{ Type = 0 Size = [PSCustomObject]@{ Megabyte = 8 } } ) } It "Should pass the test when all tempdb files are the same size" { Assert-TempDBSize -Instance Dummy } Mock Get-DbaDbFile { @( [PSCustomObject]@{ Type = 0 Size = [PSCustomObject]@{ Megabyte = 8 } }, [PSCustomObject]@{ Type = 0 Size = [PSCustomObject]@{ Megabyte = 6 } }, [PSCustomObject]@{ Type = 0 Size = [PSCustomObject]@{ Megabyte = 8 } }, [PSCustomObject]@{ Type = 0 Size = [PSCustomObject]@{ Megabyte = 7 } } ) } It "Should fail when all of the tempdb files are not the same size" { { Assert-TempDBSize -Instance Dummy } | Should -Throw -ExpectedMessage "We want all the tempdb data files to be the same size - See https://blogs.sentryone.com/aaronbertrand/sql-server-2016-tempdb-fixes/ and https://www.brentozar.com/blitz/tempdb-data-files/ for more information" } } Context "Checking Supported Build" { [DateTime]$Date = Get-Date -Format O $TestCases = @{"Date" = $Date; "BuildBehind" = "1SP"; }, @{"Date" = $Date; "BuildBehind" = "1CU"; } #if BuildBehind it should pass if build is >= SP/CU specified & Support Dates are valid It "Passed check correctly when the current build is not behind the BuildBehind value of " -TestCases $TestCases { Param($BuildBehind, $Date) #Mock to pass Mock Test-DbaBuild { @{"SPLevel" = "{SP4, LATEST}"; "CULevel" = "CU4"; "Compliant" = $true; "SupportedUntil" = $Date.AddMonths(1) } } Assert-InstanceSupportedBuild -Instance 'Dummy' -BuildBehind $BuildBehind -Date $Date } $TestCases = @{"Date" = $Date; "BuildBehind" = "1SP"; "BuildWarning" = 6; "expected" = $true; "actual" = $false }, @{"Date" = $Date; "BuildBehind" = "1CU"; "BuildWarning" = 6; "expected" = $true; "actual" = $false } #if BuildBehind it should fail if build is <= SP/CU specified & Support dates are valid It "Failed check correctly when the current build is behind the BuildBehind value of " -TestCases $TestCases { Param($BuildBehind, $Date, $expected, $actual) #Mock to fail Mock Test-DbaBuild { @{"SPLevel" = "{SP2}"; "CULevel" = "CU2"; "SPTarget" = "SP4"; "CUTarget" = "CU4"; "Compliant" = $false; "SupportedUntil" = $Date.AddMonths(1); "Build" = 42 } } { Assert-InstanceSupportedBuild -Instance 'Dummy' -BuildBehind $BuildBehind -Date $Date } | Should -Throw -ExpectedMessage "Expected `$$expected, because this build 42 should not be behind the required build, but got `$$actual" } $TestCases = @{"Date" = $Date } #if neither BuildBehind nor BuildWarning it should pass if support dates are valid It "Passed check correctly with a SupportedUntil date > today" -TestCases $TestCases { Param($Date) #Mock to pass Mock Test-DbaBuild { @{"SupportedUntil" = $Date.AddMonths(1) } } Assert-InstanceSupportedBuild -Instance 'Dummy' -Date $Date } $TestCases = @{"Date" = $Date } #if neither BuildBehind nor BuildWarning it should fail if support date is out of the support window It "Failed check correctly with a SupportedUntil date < today" -TestCases $TestCases { Param($Date) #Mock to fail Mock Test-DbaBuild { @{"SupportedUntil" = $Date.AddMonths(-1); "Build" = 42 } } $SupportedUntil = Get-Date $Date.AddMonths(-1) -Format O $Date = Get-Date $Date -Format O { Assert-InstanceSupportedBuild -Instance 'Dummy' -Date $Date } | Should -Throw -ExpectedMessage "Expected the actual value to be greater than $Date, because this build 42 is now unsupported by Microsoft, but got $SupportedUntil" } $TestCases = @{"Date" = $Date; "BuildWarning" = 6 } #if BuildWarning it should fail if support date is in the warning window It "Passed check correctly with the BuildWarning window > today" -TestCases $TestCases { Param($Date, $BuildWarning) #Mock to pass Mock Test-DbaBuild { @{"SupportedUntil" = $Date.AddMonths(9); "Build" = 42 } } { Assert-InstanceSupportedBuild -Instance 'Dummy' -Date $Date -BuildWarning $BuildWarning } } $TestCases = @{"Date" = $Date; "BuildWarning" = 6 } #if BuildWarning it should fail if support date is in the warning window It "Failed check correctly with the BuildWarning window < today" -TestCases $TestCases { Param($Date, $BuildWarning) #Mock to fail Mock Test-DbaBuild { @{"SupportedUntil" = $Date.AddMonths(3); "Build" = 42 } } $SupportedUntil = Get-Date $Date.AddMonths(3) -Format O $expected = Get-Date $Date.AddMonths($BuildWarning) -Format O { Assert-InstanceSupportedBuild -Instance 'Dummy' -Date $Date -BuildWarning $BuildWarning } | Should -Throw -ExpectedMessage "Expected the actual value to be greater than $expected, because this build 42 will be unsupported by Microsoft on $SupportedUntil which is less than $BuildWarning months away, but got $SupportedUntil" } } Context "Checking Trace Flags" { ## Mock for one trace flag Mock Get-DbaTraceFlag { [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 118 } } It "Should pass correctly when the trace flag exists and it is the only one" { Assert-TraceFlag -SQLInstance Dummy -ExpectedTraceFlag 118 } It "Should fail correctly when the trace flag does not exist but there is a different trace flag" { { Assert-TraceFlag -SQLInstance Dummy -ExpectedTraceFlag 117 } | Should -Throw -ExpectedMessage "Expected 117 to be found in collection 118, because We expect that Trace Flag 117 will be set on Dummy, but it was not found." } It "Should fail correctly when the trace flag does not exist and there is no trace flag" { Mock Get-DbaTraceFlag { [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 118 } } { Assert-TraceFlag -SQLInstance Dummy -ExpectedTraceFlag 117 } | Should -Throw -ExpectedMessage "Expected 117 to be found in collection 118, because We expect that Trace Flag 117 will be set on Dummy, but it was not found." } It "Should Pass Correctly for more than one trace flag when they all exist" { Mock Get-DbaTraceFlag { [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 117 }, [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 118 }, [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 3604 }, [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 3605 } } Assert-TraceFlag -SQLInstance Dummy -ExpectedTraceFlag 118, 117, 3604, 3605 } It "Should Pass Correctly for more than one trace flag when they exist but there are extra trace flags" { Mock Get-DbaTraceFlag { [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 117 }, [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 118 }, [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 3604 }, [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 3605 } } Assert-TraceFlag -SQLInstance Dummy -ExpectedTraceFlag 118, 117, 3604 } It "Should Fail Correctly when checking more than one trace flag when 1 is missing" { Mock Get-DbaTraceFlag { [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 117 }, [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 118 }, [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 3604 } } { Assert-TraceFlag -SQLInstance Dummy -ExpectedTraceFlag 118, 117, 3604, 3605 } | Should -Throw -ExpectedMessage "Expected 3605 to be found in collection @(117, 118, 3604), because We expect that Trace Flag 3605 will be set on Dummy, but it was not found." } It "Should Fail Correctly when checking more than one trace flag when 2 are missing" { Mock Get-DbaTraceFlag { [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 117 }, [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 118 } } { Assert-TraceFlag -SQLInstance Dummy -ExpectedTraceFlag 118, 117, 3604, 3605 } | Should -Throw -ExpectedMessage "Expected 3604 to be found in collection @(117, 118), because We expect that Trace Flag 3604 will be set on Dummy, but it was not found" } It "Should pass correctly when no trace flag exists and none expected" { Mock Get-DbaTraceFlag { } Assert-TraceFlag -SQLInstance Dummy -ExpectedTraceFlag $null } It "Should fail correctly when a trace flag exists and none expected" { Mock Get-DbaTraceFlag { [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 117 } } { Assert-TraceFlag -SQLInstance Dummy -ExpectedTraceFlag $null } | Should -Throw -ExpectedMessage "Expected `$null or empty, because We expect that there will be no Trace Flags set on Dummy, but got 117" } } Context "Checking Trace Flags Not Expected" { ## Mock for one trace flag Mock Get-DbaTraceFlag { [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 118 } } It "Should pass correctly when the trace flag exists and it is not the one expected to be running" { Assert-NotTraceFlag -SQLInstance Dummy -NotExpectedTraceFlag 117 } It "Should pass correctly when no trace flag is running" { Mock Get-DbaTraceFlag { } Assert-NotTraceFlag -SQLInstance Dummy -NotExpectedTraceFlag 117 } It "Should fail correctly when the trace flag is running and is the only one" { Mock Get-DbaTraceFlag { [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 118 } } { Assert-NotTraceFlag -SQLInstance Dummy -NotExpectedTraceFlag 118 } | Should -Throw -ExpectedMessage "Expected 118 to not be found in collection 118, because We expect that Trace Flag 118 will not be set on Dummy, but it was found." } It "Should fail correctly for one trace flag when the trace flag is running but there is another one running as well" { Mock Get-DbaTraceFlag { [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 117 }, [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 118 } } { Assert-NotTraceFlag -SQLInstance Dummy -NotExpectedTraceFlag 117 } | Should -Throw -ExpectedMessage "Expected 117 to not be found in collection @(117, 118), because We expect that Trace Flag 117 will not be set on Dummy, but it was found." } It "Should Pass Correctly for more than one trace flag when no trace flag is set" { Mock Get-DbaTraceFlag { } Assert-NotTraceFlag -SQLInstance Dummy -NotExpectedTraceFlag 118, 117, 3604, 3605 } It "Should Pass Correctly for more than one trace flag when a different one is running" { Mock Get-DbaTraceFlag { [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 117 }, [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 118 } } Assert-NotTraceFlag -SQLInstance Dummy -NotExpectedTraceFlag 3604, 3605 } It "Should Fail Correctly for more than one trace flag when one is running" { Mock Get-DbaTraceFlag { [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 117 }, [PSObject]@{ 'ComputerName' = 'ComputerName' 'Global' = 1 'InstanceName' = 'MSSQLSERVER' 'Session' = 0 'SqlInstance' = 'SQLInstance' 'Status' = 1 'TraceFlag' = 118 } } { Assert-NotTraceFlag -SQLInstance Dummy -NotExpectedTraceFlag 117, 3604, 3605 } | Should -Throw -ExpectedMessage "Expected 117 to not be found in collection @(117, 118), because We expect that Trace Flag 117 will not be set on Dummy, but it was found." } } Context "Checking CLR Enabled" { # Mock the version check for running tests Mock Connect-DbaInstance { } # Define test cases for the results to fail test and fill expected message # So the results of SPConfigure is 1, we expect $false but the result is true and the results of SPConfigure is 0, we expect $true but the result is false $TestCases = @{spconfig = 1; expected = $false; actual = $true }, @{spconfig = 0; expected = $true; actual = $false } It "Fails Check Correctly for Config and expected value " -TestCases $TestCases { Param($spconfig, $actual, $expected) Mock Get-DbaSpConfigure { @{"ConfiguredValue" = $spconfig } } { Assert-CLREnabled -SQLInstance 'Dummy' -CLREnabled $expected } | Should -Throw -ExpectedMessage "Expected `$$expected, because The CLR Enabled should be set correctly, but got `$$actual" } $TestCases = @{spconfig = 0; expected = $false }, @{spconfig = 1; expected = $true; } It "Passes Check Correctly for Config and expected value " -TestCases $TestCases { Param($spconfig, $expected) Mock Get-DbaSpConfigure { @{"ConfiguredValue" = $spconfig } } Assert-CLREnabled -SQLInstance 'Dummy' -CLREnabled $expected } # Validate we have called the mock the correct number of times It "Should call the mocks" { $assertMockParams = @{ 'CommandName' = 'Get-DbaSpConfigure' 'Times' = 4 'Exactly' = $true } Assert-MockCalled @assertMockParams } } Context "Checking AdHoc Distributed Queries Enabled" { # Mock the version check for running tests Mock Connect-DbaInstance { } # Define test cases for the results to fail test and fill expected message # So the results of SPConfigure is 1, we expect $false but the result is true and the results of SPConfigure is 0, we expect $true but the result is false $TestCases = @{spconfig = 1; expected = $false; actual = $true }, @{spconfig = 0; expected = $true; actual = $false } It "Fails Check Correctly for Config and expected value " -TestCases $TestCases { Param($spconfig, $actual, $expected) Mock Get-DbaSpConfigure { @{"ConfiguredValue" = $spconfig } } { Assert-AdHocDistributedQueriesEnabled -SQLInstance 'Dummy' -AdHocDistributedQueriesEnabled $expected } | Should -Throw -ExpectedMessage "Expected `$$expected, because The AdHoc Distributed Queries Enabled setting should be set correctly, but got `$$actual" } $TestCases = @{spconfig = 0; expected = $false }, @{spconfig = 1; expected = $true; } It "Passes Check Correctly for Config and expected value " -TestCases $TestCases { Param($spconfig, $expected) Mock Get-DbaSpConfigure { @{"ConfiguredValue" = $spconfig } } Assert-AdHocDistributedQueriesEnabled -SQLInstance 'Dummy' -AdHocDistributedQueriesEnabled $expected } # Validate we have called the mock the correct number of times It "Should call the mocks" { $assertMockParams = @{ 'CommandName' = 'Get-DbaSpConfigure' 'Times' = 4 'Exactly' = $true } Assert-MockCalled @assertMockParams } } Context "Checking XPCmdShell is disabled" { # Mock the version check for running tests Mock Connect-DbaInstance { } # Define test cases for the results to fail test and fill expected message # This one is different from the others as we are checking for disabled !! # So the results of SPConfigure is 1, we expect $true but the result is false and the results of SPConfigure is 0, we expect $false but the result is true $TestCases = @{spconfig = 1; expected = $true; actual = $false }, @{spconfig = 0; expected = $false; actual = $true } It "Fails Check Correctly for Config and expected value " -TestCases $TestCases { Param($spconfig, $actual, $expected) Mock Get-DbaSpConfigure { @{"ConfiguredValue" = $spconfig } } { Assert-XpCmdShellDisabled -SQLInstance 'Dummy' -XpCmdShellDisabled $expected } | Should -Throw -ExpectedMessage "Expected `$$expected, because The XP CmdShell setting should be set correctly, but got `$$actual" } # again this one is different from the others as we are checking for disabled $TestCases = @{spconfig = 1; expected = $false }, @{spconfig = 0; expected = $true; } It "Passes Check Correctly for Config and expected value " -TestCases $TestCases { Param($spconfig, $expected) Mock Get-DbaSpConfigure { @{"ConfiguredValue" = $spconfig } } Assert-XpCmdShellDisabled -SQLInstance 'Dummy' -XpCmdShellDisabled $expected } # Validate we have called the mock the correct number of times It "Should call the mocks" { $assertMockParams = @{ 'CommandName' = 'Get-DbaSpConfigure' 'Times' = 4 'Exactly' = $true } Assert-MockCalled @assertMockParams } } Context "Checking ErrorLog Count" { # if configured value is 30 and test value 30 it will pass It "Passes Check Correctly with the number of error log files set to 30" { # Mock to pass Mock Get-DbaErrorLogConfig { @{"LogCount" = 30 } } Assert-ErrorLogCount -SQLInstance 'Dummy' -errorLogCount 30 } # if configured value is less than the current value it fails It "Fails Check Correctly with the number of error log files being 10 instead of 30 or higher" { # Mock to fail Mock Get-DbaErrorLogConfig { @{"LogCount" = 10 } } { Assert-ErrorLogCount -SQLInstance 'Dummy' -errorLogCount 30 } | Should -Throw -ExpectedMessage "Expected the actual value to be greater than or equal to 30, because We expect to have at least 30 number of error log files, but got 10." } # if configured value is higher than the current value it fails It "Passes Check Correctly with the number of error log files being 40 and test of 30 or higher" { # Mock to Pass Mock Get-DbaErrorLogConfig { @{"LogCount" = 40 } } Assert-ErrorLogCount -SQLInstance 'Dummy' -errorLogCount 30 } # Validate we have called the mock the correct number of times It "Should call the mocks" { $assertMockParams = @{ 'CommandName' = 'Get-DbaErrorLogConfig' 'Times' = 3 'Exactly' = $true } Assert-MockCalled @assertMockParams } } } InModuleScope dbachecks { (Get-ChildItem $PSScriptRoot/../../internal/assertions/).ForEach{ . $Psitem.FullName } Describe "Testing AllInstanceInfo and Relevant Assertions" -Tag AllInstanceInfo { function Get-ErrorLogEntry { } Mock Get-DbcConfigValue { } -ParameterFilter { $Name -and $Name -eq 'policy.errorlog.warningwindow' } Context "Checking Get-AllInstanceInfo" { Mock Get-ErrorLogEntry { } It "Should return the correct results for ErrorLog Entries when there are no severities" { (Get-AllInstanceInfo -Instance Dummy -Tags ErrorLog -There $true).ErrorLog | Should -BeNullOrEmpty -Because "We need no entries when we have no sev 17 to 24 errors" } It "Should return the correct results for ErrorLog Entries when there are severities" { Mock Get-ErrorLogEntry { [PSCustomObject]@{ LogDate = '2019-02-14 23:00' ProcessInfo = 'spid55' Text = 'Error: 50000, Severity: 18, State: 1.' } } (Get-AllInstanceInfo -Instance Dummy -Tags ErrorLog -There $true).ErrorLog | Should -BeOfType PSCustomObject -Because "We need entries when we have sev 17 to 24 errors" } It "Should return the correct results for Default Trace when it is enabled" { Mock Get-DbaSpConfigure { @{ 'ConfiguredValue' = 1 } } (Get-AllInstanceInfo -Instance Dummy -Tags DefaultTrace -There $true).DefaultTrace.ConfiguredValue | Should -Be 1 -Because "We need to return one when we have default trace enabled" } It "Should return the correct results for Default Trace when it is disabled" { Mock Get-DbaSpConfigure { [pscustomobject]@{ ConfiguredValue = 0 } } (Get-AllInstanceInfo -Instance Dummy -Tags DefaultTrace -There $true).DefaultTrace.ConfiguredValue | Should -Be 0 -Because "We need to return zero when default trace is not enabled" } } Context "Checking ErrorLog Entries" { It "Should pass the test successfully when there are no Severity Errors" { # Mock for success Mock Get-AllInstanceInfo { } Assert-ErrorLogEntry -AllInstanceInfo (Get-AllInstanceInfo) } It "Should fail the test successfully when there are Severity Errors" { # MOck for failing test Mock Get-AllInstanceInfo { [PSCustomObject]@{ ErrorLog = [PSCustomObject]@{ LogDate = '2019-02-14 23:00' ProcessInfo = 'spid55' Text = 'Error: 50000, Severity: 18, State: 1.' } } } { Assert-ErrorLogEntry -AllInstanceInfo (Get-AllInstanceInfo) } | Should -Throw -ExpectedMessage "Expected `$null or empty, because these severities indicate serious problems, but got @(@{LogDate=2019-02-14 23:00; ProcessInfo=spid55; Text=Error: 50000, Severity: 18, State: 1.})." } } Context "Checking Cross DB Ownership Chaining" { It "Should pass the test successfully when cross db ownership chaining is disabled" { # Mock for success Mock Get-AllInstanceInfo { [PSCustomObject]@{ CrossDBOwnershipChaining = [PSCustomObject]@{ ConfiguredValue = 0 } } } Assert-CrossDBOwnershipChaining -AllInstanceInfo (Get-AllInstanceInfo) } It "Should fail the test successfully when cross db ownership chaining is enabled" { # Mock for failing test Mock Get-AllInstanceInfo { [PSCustomObject]@{ CrossDBOwnershipChaining = [PSCustomObject]@{ ConfiguredValue = 1 } } } { Assert-CrossDBOwnershipChaining -AllInstanceInfo (Get-AllInstanceInfo) } | Should -Throw -ExpectedMessage "Expected 0, because We expected the Cross DB Ownership Chaining to be disabled, but got 1." } } Context "Checking Default Trace Entries" { It "Should pass the test successfully when default trace is enabled" { # Mock for success Mock Get-AllInstanceInfo { [PSCustomObject]@{ DefaultTrace = [PSCustomObject]@{ ConfiguredValue = 1 } } } Assert-DefaultTrace -AllInstanceInfo (Get-AllInstanceInfo) } It "Should fail the test successfully when when default trace is disabled" { # Mock for failing test Mock Get-AllInstanceInfo { [PSCustomObject]@{ DefaultTrace = [PSCustomObject]@{ ConfiguredValue = 0 } } } { Assert-DefaultTrace -AllInstanceInfo (Get-AllInstanceInfo) } | Should -Throw -ExpectedMessage "Expected 1, because We expected the Default Trace to be enabled, but got 0." } } Context "Checking OLE Automation Procedures Entries" { It "Should pass the test successfully when OLE Automation Procedures is disabled" { # Mock for success # This should pass when the configured value for OleAutomationProcedures enabled is 0 (ie disabled) Mock Get-AllInstanceInfo { [PSCustomObject]@{ OleAutomationProceduresDisabled = [PSCustomObject]@{ ConfiguredValue = 0 } } } Assert-OLEAutomationProcedures -AllInstanceInfo (Get-AllInstanceInfo) } It "Should fail the test successfully when when OLE Automation Procedures is enabled" { # Mock for failing test # This should pass when the configured value for OleAutomationProcedures enabled is 1 (ie enabled) Mock Get-AllInstanceInfo { [PSCustomObject]@{ OleAutomationProceduresDisabled = [PSCustomObject]@{ ConfiguredValue = 1 } } } { Assert-OLEAutomationProcedures -AllInstanceInfo (Get-AllInstanceInfo) } | Should -Throw -ExpectedMessage "Expected 0, because we expect the OLE Automation Procedures to be disabled, but got 1." } } Context "Checking Remote Access Entries" { It "Should pass the test successfully when remote access is disabled" { # Mock for success Mock Get-AllInstanceInfo { [PSCustomObject]@{ RemoteAccess = [PSCustomObject]@{ ConfiguredValue = 0 } } } Assert-RemoteAccess -AllInstanceInfo (Get-AllInstanceInfo) } It "Should fail the test successfully when remote access is enabled" { # Mock for failing test Mock Get-AllInstanceInfo { [PSCustomObject]@{ RemoteAccess = [PSCustomObject]@{ ConfiguredValue = 1 } } } { Assert-RemoteAccess -AllInstanceInfo (Get-AllInstanceInfo) } | Should -Throw -ExpectedMessage "Expected 0, because we expected Remote Access to be disabled, but got 1." } } Context "Checking Scan For Startup Procedures Entries" { It "Should pass the test successfully when scan for startup procedures is disabled and config is true" { # Mock for success Mock Get-AllInstanceInfo { [PSCustomObject]@{ ScanForStartupProceduresDisabled = [PSCustomObject]@{ ConfiguredValue = 0 } } } Assert-ScanForStartupProcedures -AllInstanceInfo (Get-AllInstanceInfo) -ScanForStartupProcsDisabled $true } It "Should fail the test successfully when scan for startup procedures is disabled and config is false" { # Mock for failing test Mock Get-AllInstanceInfo { [PSCustomObject]@{ ScanForStartupProceduresDisabled = [PSCustomObject]@{ ConfiguredValue = 0 } } } { Assert-ScanForStartupProcedures -AllInstanceInfo (Get-AllInstanceInfo) -ScanForStartupProcsDisabled $false } | Should -Throw -ExpectedMessage "Expected `$false, because We expected the scan for startup procedures to be configured correctly, but got `$true." } It "Should pass the test successfully when scan for startup procedures is enabled and config is false" { # Mock for success Mock Get-AllInstanceInfo { [PSCustomObject]@{ ScanForStartupProceduresDisabled = [PSCustomObject]@{ ConfiguredValue = 1 } } } Assert-ScanForStartupProcedures -AllInstanceInfo (Get-AllInstanceInfo) -ScanForStartupProcsDisabled $false } It "Should fail the test successfully when scan for startup procedures is enabled and config is true" { # Mock for failing test Mock Get-AllInstanceInfo { [PSCustomObject]@{ ScanForStartupProceduresDisabled = [PSCustomObject]@{ ConfiguredValue = 1 } } } { Assert-ScanForStartupProcedures -AllInstanceInfo (Get-AllInstanceInfo) -ScanForStartupProcsDisabled $true } | Should -Throw -ExpectedMessage "Expected `$true, because We expected the scan for startup procedures to be configured correctly, but got `$false." } } Context "Checking Cross DB Ownership Chaining" { It "Should pass the test successfully when cross db ownership chaining is disabled" { # Mock for success Mock Get-AllInstanceInfo { [PSCustomObject]@{ CrossDBOwnershipChaining = [PSCustomObject]@{ ConfiguredValue = 0 } } } Assert-CrossDBOwnershipChaining -AllInstanceInfo (Get-AllInstanceInfo) } It "Should fail the test successfully when cross db ownership chaining is enabled" { # Mock for failing test Mock Get-AllInstanceInfo { [PSCustomObject]@{ CrossDBOwnershipChaining = [PSCustomObject]@{ ConfiguredValue = 1 } } } { Assert-CrossDBOwnershipChaining -AllInstanceInfo (Get-AllInstanceInfo) } | Should -Throw -ExpectedMessage "Expected 0, because we expected the cross db ownership chaining to be disabled, but got 1." } } Context "Checking Max Dump Entries" { It "Should pass the test successfully when the number of dumps is less than config" { # Mock for success Mock Get-AllInstanceInfo { [PSCustomObject]@{ MaxDump = [PSCustomObject]@{ Count = 0 } } } $maxdumps = 1 Assert-MaxDump -AllInstanceInfo (Get-AllInstanceInfo) -maxdumps $maxdumps } It "Should fail the test successfully when the number of dumps is more than config" { # Mock for failing test Mock Get-AllInstanceInfo { [PSCustomObject]@{ MaxDump = [PSCustomObject]@{ Count = 7 } } } $maxdumps = 4 { Assert-MaxDump -AllInstanceInfo (Get-AllInstanceInfo) -maxdumps $maxdumps } | Should -Throw -ExpectedMessage "Expected the actual value to be less than 4, because We expected less than 4 dumps but found 7. Memory dumps often suggest issues with the SQL Server instance, but got 7" } } Context "Checking Latest Build of SQL Server" { It "Should pass the test successfully when scan for latest build of SQL passes" { # Mock for success Mock Get-AllInstanceInfo { [PSCustomObject]@{ LatestBuild = [PSCustomObject]@{ Compliant = $true } } } Assert-LatestBuild -AllInstanceInfo (Get-AllInstanceInfo) } It "Should fail the test successfully when scan for latest build of SQL fails" { # Mock for failing test Mock Get-AllInstanceInfo { [PSCustomObject]@{ LatestBuild = [PSCustomObject]@{ Compliant = $false } } } { Assert-LatestBuild -AllInstanceInfo (Get-AllInstanceInfo) } | Should -Throw -ExpectedMessage "Expected `$true, because We expected the SQL Server to be on the newest SQL Server Packs/CUs, but got `$false." } } Context "Checking SQL Engine" { It "Should pass the test successfully when the sql engine is running and the config is set to running" { # Mock for success Mock Get-AllInstanceInfo { [PSCustomObject]@{ EngineService = [pscustomobject] @{ State = 'Running' StartType = 'Automatic' } } } Assert-EngineState -AllInstanceInfo (Get-AllInstanceInfo) -state 'Running' } It "Should fail the test successfully successfully when the sql engine is stopped and the config is set to running" { # Mock for failure Mock Get-AllInstanceInfo { [PSCustomObject]@{ EngineService = [pscustomobject] @{ State = 'Stopped' StartType = 'Automatic' } } } { Assert-EngineState -AllInstanceInfo (Get-AllInstanceInfo) -state 'Running' } | Should -Throw -ExpectedMessage "Expected strings to be the same, because The SQL Service was expected to be Running, but they were different." } It "Should pass the test successfully when the sql engine is stopped and the config is set to stopped" { # Mock for success Mock Get-AllInstanceInfo { [PSCustomObject]@{ EngineService = [pscustomobject] @{ State = 'Running' StartType = 'Automatic' } } } Assert-EngineState -AllInstanceInfo (Get-AllInstanceInfo) -state 'Running' } It "Should fail the test successfully successfully when the sql engine is running and the config is set to stopped" { # Mock for failure Mock Get-AllInstanceInfo { [PSCustomObject]@{ EngineService = [pscustomobject] @{ State = 'Stopped' StartType = 'Automatic' } } } { Assert-EngineState -AllInstanceInfo (Get-AllInstanceInfo) -state 'Running' } | Should -Throw -ExpectedMessage "Expected strings to be the same, because The SQL Service was expected to be Running, but they were different." } It "Should pass the test successfully when the sql engine is set to Automatic and the config is set to Automatic and it is not a cluster" { # Mock for success Mock Get-AllInstanceInfo { [PSCustomObject]@{ EngineService = [pscustomobject] @{ State = 'Running' StartType = 'Automatic' } } } Assert-EngineStartType -AllInstanceInfo (Get-AllInstanceInfo) -StartType 'Automatic' } It "Should fail the test successfully when the sql engine is set to Manual and the config is set to Automatic and it is not a cluster" { # Mock for failure Mock Get-AllInstanceInfo { [PSCustomObject]@{ EngineService = [pscustomobject] @{ State = 'Stopped' StartType = 'Manual' } } } { Assert-EngineStartType -AllInstanceInfo (Get-AllInstanceInfo) -StartType 'Automatic' } | Should -Throw -ExpectedMessage "Expected strings to be the same, because The SQL Service Start Type was expected to be Automatic, but they were different." } It "Should fail the test successfully when the sql engine is set to Disabled and the config is set to Automatic and it is not a cluster" { # Mock for failure Mock Get-AllInstanceInfo { [PSCustomObject]@{ EngineService = [pscustomobject] @{ State = 'Stopped' StartType = 'Disabled' } } } { Assert-EngineStartType -AllInstanceInfo (Get-AllInstanceInfo) -StartType 'Automatic' } | Should -Throw -ExpectedMessage "Expected strings to be the same, because The SQL Service Start Type was expected to be Automatic, but they were different." } It "Should pass the test successfully when the sql engine is set to Manual and the config is set to Manual and it is not a cluster" { # Mock for success Mock Get-AllInstanceInfo { [PSCustomObject]@{ EngineService = [pscustomobject] @{ State = 'Running' StartType = 'Manual' } } } Assert-EngineStartType -AllInstanceInfo (Get-AllInstanceInfo) -StartType 'Manual' } It "Should fail the test successfully when the sql engine is set to Automatic and the config is set to Manual and it is not a cluster" { # Mock for failure Mock Get-AllInstanceInfo { [PSCustomObject]@{ EngineService = [pscustomobject] @{ State = 'Stopped' StartType = 'Automatic' } } } { Assert-EngineStartType -AllInstanceInfo (Get-AllInstanceInfo) -StartType 'Manual' } | Should -Throw -ExpectedMessage "Expected strings to be the same, because The SQL Service Start Type was expected to be Manual, but they were different." } It "Should fail the test successfully when the sql engine is set to Disabled and the config is set to Manual and it is not a cluster" { # Mock for failure Mock Get-AllInstanceInfo { [PSCustomObject]@{ EngineService = [pscustomobject] @{ State = 'Stopped' StartType = 'Disabled' } } } { Assert-EngineStartType -AllInstanceInfo (Get-AllInstanceInfo) -StartType 'Manual' } | Should -Throw -ExpectedMessage "Expected strings to be the same, because The SQL Service Start Type was expected to be Manual, but they were different." } It "Should pass the test successfully when the sql engine is set to Disabled and the config is set to Disabled and it is not a cluster" { # Mock for success Mock Get-AllInstanceInfo { [PSCustomObject]@{ EngineService = [pscustomobject] @{ State = 'Running' StartType = 'Disabled' } } } Assert-EngineStartType -AllInstanceInfo (Get-AllInstanceInfo) -StartType 'Disabled' } It "Should fail the test successfully when the sql engine is set to Manual and the config is set to Disabled and it is not a cluster" { # Mock for failure Mock Get-AllInstanceInfo { [PSCustomObject]@{ EngineService = [pscustomobject] @{ State = 'Stopped' StartType = 'Manual' } } } { Assert-EngineStartType -AllInstanceInfo (Get-AllInstanceInfo) -StartType 'Disabled' } | Should -Throw -ExpectedMessage "Expected strings to be the same, because The SQL Service Start Type was expected to be Disabled, but they were different." } It "Should fail the test successfully when the sql engine is set to Automatic and the config is set to Disabled and it is not a cluster" { # Mock for failure Mock Get-AllInstanceInfo { [PSCustomObject]@{ EngineService = [pscustomobject] @{ State = 'Stopped' StartType = 'Automatic' } } } { Assert-EngineStartType -AllInstanceInfo (Get-AllInstanceInfo) -StartType 'Disabled' } | Should -Throw -ExpectedMessage "Expected strings to be the same, because The SQL Service Start Type was expected to be Disabled, but they were different." } It "Should pass the test successfully when the sql engine is set to Manual and it is a cluster" { # Mock for success Mock Get-AllInstanceInfo { [PSCustomObject]@{ EngineService = [pscustomobject] @{ State = 'Running' StartType = 'Manual' } } } Assert-EngineStartTypeCluster -AllInstanceInfo (Get-AllInstanceInfo) } It "Should fail the test successfully when the sql engine is set to Automatic and it is a cluster" { # Mock for failure Mock Get-AllInstanceInfo { [PSCustomObject]@{ EngineService = [pscustomobject] @{ State = 'Stopped' StartType = 'Automatic' } } } { Assert-EngineStartTypeCluster -AllInstanceInfo (Get-AllInstanceInfo) } | Should -Throw -ExpectedMessage "Expected strings to be the same, because Clustered Instances required that the SQL engine service is set to manual, but they were different." } It "Should fail the test successfully when the sql engine is set to Disabled and it is a cluster" { # Mock for failure Mock Get-AllInstanceInfo { [PSCustomObject]@{ EngineService = [pscustomobject] @{ State = 'Stopped' StartType = 'Disabled' } } } { Assert-EngineStartTypeCluster -AllInstanceInfo (Get-AllInstanceInfo) } | Should -Throw -ExpectedMessage "Expected strings to be the same, because Clustered Instances required that the SQL engine service is set to manual, but they were different." } } Context "Checking sa login disabled" { It "Should pass the test successfully when the original sa account is disabled" { # Mock for success Mock Get-AllInstanceInfo {[PSCustomObject]@{ SaDisabled = [PSCustomObject]@{ Disabled = $true } } } Assert-SaDisabled -AllInstanceInfo (Get-AllInstanceInfo) } It "Should fail the test successfully when the original sa account is enabled" { # Mock for failing test Mock Get-AllInstanceInfo {[PSCustomObject]@{ SaDisabled = [PSCustomObject]@{ Disabled = $false } }} {Assert-SaDisabled -AllInstanceInfo (Get-AllInstanceInfo)} | Should -Throw -ExpectedMessage "Expected `$true, because We expected the original sa login to be disabled, but got `$false." } } Context "Checking no sa login exist" { It "Should pass the test successfully when no sa login exist" { # Mock for success Mock Get-AllInstanceInfo {[PSCustomObject]@{ SaExist = [PSCustomObject]@{ Exist = 0 } } } Assert-SaExist -AllInstanceInfo (Get-AllInstanceInfo) } It "Should fail the test successfully when a sa login doesn't exist" { # Mock for failing test Mock Get-AllInstanceInfo {[PSCustomObject]@{ SaExist = [PSCustomObject]@{ Exist = 1 } }} {Assert-SaExist -AllInstanceInfo (Get-AllInstanceInfo)} | Should -Throw -ExpectedMessage "Expected 0, because We expected no login to exist with the name sa, but got 1." } } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU3zT39A2lyXiuj8g4j77KCVG1 # vq2gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBSGUXCG13OfAv5/0pfenyNd4nxE # HzANBgkqhkiG9w0BAQEFAASCAQA3Oz2mbycV6Q4ns38NGrSqedo4pV0TmWpQ7oxr # IpZQisFu095UwNQQ+dmWlwjT411VBlvw0ud0Njt+EFGt458CvvVU9T6nqkkmK2OG # JLkJOkzwDLrFG7H92LdJRq8LtREnBBz488xz/Tpb4HJs/Drgwi0muC99mug9Cv9C # ffTv69G9bf7C9yDuGHfftArerPIg+c3OVLOLuEYPgGQb84yb7k5UmtSQmRwI+puw # H88Byh7MRR5sTHhwSMlla0ESvTSnks/XJwWYXw/IyqyCyD9PwPJejccwiI+pC1Os # TKVpI+AhTilaojWO0qr5jYawjd1JndKREFl5MtrsIdUX5PVM # SIG # End signature block ================================================ FILE: developing/Archive/tests/checks/ServerChecks.Tests.ps1 ================================================ [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingComputerNameHardcoded", "")] [CmdletBinding()] param () # load all of the assertion functions (Get-ChildItem $PSScriptRoot/../../internal/assertions/).ForEach{. $Psitem.FullName} Describe "Checking ServerChecks.Tests" { Context "Testing Assert-CPUPrioritisation" { #Mock for passing function Get-RemoteRegistryValue {} Mock Get-RemoteRegistryValue { 24 } It "Should Pass When value set correctly" { Assert-CPUPrioritisation } #Mock for failing function Get-RemoteRegistryValue {} Mock Get-RemoteRegistryValue { 2 } It "Should fail When value set incorrectly" { {Assert-CPUPrioritisation} | Should -Throw -ExpectedMessage "Expected exactly 24, because a server should prioritise CPU to it's Services, not to the user experience when someone logs on, but got 2." } } Context "Testing Assert-DiskAllocationUnit" { it "Should pass when all SQLDisks are formatted with the 65536b (64kb) block allocation unit size" { Mock Test-DbaDiskAllocation { @( [PSObject]@{ 'BlockSize' = 4096 'IsBestPractice' = $True 'IsSqlDisk' = $True 'Label' = $Null 'Name' = 'C:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $True 'Label' = 'SQL Data' 'Name' = 'D:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $False 'Label' = 'SQL Archive' 'Name' = 'F:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $True 'Label' = 'SQL Logs' 'Name' = 'L:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $True 'Label' = 'SQL Performance' 'Name' = 'P:\' 'Server' = 'DummyServer' } ) } $DiskAllocationObjects = Test-DbaDiskAllocation -ComputerName Dummy $DiskAllocationObjects.ForEach{ Assert-DiskAllocationUnit -DiskAllocationObject $PSItem } } it "Should fail when any SQLDisks is formatted with a block allocation unit size that isn't 65536b (64KB)" { Mock Test-DbaDiskAllocation { @( [PSObject]@{ 'BlockSize' = 4096 'IsBestPractice' = $True 'IsSqlDisk' = $True 'Label' = $Null 'Name' = 'C:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $True 'Label' = 'SQL Data' 'Name' = 'D:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $False 'Label' = 'SQL Archive' 'Name' = 'F:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $True 'Label' = 'SQL Logs' 'Name' = 'L:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $false # changed this to make it fail 'IsSqlDisk' = $True 'Label' = 'SQL Performance' 'Name' = 'P:\' 'Server' = 'DummyServer' } ) } $DiskAllocationObjects = Test-DbaDiskAllocation -ComputerName Dummy {Assert-DiskAllocationUnit -DiskAllocationObject $DiskAllocationObjects[4] } | should -Throw -ExpectedMessage "Expected `$true, because SQL Server performance will be better when accessing data from a disk that is formatted with 64Kb block allocation unit, but got `$false." } } Context "Testing Get-AllServerInfo for Tags Server with a server that exists" { Mock Test-Connection { @( [PSObject]@{ 'Address' = 'DummyServer' 'BufferSize' = 32 'NoFragmentation' = $False 'PrimaryAddressResolutionStatus' = 0 'ProtocolAddress' = '10.10.10.10' 'ProtocolAddressResolved' = '' 'RecordRoute' = 0 'ReplyInconsistency' = $False 'ReplySize' = 32 'ResolveAddressNames' = $False 'ResponseTime' = 1 'ResponseTimeToLive' = 128 'RouteRecord' = $Null 'RouteRecordResolved' = $Null 'SourceRoute' = '' 'SourceRouteType' = 0 'StatusCode' = 0 'Timeout' = 4000 'TimeStampRecord' = $Null 'TimeStampRecordAddress' = $Null 'TimeStampRecordAddressResolved' = $Null 'TimestampRoute' = 0 'TimeToLive' = 80 'TypeofService' = 0 '__CLASS' = 'Win32_PingStatus' '__DERIVATION' = @() '__DYNASTY' = 'Win32_PingStatus' '__GENUS' = 2 '__NAMESPACE' = 'root\cimv2' '__PATH' = '\\SourceServer\root\cimv2:Win32_PingStatus.Address="DummyServer",BufferSize=32,NoFragmentation=FALSE,RecordRoute=0,ResolveAddressNames=FALSE,SourceRoute="",SourceRouteType=0,Ti meout=4000,TimestampRoute=0,TimeToLive=80,TypeofService=0' '__PROPERTY_COUNT' = 24 '__RELPATH' = 'Win32_PingStatus.Address="DummyServer",BufferSize=32,NoFragmentation=FALSE,RecordRoute=0,ResolveAddressNames=FALSE,SourceRoute="",SourceRouteType=0,Timeout=4000,TimestampRoute= 0,TimeToLive=80,TypeofService=0' '__SERVER' = 'SourceServer' '__SUPERCLASS' = $Null }, [PSObject]@{ 'Address' = 'DummyServer' 'BufferSize' = 32 'NoFragmentation' = $False 'PrimaryAddressResolutionStatus' = 0 'ProtocolAddress' = '10.10.10.10' 'ProtocolAddressResolved' = '' 'RecordRoute' = 0 'ReplyInconsistency' = $False 'ReplySize' = 32 'ResolveAddressNames' = $False 'ResponseTime' = 0 'ResponseTimeToLive' = 128 'RouteRecord' = $Null 'RouteRecordResolved' = $Null 'SourceRoute' = '' 'SourceRouteType' = 0 'StatusCode' = 0 'Timeout' = 4000 'TimeStampRecord' = $Null 'TimeStampRecordAddress' = $Null 'TimeStampRecordAddressResolved' = $Null 'TimestampRoute' = 0 'TimeToLive' = 80 'TypeofService' = 0 '__CLASS' = 'Win32_PingStatus' '__DERIVATION' = @() '__DYNASTY' = 'Win32_PingStatus' '__GENUS' = 2 '__NAMESPACE' = 'root\cimv2' '__PATH' = '\\SourceServer\root\cimv2:Win32_PingStatus.Address="DummyServer",BufferSize=32,NoFragmentation=FALSE,RecordRoute=0,ResolveAddressNames=FALSE,SourceRoute="",SourceRouteType=0,Ti meout=4000,TimestampRoute=0,TimeToLive=80,TypeofService=0' '__PROPERTY_COUNT' = 24 '__RELPATH' = 'Win32_PingStatus.Address="DummyServer",BufferSize=32,NoFragmentation=FALSE,RecordRoute=0,ResolveAddressNames=FALSE,SourceRoute="",SourceRouteType=0,Timeout=4000,TimestampRoute= 0,TimeToLive=80,TypeofService=0' '__SERVER' = 'SourceServer' '__SUPERCLASS' = $Null }, [PSObject]@{ 'Address' = 'DummyServer' 'BufferSize' = 32 'NoFragmentation' = $False 'PrimaryAddressResolutionStatus' = 0 'ProtocolAddress' = '10.10.10.10' 'ProtocolAddressResolved' = '' 'RecordRoute' = 0 'ReplyInconsistency' = $False 'ReplySize' = 32 'ResolveAddressNames' = $False 'ResponseTime' = 0 'ResponseTimeToLive' = 128 'RouteRecord' = $Null 'RouteRecordResolved' = $Null 'SourceRoute' = '' 'SourceRouteType' = 0 'StatusCode' = 0 'Timeout' = 4000 'TimeStampRecord' = $Null 'TimeStampRecordAddress' = $Null 'TimeStampRecordAddressResolved' = $Null 'TimestampRoute' = 0 'TimeToLive' = 80 'TypeofService' = 0 '__CLASS' = 'Win32_PingStatus' '__DERIVATION' = @() '__DYNASTY' = 'Win32_PingStatus' '__GENUS' = 2 '__NAMESPACE' = 'root\cimv2' '__PATH' = '\\SourceServer\root\cimv2:Win32_PingStatus.Address="DummyServer",BufferSize=32,NoFragmentation=FALSE,RecordRoute=0,ResolveAddressNames=FALSE,SourceRoute="",SourceRouteType=0,Ti meout=4000,TimestampRoute=0,TimeToLive=80,TypeofService=0' '__PROPERTY_COUNT' = 24 '__RELPATH' = 'Win32_PingStatus.Address="DummyServer",BufferSize=32,NoFragmentation=FALSE,RecordRoute=0,ResolveAddressNames=FALSE,SourceRoute="",SourceRouteType=0,Timeout=4000,TimestampRoute= 0,TimeToLive=80,TypeofService=0' '__SERVER' = 'SourceServer' '__SUPERCLASS' = $Null } ) } Mock Test-DbaDiskAllocation { @( [PSObject]@{ 'BlockSize' = 4096 'IsBestPractice' = $False 'IsSqlDisk' = $True 'Label' = $Null 'Name' = 'C:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $True 'Label' = 'SQL Data' 'Name' = 'D:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $False 'Label' = 'SQL Archive' 'Name' = 'F:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $True 'Label' = 'SQL Logs' 'Name' = 'L:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $True 'Label' = 'SQL Performance' 'Name' = 'P:\' 'Server' = 'DummyServer' } ) } Mock Test-DbaPowerPlan { [PSObject]@{ 'ActivePowerPlan' = 'High performance' 'ComputerName' = [PSObject]@{ 'ComputerName' = 'DummyServer' 'FullName' = 'DummyServer' 'FullSmoName' = 'DummyServer' 'InputObject' = 'DummyServer' 'InstanceName' = 'MSSQLSERVER' 'IsConnectionString' = $False 'IsLocalHost' = $False 'LinkedLive' = $False 'LinkedServer' = $Null 'NetworkProtocol' = [Sqlcollaborative.Dbatools.Connection.SqlConnectionProtocol]'Any' 'Port' = 1433 'SqlComputerName' = '[DummyServer]' 'SqlFullName' = '[DummyServer]' 'SqlInstanceName' = '[MSSQLSERVER]' 'Type' = [Sqlcollaborative.Dbatools.Parameter.DbaInstanceInputType]'Default' } 'isBestPractice' = $True 'RecommendedPowerPlan' = 'High performance' } } Mock Test-DbaSpn { @( [PSObject]@{ 'Cluster' = $False 'ComputerName' = 'DummyServer' 'Credential' = $Null 'DynamicPort' = $False 'Error' = 'SPN missing' 'InstanceName' = 'MSSQLSERVER' 'InstanceServiceAccount' = 'Domain\Account' 'IsSet' = $False 'Port' = $Null 'RequiredSPN' = 'MSSQLSvc/DummyServer' 'SqlProduct' = 'SQL Server 2017 Enterprise Edition: Core-based Licensing (64-bit)' 'TcpEnabled' = $True 'Warning' = 'None' }, [PSObject]@{ 'Cluster' = $False 'ComputerName' = 'DummyServer' 'Credential' = $Null 'DynamicPort' = $False 'Error' = 'SPN missing' 'InstanceName' = 'NoneDefaultInstance' 'InstanceServiceAccount' = 'Domain\Account' 'IsSet' = $False 'Port' = $Null 'RequiredSPN' = 'MSSQLSvc/DummyServer:NoneDefaultInstance' 'SqlProduct' = 'SQL Server 2016 Enterprise Edition: Core-based Licensing (64-bit)' 'TcpEnabled' = $True 'Warning' = 'None' }, [PSObject]@{ 'Cluster' = $False 'ComputerName' = 'DummyServer' 'Credential' = $Null 'DynamicPort' = $False 'Error' = 'SPN missing' 'InstanceName' = 'MSSQLSERVER' 'InstanceServiceAccount' = 'Domain\Account' 'IsSet' = $False 'Port' = '1433' 'RequiredSPN' = 'MSSQLSvc/DummyServer:1433' 'SqlProduct' = 'SQL Server 2017 Enterprise Edition: Core-based Licensing (64-bit)' 'TcpEnabled' = $True 'Warning' = 'None' }, [PSObject]@{ 'Cluster' = $False 'ComputerName' = 'DummyServer' 'Credential' = $Null 'DynamicPort' = $False 'Error' = 'SPN missing' 'InstanceName' = 'NoneDefaultInstance' 'InstanceServiceAccount' = 'Domain\Account' 'IsSet' = $False 'Port' = '1437' 'RequiredSPN' = 'MSSQLSvc/DummyServer:1437' 'SqlProduct' = 'SQL Server 2016 Enterprise Edition: Core-based Licensing (64-bit)' 'TcpEnabled' = $True 'Warning' = 'None' } ) } Mock Get-DbaDiskSpace { @( [PSObject]@{ 'BlockSize' = 4096 'Capacity' = [PSObject]@{ 'Byte' = 42355126272 'Digits' = 2 'Gigabyte' = 39.4462852478027 'Kilobyte' = 41362428 'Megabyte' = 40392.99609375 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.0385217629373074 } 'ComputerName' = 'DummyServer' 'DriveType' = 'Local Disk' 'FileSystem' = 'NTFS' 'Free' = [PSObject]@{ 'Byte' = 19814010880 'Digits' = 2 'Gigabyte' = 18.4532356262207 'Kilobyte' = 19349620 'Megabyte' = 18896.11328125 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.0180207379162312 } 'FreeInBytes' = 19814010880 'FreeInGB' = 18.45 'FreeInKB' = 19349620 'FreeInMB' = 18896.11 'FreeInPB' = 0 'FreeInTB' = 0.02 'IsSqlDisk' = $Null 'Label' = '' 'Name' = 'C:\' 'PercentFree' = 46.78 'Server' = 'DummyServer' 'SizeInBytes' = 42355126272 'SizeInGB' = 39.45 'SizeInKB' = 41362428 'SizeInMB' = 40393 'SizeInPB' = 0 'SizeInTB' = 0.04 'Type' = [Sqlcollaborative.Dbatools.Computer.DriveType]'LocalDisk' }, [PSObject]@{ 'BlockSize' = 65536 'Capacity' = [PSObject]@{ 'Byte' = 153408700416 'Digits' = 2 'Gigabyte' = 142.872985839844 'Kilobyte' = 149813184 'Megabyte' = 146301.9375 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.139524400234222 } 'ComputerName' = 'DummyServer' 'DriveType' = 'Local Disk' 'FileSystem' = 'NTFS' 'Free' = [PSObject]@{ 'Byte' = 82363809792 'Digits' = 2 'Gigabyte' = 76.707275390625 'Kilobyte' = 80433408 'Megabyte' = 78548.25 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.0749094486236572 } 'FreeInBytes' = 82363809792 'FreeInGB' = 76.71 'FreeInKB' = 80433408 'FreeInMB' = 78548.25 'FreeInPB' = 0 'FreeInTB' = 0.07 'IsSqlDisk' = $Null 'Label' = 'SQL Logs' 'Name' = 'L:\' 'PercentFree' = 53.69 'Server' = 'DummyServer' 'SizeInBytes' = 153408700416 'SizeInGB' = 142.87 'SizeInKB' = 149813184 'SizeInMB' = 146301.94 'SizeInPB' = 0 'SizeInTB' = 0.14 'Type' = [Sqlcollaborative.Dbatools.Computer.DriveType]'LocalDisk' }, [PSObject]@{ 'BlockSize' = 65536 'Capacity' = [PSObject]@{ 'Byte' = 382116757504 'Digits' = 2 'Gigabyte' = 355.873962402344 'Kilobyte' = 373160896 'Megabyte' = 364414.9375 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.347533166408539 } 'ComputerName' = 'DummyServer' 'DriveType' = 'Local Disk' 'FileSystem' = 'NTFS' 'Free' = [PSObject]@{ 'Byte' = 84496482304 'Digits' = 2 'Gigabyte' = 78.6934814453125 'Kilobyte' = 82516096 'Megabyte' = 80582.125 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.076849102973938 } 'FreeInBytes' = 84496482304 'FreeInGB' = 78.69 'FreeInKB' = 82516096 'FreeInMB' = 80582.12 'FreeInPB' = 0 'FreeInTB' = 0.08 'IsSqlDisk' = $Null 'Label' = 'SQL Performance' 'Name' = 'P:\' 'PercentFree' = 22.11 'Server' = 'DummyServer' 'SizeInBytes' = 382116757504 'SizeInGB' = 355.87 'SizeInKB' = 373160896 'SizeInMB' = 364414.94 'SizeInPB' = 0 'SizeInTB' = 0.35 'Type' = [Sqlcollaborative.Dbatools.Computer.DriveType]'LocalDisk' }, [PSObject]@{ 'BlockSize' = 65536 'Capacity' = [PSObject]@{ 'Byte' = 42813292544 'Digits' = 2 'Gigabyte' = 39.8729858398438 'Kilobyte' = 41809856 'Megabyte' = 40829.9375 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.0389384627342224 } 'ComputerName' = 'DummyServer' 'DriveType' = 'Local Disk' 'FileSystem' = 'NTFS' 'Free' = [PSObject]@{ 'Byte' = 42719117312 'Digits' = 2 'Gigabyte' = 39.7852783203125 'Kilobyte' = 41717888 'Megabyte' = 40740.125 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.0388528108596802 } 'FreeInBytes' = 42719117312 'FreeInGB' = 39.79 'FreeInKB' = 41717888 'FreeInMB' = 40740.12 'FreeInPB' = 0 'FreeInTB' = 0.04 'IsSqlDisk' = $Null 'Label' = 'Archive Data (SLOW!)' 'Name' = 'F:\' 'PercentFree' = 99.78 'Server' = 'DummyServer' 'SizeInBytes' = 42813292544 'SizeInGB' = 39.87 'SizeInKB' = 41809856 'SizeInMB' = 40829.94 'SizeInPB' = 0 'SizeInTB' = 0.04 'Type' = [Sqlcollaborative.Dbatools.Computer.DriveType]'LocalDisk' }, [PSObject]@{ 'BlockSize' = 65536 'Capacity' = [PSObject]@{ 'Byte' = 580757946368 'Digits' = 2 'Gigabyte' = 540.872985839844 'Kilobyte' = 567146432 'Megabyte' = 553853.9375 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.528196275234222 } 'ComputerName' = 'DummyServer' 'DriveType' = 'Local Disk' 'FileSystem' = 'NTFS' 'Free' = [PSObject]@{ 'Byte' = 580605968384 'Digits' = 2 'Gigabyte' = 540.7314453125 'Kilobyte' = 566998016 'Megabyte' = 553709 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.528058052062988 } 'FreeInBytes' = 580605968384 'FreeInGB' = 540.73 'FreeInKB' = 566998016 'FreeInMB' = 553709 'FreeInPB' = 0 'FreeInTB' = 0.53 'IsSqlDisk' = $Null 'Label' = 'SQL Data' 'Name' = 'D:\' 'PercentFree' = 99.97 'Server' = 'DummyServer' 'SizeInBytes' = 580757946368 'SizeInGB' = 540.87 'SizeInKB' = 567146432 'SizeInMB' = 553853.94 'SizeInPB' = 0 'SizeInTB' = 0.53 'Type' = [Sqlcollaborative.Dbatools.Computer.DriveType]'LocalDisk' } ) } $tags = 'PowerPlan', 'SPN', 'DiskCapacity', 'PingComputer', 'CPUPrioritisation', 'DiskAllocationUnit', 'InstanceConnection' $ServerInfo = Get-AllServerInfo -ComputerName Dummy -Tags $tags It "Should get the right results for PingComputer" { $serverInfo.PingComputer.Count | Should -Be 3 $serverInfo.PingComputer[0].Address | Should -Be 'DummyServer' $serverInfo.PingComputer[0].ProtocolAddress | Should -Be '10.10.10.10' $serverInfo.PingComputer[0].ProtocolAddress | Should -Be '10.10.10.10' $serverInfo.PingComputer[0].ResponseTime | Should -Be 1 } It "Should get the right results for DiskAllocationUnit" { $serverInfo.DiskAllocation[0].Name | Should -Be 'C:\' $serverInfo.DiskAllocation[0].isBestPractice| Should -BeFalse $serverInfo.DiskAllocation[0].isSqlDisk| Should -BeTrue } It "Should get the right results for PowerPlan" { $serverInfo.PowerPlan | Should -BeTrue } It "Should get the right results for SPN" { $serverInfo.SPNs[0].ComputerName | Should -Be 'DummyServer' $serverInfo.SPNs[0].Error | Should -Be 'SPN missing' $serverInfo.SPNs[0].RequiredSPN | Should -Be 'MSSQLSvc/DummyServer' } It "Should get the right results for DiskCapacity" { $serverInfo.DiskSpace[0].ComputerName | Should -Be 'DummyServer' $serverInfo.DiskSpace[0].Name | Should -Be 'C:\' $serverInfo.DiskSpace[0].PercentFree | Should -Be 46.78 } } Context "Testing Get-AllServerInfo for Tags Server with a server that doesn't exist" { Mock Test-Connection {Throw} Mock Test-DbaDiskAllocation {Throw} Mock Test-DbaPowerPlan {Throw} Mock Test-DbaSpn {Throw} Mock Get-DbaDiskSpace {Throw} $tags = 'PowerPlan', 'SPN', 'DiskCapacity', 'PingComputer', 'CPUPrioritisation', 'DiskAllocationUnit', 'InstanceConnection' $ServerInfo = Get-AllServerInfo -ComputerName Dummy -Tags $tags It "Should get the right results for PingComputer" { $serverInfo.PingComputer.Count | Should -Be -1 -Because "This is what the function should return for no server" $serverInfo.PingComputer[0].Address | Should -BeNullOrEmpty -Because "This is what the function should return for no server" $serverInfo.PingComputer[0].ResponseTime | Should -Be 50000000 -Because "This is what the function should return for no server" } It "Should get the right results for DiskAllocationUnit" { $serverInfo.DiskAllocation[0].Name | Should -Be '? ' # Yes there is a space for formatting the PowerBi $serverInfo.DiskAllocation[0].isBestPractice| Should -BeFalse $serverInfo.DiskAllocation[0].isSqlDisk| Should -BeTrue } It "Should get the right results for PowerPlan" { $serverInfo.PowerPlan | Should -BeFalse } It "Should get the right results for SPN" { $serverInfo.SPNs[0].Error | Should -Be 'An Error occurred' $serverInfo.SPNs[0].RequiredSPN | Should -Be 'Dont know the SPN' } It "Should get the right results for DiskCapacity" { $serverInfo.DiskSpace.ComputerName| Should -Be 'An Error occurred Dummy' $serverInfo.DiskSpace.Name | Should -Be 'Do not know the Name' $serverInfo.DiskSpace.PercentFree | Should -Be -1 } } # There is probably a way of using test cases for this and making it dynamic # Some bearded fellow wrote about it!! # https://sqldbawithabeard.com/2017/07/06/writing-dynamic-and-random-tests-cases-for-pester/ # But right now I cant see it so this will do Context "Testing Get-AllServerInfo for Tags PowerPlan with a server that exists" { Mock Test-DbaPowerPlan { [PSObject]@{ 'ActivePowerPlan' = 'High performance' 'ComputerName' = [PSObject]@{ 'ComputerName' = 'DummyServer' 'FullName' = 'DummyServer' 'FullSmoName' = 'DummyServer' 'InputObject' = 'DummyServer' 'InstanceName' = 'MSSQLSERVER' 'IsConnectionString' = $False 'IsLocalHost' = $False 'LinkedLive' = $False 'LinkedServer' = $Null 'NetworkProtocol' = [Sqlcollaborative.Dbatools.Connection.SqlConnectionProtocol]'Any' 'Port' = 1433 'SqlComputerName' = '[DummyServer]' 'SqlFullName' = '[DummyServer]' 'SqlInstanceName' = '[MSSQLSERVER]' 'Type' = [Sqlcollaborative.Dbatools.Parameter.DbaInstanceInputType]'Default' } 'isBestPractice' = $True 'RecommendedPowerPlan' = 'High performance' } } Mock Test-Connection {} Mock Test-DbaDiskAllocation {} Mock Test-DbaSpn {} Mock Get-DbaDiskSpace {} $tags = 'PowerPlan' $ServerInfo = Get-AllServerInfo -ComputerName Dummy -Tags $tags It "Should have no results for PingComputer" { $serverInfo.PingComputer| Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Test-Connection' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } It "Should have no results for DiskAllocationUnit" { $serverInfo.DiskAllocation | Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Test-DbaDiskAllocation' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } It "Should get the right results for PowerPlan" { $serverInfo.PowerPlan | Should -BeTrue } It "Should have no results for SPN" { $serverInfo.SPNs | Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Test-DbaSPN' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } It "Should have no results for DiskCapacity" { $serverInfo.DiskSpace | Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Get-DbaDiskSpace' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } } Context "Testing Get-AllServerInfo for Tags PowerPlan with a server that doesn't exist" { Mock Test-Connection {} Mock Test-DbaDiskAllocation {} Mock Test-DbaPowerPlan {Throw} Mock Test-DbaSpn {} Mock Get-DbaDiskSpace {} $tags = 'PowerPlan' $ServerInfo = Get-AllServerInfo -ComputerName Dummy -Tags $tags It "Should have no results for PingComputer" { $serverInfo.PingComputer| Should -BeNullOrEmpty } It "Should have no results for DiskAllocationUnit" { $serverInfo.DiskAllocation | Should -BeNullOrEmpty } It "Should get the right results for PowerPlan" { $serverInfo.PowerPlan | Should -BeFalse } It "Should have no results for SPN" { $serverInfo.SPNs | Should -BeNullOrEmpty } It "Should have no results for DiskCapacity" { $serverInfo.DiskSpace | Should -BeNullOrEmpty } } Context "Testing Get-AllServerInfo for Tags PingComputer with a server that exists" { Mock Test-Connection { @( [PSObject]@{ 'Address' = 'DummyServer' 'BufferSize' = 32 'NoFragmentation' = $False 'PrimaryAddressResolutionStatus' = 0 'ProtocolAddress' = '10.10.10.10' 'ProtocolAddressResolved' = '' 'RecordRoute' = 0 'ReplyInconsistency' = $False 'ReplySize' = 32 'ResolveAddressNames' = $False 'ResponseTime' = 1 'ResponseTimeToLive' = 128 'RouteRecord' = $Null 'RouteRecordResolved' = $Null 'SourceRoute' = '' 'SourceRouteType' = 0 'StatusCode' = 0 'Timeout' = 4000 'TimeStampRecord' = $Null 'TimeStampRecordAddress' = $Null 'TimeStampRecordAddressResolved' = $Null 'TimestampRoute' = 0 'TimeToLive' = 80 'TypeofService' = 0 '__CLASS' = 'Win32_PingStatus' '__DERIVATION' = @() '__DYNASTY' = 'Win32_PingStatus' '__GENUS' = 2 '__NAMESPACE' = 'root\cimv2' '__PATH' = '\\SourceServer\root\cimv2:Win32_PingStatus.Address="DummyServer",BufferSize=32,NoFragmentation=FALSE,RecordRoute=0,ResolveAddressNames=FALSE,SourceRoute="",SourceRouteType=0,Ti meout=4000,TimestampRoute=0,TimeToLive=80,TypeofService=0' '__PROPERTY_COUNT' = 24 '__RELPATH' = 'Win32_PingStatus.Address="DummyServer",BufferSize=32,NoFragmentation=FALSE,RecordRoute=0,ResolveAddressNames=FALSE,SourceRoute="",SourceRouteType=0,Timeout=4000,TimestampRoute= 0,TimeToLive=80,TypeofService=0' '__SERVER' = 'SourceServer' '__SUPERCLASS' = $Null }, [PSObject]@{ 'Address' = 'DummyServer' 'BufferSize' = 32 'NoFragmentation' = $False 'PrimaryAddressResolutionStatus' = 0 'ProtocolAddress' = '10.10.10.10' 'ProtocolAddressResolved' = '' 'RecordRoute' = 0 'ReplyInconsistency' = $False 'ReplySize' = 32 'ResolveAddressNames' = $False 'ResponseTime' = 0 'ResponseTimeToLive' = 128 'RouteRecord' = $Null 'RouteRecordResolved' = $Null 'SourceRoute' = '' 'SourceRouteType' = 0 'StatusCode' = 0 'Timeout' = 4000 'TimeStampRecord' = $Null 'TimeStampRecordAddress' = $Null 'TimeStampRecordAddressResolved' = $Null 'TimestampRoute' = 0 'TimeToLive' = 80 'TypeofService' = 0 '__CLASS' = 'Win32_PingStatus' '__DERIVATION' = @() '__DYNASTY' = 'Win32_PingStatus' '__GENUS' = 2 '__NAMESPACE' = 'root\cimv2' '__PATH' = '\\SourceServer\root\cimv2:Win32_PingStatus.Address="DummyServer",BufferSize=32,NoFragmentation=FALSE,RecordRoute=0,ResolveAddressNames=FALSE,SourceRoute="",SourceRouteType=0,Ti meout=4000,TimestampRoute=0,TimeToLive=80,TypeofService=0' '__PROPERTY_COUNT' = 24 '__RELPATH' = 'Win32_PingStatus.Address="DummyServer",BufferSize=32,NoFragmentation=FALSE,RecordRoute=0,ResolveAddressNames=FALSE,SourceRoute="",SourceRouteType=0,Timeout=4000,TimestampRoute= 0,TimeToLive=80,TypeofService=0' '__SERVER' = 'SourceServer' '__SUPERCLASS' = $Null }, [PSObject]@{ 'Address' = 'DummyServer' 'BufferSize' = 32 'NoFragmentation' = $False 'PrimaryAddressResolutionStatus' = 0 'ProtocolAddress' = '10.10.10.10' 'ProtocolAddressResolved' = '' 'RecordRoute' = 0 'ReplyInconsistency' = $False 'ReplySize' = 32 'ResolveAddressNames' = $False 'ResponseTime' = 0 'ResponseTimeToLive' = 128 'RouteRecord' = $Null 'RouteRecordResolved' = $Null 'SourceRoute' = '' 'SourceRouteType' = 0 'StatusCode' = 0 'Timeout' = 4000 'TimeStampRecord' = $Null 'TimeStampRecordAddress' = $Null 'TimeStampRecordAddressResolved' = $Null 'TimestampRoute' = 0 'TimeToLive' = 80 'TypeofService' = 0 '__CLASS' = 'Win32_PingStatus' '__DERIVATION' = @() '__DYNASTY' = 'Win32_PingStatus' '__GENUS' = 2 '__NAMESPACE' = 'root\cimv2' '__PATH' = '\\SourceServer\root\cimv2:Win32_PingStatus.Address="DummyServer",BufferSize=32,NoFragmentation=FALSE,RecordRoute=0,ResolveAddressNames=FALSE,SourceRoute="",SourceRouteType=0,Ti meout=4000,TimestampRoute=0,TimeToLive=80,TypeofService=0' '__PROPERTY_COUNT' = 24 '__RELPATH' = 'Win32_PingStatus.Address="DummyServer",BufferSize=32,NoFragmentation=FALSE,RecordRoute=0,ResolveAddressNames=FALSE,SourceRoute="",SourceRouteType=0,Timeout=4000,TimestampRoute= 0,TimeToLive=80,TypeofService=0' '__SERVER' = 'SourceServer' '__SUPERCLASS' = $Null } ) } Mock Test-DbaDiskAllocation {} Mock Test-DbaSpn {} Mock Get-DbaDiskSpace {} $tags = 'PingComputer' $ServerInfo = Get-AllServerInfo -ComputerName Dummy -Tags $tags It "Should have the right results for PingComputer" { $serverInfo.PingComputer.Count | Should -Be 3 $serverInfo.PingComputer[0].Address | Should -Be 'DummyServer' $serverInfo.PingComputer[0].ProtocolAddress | Should -Be '10.10.10.10' $serverInfo.PingComputer[0].ProtocolAddress | Should -Be '10.10.10.10' $serverInfo.PingComputer[0].ResponseTime | Should -Be 1 $assertMockParams = @{ 'CommandName' = 'Test-Connection' 'Times' = 1 'Exactly' = $true } Assert-MockCalled @assertMockParams } It "Should have no results for DiskAllocationUnit" { $serverInfo.DiskAllocation | Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Test-DbaDiskAllocation' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } It "Should have no results results for PowerPlan" { $serverInfo.PowerPlan | Should -BeNullOrEmpty } It "Should have no results for SPN" { $serverInfo.SPNs | Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Test-DbaSPN' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } It "Should have no results for DiskCapacity" { $serverInfo.DiskSpace | Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Get-DbaDiskSpace' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } } Context "Testing Get-AllServerInfo for Tags PingComputer with a server that doesn't exist" { Mock Test-Connection {Throw} Mock Test-DbaDiskAllocation {} Mock Test-DbaPowerPlan {} Mock Test-DbaSpn {} Mock Get-DbaDiskSpace {} $tags = 'PingComputer' $ServerInfo = Get-AllServerInfo -ComputerName Dummy -Tags $tags It "Should get the right results for PingComputer" { $serverInfo.PingComputer.Count | Should -Be -1 -Because "This is what the function should return for no server" $serverInfo.PingComputer[0].Address | Should -BeNullOrEmpty -Because "This is what the function should return for no server" $serverInfo.PingComputer[0].ResponseTime | Should -Be 50000000 -Because "This is what the function should return for no server" } It "Should have no results for DiskAllocationUnit" { $serverInfo.DiskAllocation | Should -BeNullOrEmpty } It "Should have no results for PowerPlan" { $serverInfo.PowerPlan | Should -BeNullOrEmpty } It "Should have no results for SPN" { $serverInfo.SPNs | Should -BeNullOrEmpty } It "Should have no results for DiskCapacity" { $serverInfo.DiskSpace | Should -BeNullOrEmpty } } Context "Testing Get-AllServerInfo for Tags DiskAllocationUnit with a server that exists" { Mock Test-Connection { } Mock Test-DbaDiskAllocation { @( [PSObject]@{ 'BlockSize' = 4096 'IsBestPractice' = $False 'IsSqlDisk' = $True 'Label' = $Null 'Name' = 'C:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $True 'Label' = 'SQL Data' 'Name' = 'D:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $False 'Label' = 'SQL Archive' 'Name' = 'F:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $True 'Label' = 'SQL Logs' 'Name' = 'L:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $True 'Label' = 'SQL Performance' 'Name' = 'P:\' 'Server' = 'DummyServer' } ) } Mock Test-DbaSpn {} Mock Get-DbaDiskSpace {} $tags = 'DiskAllocationUnit' $ServerInfo = Get-AllServerInfo -ComputerName Dummy -Tags $tags It "Should have no results for PingComputer" { $serverInfo.PingComputer| Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Test-Connection' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } It "Should have the right results for DiskAllocationUnit" { $serverInfo.DiskAllocation[0].Name | Should -Be 'C:\' $serverInfo.DiskAllocation[0].isBestPractice| Should -BeFalse $serverInfo.DiskAllocation[0].isSqlDisk| Should -BeTrue $assertMockParams = @{ 'CommandName' = 'Test-DbaDiskAllocation' 'Times' = 1 'Exactly' = $true } Assert-MockCalled @assertMockParams } It "Should have no results results for PowerPlan" { $serverInfo.PowerPlan | Should -BeNullOrEmpty } It "Should have no results for SPN" { $serverInfo.SPNs | Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Test-DbaSPN' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } It "Should have no results for DiskCapacity" { $serverInfo.DiskSpace | Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Get-DbaDiskSpace' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } } Context "Testing Get-AllServerInfo for Tags DiskAllocationUnit with a server that doesn't exist" { Mock Test-Connection {} Mock Test-DbaDiskAllocation {Throw} Mock Test-DbaPowerPlan {} Mock Test-DbaSpn {} Mock Get-DbaDiskSpace {} $tags = 'DiskAllocationUnit' $ServerInfo = Get-AllServerInfo -ComputerName Dummy -Tags $tags It "Should have no results for PingComputer" { $serverInfo.PingComputer| Should -BeNullOrEmpty } It "Should have the right results for DiskAllocationUnit" { $serverInfo.DiskAllocation[0].Name | Should -Be '? ' # Yes there is a space for formatting the PowerBi $serverInfo.DiskAllocation[0].isBestPractice| Should -BeFalse $serverInfo.DiskAllocation[0].isSqlDisk| Should -BeTrue } It "Should have no results for PowerPlan" { $serverInfo.PowerPlan | Should -BeNullOrEmpty } It "Should have no results for SPN" { $serverInfo.SPNs | Should -BeNullOrEmpty } It "Should have no results for DiskCapacity" { $serverInfo.DiskSpace | Should -BeNullOrEmpty } } Context "Testing Get-AllServerInfo for Tags SPN with a server that exists" { Mock Test-Connection { } Mock Test-DbaDiskAllocation { } Mock Test-DbaSpn { @( [PSObject]@{ 'Cluster' = $False 'ComputerName' = 'DummyServer' 'Credential' = $Null 'DynamicPort' = $False 'Error' = 'SPN missing' 'InstanceName' = 'MSSQLSERVER' 'InstanceServiceAccount' = 'Domain\Account' 'IsSet' = $False 'Port' = $Null 'RequiredSPN' = 'MSSQLSvc/DummyServer' 'SqlProduct' = 'SQL Server 2017 Enterprise Edition: Core-based Licensing (64-bit)' 'TcpEnabled' = $True 'Warning' = 'None' }, [PSObject]@{ 'Cluster' = $False 'ComputerName' = 'DummyServer' 'Credential' = $Null 'DynamicPort' = $False 'Error' = 'SPN missing' 'InstanceName' = 'NoneDefaultInstance' 'InstanceServiceAccount' = 'Domain\Account' 'IsSet' = $False 'Port' = $Null 'RequiredSPN' = 'MSSQLSvc/DummyServer:NoneDefaultInstance' 'SqlProduct' = 'SQL Server 2016 Enterprise Edition: Core-based Licensing (64-bit)' 'TcpEnabled' = $True 'Warning' = 'None' }, [PSObject]@{ 'Cluster' = $False 'ComputerName' = 'DummyServer' 'Credential' = $Null 'DynamicPort' = $False 'Error' = 'SPN missing' 'InstanceName' = 'MSSQLSERVER' 'InstanceServiceAccount' = 'Domain\Account' 'IsSet' = $False 'Port' = '1433' 'RequiredSPN' = 'MSSQLSvc/DummyServer:1433' 'SqlProduct' = 'SQL Server 2017 Enterprise Edition: Core-based Licensing (64-bit)' 'TcpEnabled' = $True 'Warning' = 'None' }, [PSObject]@{ 'Cluster' = $False 'ComputerName' = 'DummyServer' 'Credential' = $Null 'DynamicPort' = $False 'Error' = 'SPN missing' 'InstanceName' = 'NoneDefaultInstance' 'InstanceServiceAccount' = 'Domain\Account' 'IsSet' = $False 'Port' = '1437' 'RequiredSPN' = 'MSSQLSvc/DummyServer:1437' 'SqlProduct' = 'SQL Server 2016 Enterprise Edition: Core-based Licensing (64-bit)' 'TcpEnabled' = $True 'Warning' = 'None' } ) } Mock Get-DbaDiskSpace {} $tags = 'SPN' $ServerInfo = Get-AllServerInfo -ComputerName Dummy -Tags $tags It "Should have no results for PingComputer" { $serverInfo.PingComputer| Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Test-Connection' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } It "Should have no results for DiskAllocationUnit" { $serverInfo.DiskAllocation | Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Test-DbaDiskAllocation' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } It "Should have no results results for PowerPlan" { $serverInfo.PowerPlan | Should -BeNullOrEmpty } It "Should have the right results for SPN" { $serverInfo.SPNs[0].ComputerName | Should -Be 'DummyServer' $serverInfo.SPNs[0].Error | Should -Be 'SPN missing' $serverInfo.SPNs[0].RequiredSPN | Should -Be 'MSSQLSvc/DummyServer' $assertMockParams = @{ 'CommandName' = 'Test-DbaSPN' 'Times' = 1 'Exactly' = $true } Assert-MockCalled @assertMockParams } It "Should have no results for DiskCapacity" { $serverInfo.DiskSpace | Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Get-DbaDiskSpace' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } } Context "Testing Get-AllServerInfo for Tags SPN with a server that doesn't exist" { Mock Test-Connection {} Mock Test-DbaDiskAllocation {} Mock Test-DbaPowerPlan {} Mock Test-DbaSpn {Throw} Mock Get-DbaDiskSpace {} $tags = 'SPN' $ServerInfo = Get-AllServerInfo -ComputerName Dummy -Tags $tags It "Should have no results for PingComputer" { $serverInfo.PingComputer| Should -BeNullOrEmpty } It "Should have no results for DiskAllocationUnit" { $serverInfo.DiskAllocation| Should -BeNullOrEmpty } It "Should have no results for PowerPlan" { $serverInfo.PowerPlan | Should -BeNullOrEmpty } It "Should have the right results for SPN" { $serverInfo.SPNs[0].Error | Should -Be 'An Error occurred' $serverInfo.SPNs[0].RequiredSPN | Should -Be 'Dont know the SPN' } It "Should have no results for DiskCapacity" { $serverInfo.DiskSpace | Should -BeNullOrEmpty } } Context "Testing Get-AllServerInfo for Tags DiskCapacity with a server that exists" { Mock Test-Connection { } Mock Test-DbaDiskAllocation { } Mock Test-DbaSpn { } Mock Get-DbaDiskSpace { @( [PSObject]@{ 'BlockSize' = 4096 'Capacity' = [PSObject]@{ 'Byte' = 42355126272 'Digits' = 2 'Gigabyte' = 39.4462852478027 'Kilobyte' = 41362428 'Megabyte' = 40392.99609375 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.0385217629373074 } 'ComputerName' = 'DummyServer' 'DriveType' = 'Local Disk' 'FileSystem' = 'NTFS' 'Free' = [PSObject]@{ 'Byte' = 19814010880 'Digits' = 2 'Gigabyte' = 18.4532356262207 'Kilobyte' = 19349620 'Megabyte' = 18896.11328125 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.0180207379162312 } 'FreeInBytes' = 19814010880 'FreeInGB' = 18.45 'FreeInKB' = 19349620 'FreeInMB' = 18896.11 'FreeInPB' = 0 'FreeInTB' = 0.02 'IsSqlDisk' = $Null 'Label' = '' 'Name' = 'C:\' 'PercentFree' = 46.78 'Server' = 'DummyServer' 'SizeInBytes' = 42355126272 'SizeInGB' = 39.45 'SizeInKB' = 41362428 'SizeInMB' = 40393 'SizeInPB' = 0 'SizeInTB' = 0.04 'Type' = [Sqlcollaborative.Dbatools.Computer.DriveType]'LocalDisk' }, [PSObject]@{ 'BlockSize' = 65536 'Capacity' = [PSObject]@{ 'Byte' = 153408700416 'Digits' = 2 'Gigabyte' = 142.872985839844 'Kilobyte' = 149813184 'Megabyte' = 146301.9375 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.139524400234222 } 'ComputerName' = 'DummyServer' 'DriveType' = 'Local Disk' 'FileSystem' = 'NTFS' 'Free' = [PSObject]@{ 'Byte' = 82363809792 'Digits' = 2 'Gigabyte' = 76.707275390625 'Kilobyte' = 80433408 'Megabyte' = 78548.25 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.0749094486236572 } 'FreeInBytes' = 82363809792 'FreeInGB' = 76.71 'FreeInKB' = 80433408 'FreeInMB' = 78548.25 'FreeInPB' = 0 'FreeInTB' = 0.07 'IsSqlDisk' = $Null 'Label' = 'SQL Logs' 'Name' = 'L:\' 'PercentFree' = 53.69 'Server' = 'DummyServer' 'SizeInBytes' = 153408700416 'SizeInGB' = 142.87 'SizeInKB' = 149813184 'SizeInMB' = 146301.94 'SizeInPB' = 0 'SizeInTB' = 0.14 'Type' = [Sqlcollaborative.Dbatools.Computer.DriveType]'LocalDisk' }, [PSObject]@{ 'BlockSize' = 65536 'Capacity' = [PSObject]@{ 'Byte' = 382116757504 'Digits' = 2 'Gigabyte' = 355.873962402344 'Kilobyte' = 373160896 'Megabyte' = 364414.9375 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.347533166408539 } 'ComputerName' = 'DummyServer' 'DriveType' = 'Local Disk' 'FileSystem' = 'NTFS' 'Free' = [PSObject]@{ 'Byte' = 84496482304 'Digits' = 2 'Gigabyte' = 78.6934814453125 'Kilobyte' = 82516096 'Megabyte' = 80582.125 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.076849102973938 } 'FreeInBytes' = 84496482304 'FreeInGB' = 78.69 'FreeInKB' = 82516096 'FreeInMB' = 80582.12 'FreeInPB' = 0 'FreeInTB' = 0.08 'IsSqlDisk' = $Null 'Label' = 'SQL Performance' 'Name' = 'P:\' 'PercentFree' = 22.11 'Server' = 'DummyServer' 'SizeInBytes' = 382116757504 'SizeInGB' = 355.87 'SizeInKB' = 373160896 'SizeInMB' = 364414.94 'SizeInPB' = 0 'SizeInTB' = 0.35 'Type' = [Sqlcollaborative.Dbatools.Computer.DriveType]'LocalDisk' }, [PSObject]@{ 'BlockSize' = 65536 'Capacity' = [PSObject]@{ 'Byte' = 42813292544 'Digits' = 2 'Gigabyte' = 39.8729858398438 'Kilobyte' = 41809856 'Megabyte' = 40829.9375 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.0389384627342224 } 'ComputerName' = 'DummyServer' 'DriveType' = 'Local Disk' 'FileSystem' = 'NTFS' 'Free' = [PSObject]@{ 'Byte' = 42719117312 'Digits' = 2 'Gigabyte' = 39.7852783203125 'Kilobyte' = 41717888 'Megabyte' = 40740.125 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.0388528108596802 } 'FreeInBytes' = 42719117312 'FreeInGB' = 39.79 'FreeInKB' = 41717888 'FreeInMB' = 40740.12 'FreeInPB' = 0 'FreeInTB' = 0.04 'IsSqlDisk' = $Null 'Label' = 'Archive Data (SLOW!)' 'Name' = 'F:\' 'PercentFree' = 99.78 'Server' = 'DummyServer' 'SizeInBytes' = 42813292544 'SizeInGB' = 39.87 'SizeInKB' = 41809856 'SizeInMB' = 40829.94 'SizeInPB' = 0 'SizeInTB' = 0.04 'Type' = [Sqlcollaborative.Dbatools.Computer.DriveType]'LocalDisk' }, [PSObject]@{ 'BlockSize' = 65536 'Capacity' = [PSObject]@{ 'Byte' = 580757946368 'Digits' = 2 'Gigabyte' = 540.872985839844 'Kilobyte' = 567146432 'Megabyte' = 553853.9375 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.528196275234222 } 'ComputerName' = 'DummyServer' 'DriveType' = 'Local Disk' 'FileSystem' = 'NTFS' 'Free' = [PSObject]@{ 'Byte' = 580605968384 'Digits' = 2 'Gigabyte' = 540.7314453125 'Kilobyte' = 566998016 'Megabyte' = 553709 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.528058052062988 } 'FreeInBytes' = 580605968384 'FreeInGB' = 540.73 'FreeInKB' = 566998016 'FreeInMB' = 553709 'FreeInPB' = 0 'FreeInTB' = 0.53 'IsSqlDisk' = $Null 'Label' = 'SQL Data' 'Name' = 'D:\' 'PercentFree' = 99.97 'Server' = 'DummyServer' 'SizeInBytes' = 580757946368 'SizeInGB' = 540.87 'SizeInKB' = 567146432 'SizeInMB' = 553853.94 'SizeInPB' = 0 'SizeInTB' = 0.53 'Type' = [Sqlcollaborative.Dbatools.Computer.DriveType]'LocalDisk' } ) } $tags = 'DiskCapacity' $ServerInfo = Get-AllServerInfo -ComputerName Dummy -Tags $tags It "Should have no results for PingComputer" { $serverInfo.PingComputer| Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Test-Connection' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } It "Should have no results for DiskAllocationUnit" { $serverInfo.DiskAllocation | Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Test-DbaDiskAllocation' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } It "Should have no results results for PowerPlan" { $serverInfo.PowerPlan | Should -BeNullOrEmpty } It "Should have no results for SPN" { $serverInfo.SPNs|Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Test-DbaSPN' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } It "Should have the right results for DiskCapacity" { $serverInfo.DiskSpace[0].ComputerName | Should -Be 'DummyServer' $serverInfo.DiskSpace[0].Name | Should -Be 'C:\' $serverInfo.DiskSpace[0].PercentFree | Should -Be 46.78 $assertMockParams = @{ 'CommandName' = 'Get-DbaDiskSpace' 'Times' = 1 'Exactly' = $true } Assert-MockCalled @assertMockParams } } Context "Testing Get-AllServerInfo for Tags DiskCapacity with a server that doesn't exist" { Mock Test-Connection {} Mock Test-DbaDiskAllocation {} Mock Test-DbaPowerPlan {} Mock Test-DbaSpn {} Mock Get-DbaDiskSpace {Throw} $tags = 'DiskCapacity' $ServerInfo = Get-AllServerInfo -ComputerName Dummy -Tags $tags It "Should have no results for PingComputer" { $serverInfo.PingComputer| Should -BeNullOrEmpty } It "Should have no results for DiskAllocationUnit" { $serverInfo.DiskAllocation| Should -BeNullOrEmpty } It "Should have no results for PowerPlan" { $serverInfo.PowerPlan | Should -BeNullOrEmpty } It "Should have no results for SPN" { $serverInfo.SPNs| Should -BeNullOrEmpty } It "Should have the right results for DiskCapacity" { $serverInfo.DiskSpace.ComputerName| Should -Be 'An Error occurred Dummy' $serverInfo.DiskSpace.Name | Should -Be 'Do not know the Name' $serverInfo.DiskSpace.PercentFree | Should -Be -1 } } Context "Testing Get-AllServerInfo for Tags DiskCapacity,SPN,DiskAllocationUnit with a server that exists" { Mock Test-Connection { } Mock Test-DbaDiskAllocation { @( [PSObject]@{ 'BlockSize' = 4096 'IsBestPractice' = $False 'IsSqlDisk' = $True 'Label' = $Null 'Name' = 'C:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $True 'Label' = 'SQL Data' 'Name' = 'D:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $False 'Label' = 'SQL Archive' 'Name' = 'F:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $True 'Label' = 'SQL Logs' 'Name' = 'L:\' 'Server' = 'DummyServer' }, [PSObject]@{ 'BlockSize' = 65536 'IsBestPractice' = $True 'IsSqlDisk' = $True 'Label' = 'SQL Performance' 'Name' = 'P:\' 'Server' = 'DummyServer' } ) } Mock Test-DbaSpn { @( [PSObject]@{ 'Cluster' = $False 'ComputerName' = 'DummyServer' 'Credential' = $Null 'DynamicPort' = $False 'Error' = 'SPN missing' 'InstanceName' = 'MSSQLSERVER' 'InstanceServiceAccount' = 'Domain\Account' 'IsSet' = $False 'Port' = $Null 'RequiredSPN' = 'MSSQLSvc/DummyServer' 'SqlProduct' = 'SQL Server 2017 Enterprise Edition: Core-based Licensing (64-bit)' 'TcpEnabled' = $True 'Warning' = 'None' }, [PSObject]@{ 'Cluster' = $False 'ComputerName' = 'DummyServer' 'Credential' = $Null 'DynamicPort' = $False 'Error' = 'SPN missing' 'InstanceName' = 'NoneDefaultInstance' 'InstanceServiceAccount' = 'Domain\Account' 'IsSet' = $False 'Port' = $Null 'RequiredSPN' = 'MSSQLSvc/DummyServer:NoneDefaultInstance' 'SqlProduct' = 'SQL Server 2016 Enterprise Edition: Core-based Licensing (64-bit)' 'TcpEnabled' = $True 'Warning' = 'None' }, [PSObject]@{ 'Cluster' = $False 'ComputerName' = 'DummyServer' 'Credential' = $Null 'DynamicPort' = $False 'Error' = 'SPN missing' 'InstanceName' = 'MSSQLSERVER' 'InstanceServiceAccount' = 'Domain\Account' 'IsSet' = $False 'Port' = '1433' 'RequiredSPN' = 'MSSQLSvc/DummyServer:1433' 'SqlProduct' = 'SQL Server 2017 Enterprise Edition: Core-based Licensing (64-bit)' 'TcpEnabled' = $True 'Warning' = 'None' }, [PSObject]@{ 'Cluster' = $False 'ComputerName' = 'DummyServer' 'Credential' = $Null 'DynamicPort' = $False 'Error' = 'SPN missing' 'InstanceName' = 'NoneDefaultInstance' 'InstanceServiceAccount' = 'Domain\Account' 'IsSet' = $False 'Port' = '1437' 'RequiredSPN' = 'MSSQLSvc/DummyServer:1437' 'SqlProduct' = 'SQL Server 2016 Enterprise Edition: Core-based Licensing (64-bit)' 'TcpEnabled' = $True 'Warning' = 'None' } ) } Mock Get-DbaDiskSpace { @( [PSObject]@{ 'BlockSize' = 4096 'Capacity' = [PSObject]@{ 'Byte' = 42355126272 'Digits' = 2 'Gigabyte' = 39.4462852478027 'Kilobyte' = 41362428 'Megabyte' = 40392.99609375 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.0385217629373074 } 'ComputerName' = 'DummyServer' 'DriveType' = 'Local Disk' 'FileSystem' = 'NTFS' 'Free' = [PSObject]@{ 'Byte' = 19814010880 'Digits' = 2 'Gigabyte' = 18.4532356262207 'Kilobyte' = 19349620 'Megabyte' = 18896.11328125 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.0180207379162312 } 'FreeInBytes' = 19814010880 'FreeInGB' = 18.45 'FreeInKB' = 19349620 'FreeInMB' = 18896.11 'FreeInPB' = 0 'FreeInTB' = 0.02 'IsSqlDisk' = $Null 'Label' = '' 'Name' = 'C:\' 'PercentFree' = 46.78 'Server' = 'DummyServer' 'SizeInBytes' = 42355126272 'SizeInGB' = 39.45 'SizeInKB' = 41362428 'SizeInMB' = 40393 'SizeInPB' = 0 'SizeInTB' = 0.04 'Type' = [Sqlcollaborative.Dbatools.Computer.DriveType]'LocalDisk' }, [PSObject]@{ 'BlockSize' = 65536 'Capacity' = [PSObject]@{ 'Byte' = 153408700416 'Digits' = 2 'Gigabyte' = 142.872985839844 'Kilobyte' = 149813184 'Megabyte' = 146301.9375 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.139524400234222 } 'ComputerName' = 'DummyServer' 'DriveType' = 'Local Disk' 'FileSystem' = 'NTFS' 'Free' = [PSObject]@{ 'Byte' = 82363809792 'Digits' = 2 'Gigabyte' = 76.707275390625 'Kilobyte' = 80433408 'Megabyte' = 78548.25 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.0749094486236572 } 'FreeInBytes' = 82363809792 'FreeInGB' = 76.71 'FreeInKB' = 80433408 'FreeInMB' = 78548.25 'FreeInPB' = 0 'FreeInTB' = 0.07 'IsSqlDisk' = $Null 'Label' = 'SQL Logs' 'Name' = 'L:\' 'PercentFree' = 53.69 'Server' = 'DummyServer' 'SizeInBytes' = 153408700416 'SizeInGB' = 142.87 'SizeInKB' = 149813184 'SizeInMB' = 146301.94 'SizeInPB' = 0 'SizeInTB' = 0.14 'Type' = [Sqlcollaborative.Dbatools.Computer.DriveType]'LocalDisk' }, [PSObject]@{ 'BlockSize' = 65536 'Capacity' = [PSObject]@{ 'Byte' = 382116757504 'Digits' = 2 'Gigabyte' = 355.873962402344 'Kilobyte' = 373160896 'Megabyte' = 364414.9375 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.347533166408539 } 'ComputerName' = 'DummyServer' 'DriveType' = 'Local Disk' 'FileSystem' = 'NTFS' 'Free' = [PSObject]@{ 'Byte' = 84496482304 'Digits' = 2 'Gigabyte' = 78.6934814453125 'Kilobyte' = 82516096 'Megabyte' = 80582.125 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.076849102973938 } 'FreeInBytes' = 84496482304 'FreeInGB' = 78.69 'FreeInKB' = 82516096 'FreeInMB' = 80582.12 'FreeInPB' = 0 'FreeInTB' = 0.08 'IsSqlDisk' = $Null 'Label' = 'SQL Performance' 'Name' = 'P:\' 'PercentFree' = 22.11 'Server' = 'DummyServer' 'SizeInBytes' = 382116757504 'SizeInGB' = 355.87 'SizeInKB' = 373160896 'SizeInMB' = 364414.94 'SizeInPB' = 0 'SizeInTB' = 0.35 'Type' = [Sqlcollaborative.Dbatools.Computer.DriveType]'LocalDisk' }, [PSObject]@{ 'BlockSize' = 65536 'Capacity' = [PSObject]@{ 'Byte' = 42813292544 'Digits' = 2 'Gigabyte' = 39.8729858398438 'Kilobyte' = 41809856 'Megabyte' = 40829.9375 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.0389384627342224 } 'ComputerName' = 'DummyServer' 'DriveType' = 'Local Disk' 'FileSystem' = 'NTFS' 'Free' = [PSObject]@{ 'Byte' = 42719117312 'Digits' = 2 'Gigabyte' = 39.7852783203125 'Kilobyte' = 41717888 'Megabyte' = 40740.125 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.0388528108596802 } 'FreeInBytes' = 42719117312 'FreeInGB' = 39.79 'FreeInKB' = 41717888 'FreeInMB' = 40740.12 'FreeInPB' = 0 'FreeInTB' = 0.04 'IsSqlDisk' = $Null 'Label' = 'Archive Data (SLOW!)' 'Name' = 'F:\' 'PercentFree' = 99.78 'Server' = 'DummyServer' 'SizeInBytes' = 42813292544 'SizeInGB' = 39.87 'SizeInKB' = 41809856 'SizeInMB' = 40829.94 'SizeInPB' = 0 'SizeInTB' = 0.04 'Type' = [Sqlcollaborative.Dbatools.Computer.DriveType]'LocalDisk' }, [PSObject]@{ 'BlockSize' = 65536 'Capacity' = [PSObject]@{ 'Byte' = 580757946368 'Digits' = 2 'Gigabyte' = 540.872985839844 'Kilobyte' = 567146432 'Megabyte' = 553853.9375 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.528196275234222 } 'ComputerName' = 'DummyServer' 'DriveType' = 'Local Disk' 'FileSystem' = 'NTFS' 'Free' = [PSObject]@{ 'Byte' = 580605968384 'Digits' = 2 'Gigabyte' = 540.7314453125 'Kilobyte' = 566998016 'Megabyte' = 553709 'Style' = [Sqlcollaborative.Dbatools.Utility.SizeStyle]'Dynamic' 'Terabyte' = 0.528058052062988 } 'FreeInBytes' = 580605968384 'FreeInGB' = 540.73 'FreeInKB' = 566998016 'FreeInMB' = 553709 'FreeInPB' = 0 'FreeInTB' = 0.53 'IsSqlDisk' = $Null 'Label' = 'SQL Data' 'Name' = 'D:\' 'PercentFree' = 99.97 'Server' = 'DummyServer' 'SizeInBytes' = 580757946368 'SizeInGB' = 540.87 'SizeInKB' = 567146432 'SizeInMB' = 553853.94 'SizeInPB' = 0 'SizeInTB' = 0.53 'Type' = [Sqlcollaborative.Dbatools.Computer.DriveType]'LocalDisk' } ) } $tags = 'DiskCapacity', 'SPN', 'DiskAllocationUnit' $ServerInfo = Get-AllServerInfo -ComputerName Dummy -Tags $tags It "Should have no results for PingComputer" { $serverInfo.PingComputer| Should -BeNullOrEmpty $assertMockParams = @{ 'CommandName' = 'Test-Connection' 'Times' = 0 'Exactly' = $true } Assert-MockCalled @assertMockParams } It "Should get the right results for DiskAllocationUnit" { $serverInfo.DiskAllocation[0].Name | Should -Be 'C:\' $serverInfo.DiskAllocation[0].isBestPractice| Should -BeFalse $serverInfo.DiskAllocation[0].isSqlDisk| Should -BeTrue } It "Should have no results results for PowerPlan" { $serverInfo.PowerPlan | Should -BeNullOrEmpty } It "Should get the right results for SPN" { $serverInfo.SPNs[0].ComputerName | Should -Be 'DummyServer' $serverInfo.SPNs[0].Error | Should -Be 'SPN missing' $serverInfo.SPNs[0].RequiredSPN | Should -Be 'MSSQLSvc/DummyServer' } It "Should have the right results for DiskCapacity" { $serverInfo.DiskSpace[0].ComputerName | Should -Be 'DummyServer' $serverInfo.DiskSpace[0].Name | Should -Be 'C:\' $serverInfo.DiskSpace[0].PercentFree | Should -Be 46.78 } } Context "Testing Get-AllServerInfo for Tags DiskCapacity,SPN,DiskAllocationUnit with a server that doesn't exist" { Mock Test-Connection {} Mock Test-DbaDiskAllocation {Throw} Mock Test-DbaPowerPlan {} Mock Test-DbaSpn {Throw} Mock Get-DbaDiskSpace {Throw} $tags = 'DiskCapacity', 'SPN', 'DiskAllocationUnit' $ServerInfo = Get-AllServerInfo -ComputerName Dummy -Tags $tags It "Should have no results for PingComputer" { $serverInfo.PingComputer| Should -BeNullOrEmpty } It "Should get the right results for DiskAllocationUnit" { $serverInfo.DiskAllocation[0].Name | Should -Be '? ' # Yes there is a space for formatting the PowerBi $serverInfo.DiskAllocation[0].isBestPractice| Should -BeFalse $serverInfo.DiskAllocation[0].isSqlDisk| Should -BeTrue } It "Should have no results for PowerPlan" { $serverInfo.PowerPlan | Should -BeNullOrEmpty } It "Should get the right results for SPN" { $serverInfo.SPNs[0].Error | Should -Be 'An Error occurred' $serverInfo.SPNs[0].RequiredSPN | Should -Be 'Dont know the SPN' } It "Should have the right results for DiskCapacity" { $serverInfo.DiskSpace.ComputerName| Should -Be 'An Error occurred Dummy' $serverInfo.DiskSpace.Name | Should -Be 'Do not know the Name' $serverInfo.DiskSpace.PercentFree | Should -Be -1 } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUL01THUaCV9L44n0ZH2D2uzfl # cN6gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTH7zwJAi7gLC7ht/hzywWrAI8H # cDANBgkqhkiG9w0BAQEFAASCAQA7vsLJAEpmYk85S0thhFFsVVMBVLC1dWqUxjkG # uy/xOG1cpn0yuHjYvil/CaLcXt1N+paOl0iLk1kI165x+OZ2BC9zw8gbAg/+J/YG # 0c0GUOxl03d4ZrqnGapviKWYbPpbADS3UIk5MzdM10g50VTk6ODrQDaJWOZJZ2nS # CMJZ9xb7pGVtFYnv6uhK3nv3BquRsyGnRGLSZlBFUQ3GCs535GFkWoyniXuua8Gq # rNgI9B5pds9sPJTpMz1OXEgRGbVzI69OIdL39uERVdRIAvETFtAABjs24zQ8R9G6 # zgjk/thuvbppWavKt8dq691e5ka/NpFN+tgTIZez5zHTCl7c # SIG # End signature block ================================================ FILE: developing/Archive/tests/constants.ps1 ================================================ $script:ModuleRoot = $PSScriptRoot $script:localapp = "$env:localappdata\dbachecks" # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUXavwZZOsmcFz+/gLFVZI9FZc # xBmgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBSPxldbr/SnIZ5PGDBnl7nu40xa # vTANBgkqhkiG9w0BAQEFAASCAQA4IJ9SOvbvAO7XOJEbuT8DeyvIAKUUXne8Y3AJ # 2IDgTSlu/aBUxgPraArQd4Y5fTuIHxEz/UxCM4nHn2/1OLLeVFHCfOirYnKrvO37 # 0GsUIT+bvuWyYkidjXiF8H91q/rKkvaf3MbO0RMTJEsKnyURDmzyVLt3gY06C+Fg # u5hKlPoFHTdg31GwzLm+cqKQYWnSy+ybT/ugDMaUf+9UayW1mN8T7/TgmUA5ZNhr # iUiXr6MajYVyMJ01CW0yHIZYaUH8kTB5uSTNn6n0DIhQqk18aSsq/4pV3CJwdMZ4 # /WQzYPRjMRtwfU71Jrxzmz5vQlRJYKWOLMq11kza3ia7w5c5 # SIG # End signature block ================================================ FILE: developing/Archive/tests/functions/Export-DbcConfig.Tests.ps1 ================================================  Describe "Export-DbcConfig Unit Tests" -Tags "IntegrationTests" { Context "Command executes properly and returns proper info" { BeforeAll { Remove-Item "$script:localapp\config.json" -ErrorAction SilentlyContinue Export-DbcConfig -Path 'TestDrive:\config.json' } AfterAll { Remove-Item "$script:localapp\config.json" -ErrorAction SilentlyContinue } It "Should not throw" { { Export-DbcConfig } | Should -Not -Throw } It "outputs default file without errors" { (Get-ChildItem "$script:localapp\config.json" -ErrorAction SilentlyContinue) -ne $null | Should -BeTrue } It "outputs a named file without errors" { Test-Path 'TestDrive:\config.json' | Should -BeTrue } It "outputs an object" { $o = Export-DbcConfig -Force $o | Get-Member -Name Open | Should -Not -BeNullOrEmpty } } } ================================================ FILE: developing/Archive/tests/functions/Get-CheckFile.Tests.ps1 ================================================ Remove-Module dbachecks -ErrorAction SilentlyContinue Import-Module "$PSScriptRoot\..\..\dbachecks.psd1" . "$PSScriptRoot/../../internal/functions/Get-CheckFile.ps1" Describe "Testing Get-CheckFile function" { Mock Get-ChildItem { return @( @{ Name = "One.Tests.ps1"; FullName = "C:\Checks\One.Tests.ps1" }, @{ Name = "Two.Tests.ps1"; FullName = "C:\Checks\Two.Tests.ps1" }, @{ Name = "Three.Tests.ps1"; FullName = "C:\Checks\Three.Tests.ps1" } ) } -ParameterFilter { $Path } Mock Get-Content { return " # some comments to start with Describe `"First fake check`" -Tags FirstCheck { Context `"Some context`" { } } Describe `"Second fake check`" -Tags SecondCheck, `$filename { Context `"Some context`" { } } Describe `"Third fake check`" -Tags ThirdCheck, `$filename { Context `"Some context`" { } } ".Split([Environment]::NewLine) } -ParameterFilter { $Path -eq "C:\Checks\One.Tests.ps1" } Mock Get-Content { return " `$filename = `$MyInvocation.MyCommand.Name.Replace(`".Tests.ps1`", `"`") Describe `"Fourth fake check`" -Tags FourthCheck, CommonTag, `$filename { Context `"Some context`" { } } Describe `"Fifth fake check`" -Tags FifthCheck,CommonTag,`$filename { Context `"Some context`" { } } # some comments at the end of a file, perhaps a function definition function Get-MeSomeStuff { param([string]`$whatToGet) process { } } ".Split([Environment]::NewLine) } -ParameterFilter { $Path -eq "C:\Checks\Two.Tests.ps1" } Mock Get-Content { return " Describe `"Sixth fake check`" -Tags `"SixthCheck`" { Context `"Some context`" { } } ".Split([Environment]::NewLine) } -ParameterFilter { $Path -eq "C:\Checks\Three.Tests.ps1" } Context "Testing with files matching by name" { $cases = @( @{ CheckValue = "One"; MatchingFile = "C:\Checks\One.Tests.ps1" } @{ CheckValue = "Two"; MatchingFile = "C:\Checks\Two.Tests.ps1" } @{ CheckValue = "Three"; MatchingFile = "C:\Checks\Three.Tests.ps1" } ) It " is found when Check is " -TestCases $cases { param([String]$CheckValue, [String]$MatchingFile) $result = @(Get-CheckFile -Repo "FakeRepo" -Check $CheckValue) $result.Count | Should -Be 1 -Because "we expect exactly one file" $result[0] | Should -Be $MatchingFile -Because "we expect specific file" } It "When two files match, both should be returned" { $result = @(Get-CheckFile -Repo "FakeRepo" -Check One,three) $result.Count | Should -Be 2 -Because "we expect exactly two files, one and three" } } Context "Testing with files matching by tag" { $cases = @( @{ CheckValue = "FirstCheck"; MatchingFile = "C:\Checks\One.Tests.ps1" } @{ CheckValue = "SecondCheck"; MatchingFile = "C:\Checks\One.Tests.ps1" } @{ CheckValue = "ThirdCheck"; MatchingFile = "C:\Checks\One.Tests.ps1" } @{ CheckValue = "FourthCheck"; MatchingFile = "C:\Checks\Two.Tests.ps1" } @{ CheckValue = "FifthCheck"; MatchingFile = "C:\Checks\Two.Tests.ps1" } @{ CheckValue = "SixthCheck"; MatchingFile = "C:\Checks\Three.Tests.ps1" } ) It " is found when Check is " -TestCases $cases { param([String]$CheckValue, [String]$MatchingFile) $result = @(Get-CheckFile -Repo "FakeRepo" -Check $CheckValue) $result.Count | Should -Be 1 -Because "we expect exactly one file" } It "When two files match, both should be returned" { $result = @(Get-CheckFile -Repo "FakeRepo" -Check SecondCheck,SixthCheck) $result.Count | Should -Be 2 -Because "we expect exactly two files, one and three" } } Context "Testing to make sure duplicates are not returned" { $cases = @( @{ CheckValue = "One,FirstCheck"; MatchingFile = "C:\Checks\One.Tests.ps1" } @{ CheckValue = "One,FirstCheck,SecondCheck"; MatchingFile = "C:\Checks\One.Tests.ps1" } @{ CheckValue = "Two,FourthCheck,InvalidCheck"; MatchingFile = "C:\Checks\Two.Tests.ps1" } @{ CheckValue = "Three,Three,Three"; MatchingFile = "C:\Checks\Three.Tests.ps1" } ) It " is found when Check is " -TestCases $cases { param([String]$CheckValue, [String]$MatchingFile) $result = @(Get-CheckFile -Repo "FakeRepo" -Check $CheckValue.Split(",")) $result.Count | Should -Be 1 -Because "we expect exactly one file" } } # test for duplicates Context "Testing things that don't match" { It "If there is no match, no file should be returned" { $result = @(Get-CheckFile -Repo "FakeRepo" -Check "NotMatchingAnything") $result.Count | Should -Be 0 -Because "we don't expect any matches to NotMatchingAnything" } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUEvVWSy+gQvt0tsmQfwVbN135 # wU+gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRTTyU4WE6SB0PPxqULWt3QOzSe # vDANBgkqhkiG9w0BAQEFAASCAQAcVYWr9PB+SwhN9enLdr2/knqP/NvEi7cId6bK # luTaPcx+JeM0Hwjk15Ct4ilpoVq321ITl9CmCZLGc6c+OC0F6PrAiWsf40LQX3h2 # ytNN0oHDZTlw2EwO83zXwnFVPR1QjyyD+S7A6sN+Vx0ft5oRFF8pZPdK1STZB/h3 # 80TDP5y2MyeAV9DXfu5NXCtElYiRxwWXzHwQU9CNn2MBEyIVWXo9D7/dxt+AxJ6Z # e+ClrTCh8vwEvSgrpJ5Oa3bH0oVFg6u03oavCe/iWMm/oMHuzjLjdTvDE/PpM2Wh # FkZhF5aifj++Ptxpv0I4HifhX5RMlUT/mX5qLpJeplVY9Yes # SIG # End signature block ================================================ FILE: developing/Archive/tests/functions/Get-CheckInformation.tests.ps1 ================================================ $ModuleBase = Split-Path -Parent $MyInvocation.MyCommand.Path Remove-Module dbachecks -ErrorAction SilentlyContinue Import-Module "$PSScriptRoot\..\..\dbachecks.psd1" . $ModuleBase\..\..\internal\functions\Get-CheckInformation.ps1 Describe "Testing Get-CheckInformation" -Tag Get-CheckInformation, Unittest { Context "Input" { It "Should have a Group Parameter"{ (Get-Command Get-CheckInformation).Parameters['group'] | Should -Not -BeNullOrEmpty -Because 'We are using this parameter' } It "Should have a Check Parameter"{ (Get-Command Get-CheckInformation).Parameters['Check'] | Should -Not -BeNullOrEmpty -Because 'We are using this parameter' } It "Should have a AllChecks Parameter"{ (Get-Command Get-CheckInformation).Parameters['AllChecks'] | Should -Not -BeNullOrEmpty -Because 'We are using this parameter' } It "Should have a ExcludeCheck Parameter"{ (Get-Command Get-CheckInformation).Parameters['ExcludeCheck'] | Should -Not -BeNullOrEmpty -Because 'We are using this parameter' } } Context "Output" { $results = (Get-Content $ModuleBase\get-check.json) -join "`n"| ConvertFrom-Json Mock Get-DbcCheck {$results.Where{$_.Group -eq $Group}} -ParameterFilter {$Group -and $Group -in ('Server','Database')} It "Should Return All of the checks for a group when the Check equals the group and nothing excluded" { Get-CheckInformation -Group Server -Check Server | Should -Be 'PowerPlan', 'InstanceConnection', 'Connectivity', 'SPN', 'DiskCapacity', 'Storage', 'DISA', 'PingComputer', 'CPUPrioritisation', 'DiskAllocationUnit' -Because 'When the Check is specified and is a group it should return all of the tags for that group and not the groupname if nothing is exclueded' } It "Should Return All of the checks for a group When AllChecks is specified and nothing excluded" { Get-CheckInformation -Group Server -AllChecks $true | Should -Be 'PowerPlan', 'InstanceConnection', 'Connectivity', 'SPN', 'DiskCapacity', 'Storage', 'DISA', 'PingComputer', 'CPUPrioritisation', 'DiskAllocationUnit' -Because 'When AllChecks is specified it should return all of the tags for that group and not the groupname if nothing is excluded' } It "Should Return one check for a group when one unique tag is specified and nothing excluded" { Get-CheckInformation -Group Server -Check SPN | Should -Be 'SPN' -Because 'When a Check is specified it should return just that check' } It "Should Return two checks for a group when two unique tags are specified and nothing excluded" { Get-CheckInformation -Group Server -Check SPN,InstanceConnection | Should -Be 'SPN', 'InstanceConnection' -Because 'When a Check is specified it should return just that check' } It "Should return a the unique tags for the none-unique tag if a none-unique tag is specified and nothing is excluded"{ Get-CheckInformation -Group Database -Check LastBackup | Should -Be 'TestLastBackup', 'TestLastBackupVerifyOnly', 'LastFullBackup', 'LastDiffBackup', 'LastLogBackup' -Because 'When a none-unique tag is specified it should return all of the unique tags' } It "Should return the unique tags for the none-unique tags if two none-unique tags are specified and nothing is excluded"{ Get-CheckInformation -Group Database -Check LastBackup, MaxDop | Should -Be 'TestLastBackup', 'TestLastBackupVerifyOnly', 'LastFullBackup', 'LastDiffBackup', 'LastLogBackup', 'MaxDopDatabase', 'MaxDopInstance' -Because 'When a none-unique tag is specified it should return all of the unique tags' } It "Should Return All of the checks for a group except the excluded ones when the Check equals the group and one check is excluded" { Get-CheckInformation -Group Server -Check Server -ExcludeCheck PowerPlan | Should -Be 'InstanceConnection', 'Connectivity', 'SPN', 'DiskCapacity', 'Storage', 'DISA', 'PingComputer', 'CPUPrioritisation', 'DiskAllocationUnit' -Because 'When the Check is specified and is a group it should return all of the tags for that group except the excluded one and not the groupname' } It "Should Return All of the checks for a group except the excluded ones when the Check equals the group and two checks are excluded" { Get-CheckInformation -Group Server -Check Server -ExcludeCheck PowerPlan, CPUPrioritisation | Should -Be 'InstanceConnection', 'Connectivity', 'SPN', 'DiskCapacity', 'Storage', 'DISA', 'PingComputer', 'DiskAllocationUnit' -Because 'When the Check is specified and is a group it should return all of the tags for that group except the excluded ones and not the groupname' } It "Should Return All of the checks for a group except the excluded ones when AllChecks is specified and one check is excluded" { Get-CheckInformation -Group Server -AllChecks $true -ExcludeCheck PowerPlan | Should -Be 'InstanceConnection', 'Connectivity', 'SPN', 'DiskCapacity', 'Storage', 'DISA', 'PingComputer', 'CPUPrioritisation', 'DiskAllocationUnit' -Because 'When the Check is specified and is a group it should return all of the tags for that group except the excluded one and not the groupname' } It "Should Return All of the checks for a group except the excluded ones when AllChecks is specified and two checks are excluded" { Get-CheckInformation -Group Server --AllChecks $true -ExcludeCheck PowerPlan, CPUPrioritisation | Should -Be 'InstanceConnection', 'Connectivity', 'SPN', 'DiskCapacity', 'Storage', 'DISA', 'PingComputer', 'DiskAllocationUnit' -Because 'When the Check is specified and is a group it should return all of the tags for that group except the excluded ones and not the groupname' } It "Mocks Get-DbcCheck"{ $assertMockParams = @{ 'CommandName' = 'Get-DbcCheck' 'Times' = 10 'Exactly' = $true } Assert-MockCalled @assertMockParams } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU/QO1w1t2IvaGC48k1oxNvLTw # ihugggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBT/f5aMZz9Q/1Idd5KPTcOMvSRj # vzANBgkqhkiG9w0BAQEFAASCAQBig6LSjIhmtoxk9Aaz3f5L7LibHHQf5Nht8xZ1 # ear+piGGYvKCA9oYQ9JgMlKaljsIBDyzLHp+61I3dDx+id/a52tOz382xZY011wv # mzx5S+fgkUCwQFdF4V93C1T8o+GH6IABFUl97gDyZDiBM+YS6xwr6mQvkAkM6bUh # 5I4+34W3+PwKZE+BSXV9vwaSlTpM7J5WQ48pkuhx5Y9G9QqKwhTnABj8lyvewjlt # G6EUcZhgLJVOkFpEJdUz6pcgkYwx/9m7j1uG5MDMOdRS0Nhw8EXoVvZZdvyN9Tdf # M2y2sO4xvt8ScdWvV0kzZ2PhEUhK793AgcTJWOrRVDc5HNJM # SIG # End signature block ================================================ FILE: developing/Archive/tests/functions/Get-DatabaseDetail.Tests.ps1 ================================================ [cmdletbinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification='Because they are used just doesnt see them')] Param() $commandname = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") Remove-Module dbachecks -ErrorAction SilentlyContinue Remove-Module dbatools -ErrorAction SilentlyContinue Import-Module "$PSScriptRoot\..\..\dbachecks.psd1" . "$PSScriptRoot/../../internal/functions/Get-DatabaseDetail.ps1" Describe "Integration testing of $commandname" -Tags SqlIntegrationTests,IntegrationTests, Integration { @(Get-DbcConfigValue testing.integration.instance).ForEach{ Context "Collecting database details for checks from $psitem" { BeforeAll { $expectedProperties = @{ ServerCollation = [string] SqlInstance = [string] SqlVersion = [int] DatabaseCollation = [string] CurrentOwner = [string] AutoShrink = [bool] AutoClose = [bool] AutoCreateStatisticsEnabled = [bool] AutoUpdateStatisticsEnabled = [bool] AutoUpdateStatisticsAsync = [bool] Trustworthy = [bool] PageVerify = [string] SuspectPages = [int] Status = [string] } $script:databases = (Get-DatabaseDetail -SqlInstance $psitem) } It "Execution of Get-DatabaseDetail should not throw exceptions" { { Get-DatabaseDetail -SqlInstance $psitem } | Should -Not -Throw -Because "we expect data not exceptions" } It "Get-DatabaseDetail should return at least the system databases" { $script:databases.Count | Should -BeGreaterOrEqual 4 -Because "we expect at least to have the system databases on any instance" } foreach($property in $expectedProperties.Keys) { It "Each database has $property which is not null or empty" { $script:databases."$property".ForEach{ $psitem | Should -Not -BeNullOrEmpty } } } foreach($property in $expectedProperties.Keys) { if ($expectedProperties[$property] -eq $null) { continue } It "$property property should be of type $($expectedProperties[$property].ToString())" { $script:databases."$property".ForEach{ $psitem | Should -BeOfType ($expectedProperties[$property]) } } } } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUr1kRyK6nxU+bdSNMAb3cXwbX # HoagggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRX4OtGxkPqKBADyCJ6DUBsCxOh # 7zANBgkqhkiG9w0BAQEFAASCAQBTlvO0xBAP8lRNwWvjId0aiqyJ1Su+c6UIIjEN # YNsyVHYEC6uEAh/pU/BWkcOTY2E3p+jMXSneWNzY4zs6BqiermaBjyU0S+VvRCbZ # uvUSOnLzgIRpxsYPGY+jzZhi7nhhkouLJoQXH7wR8VWtaCjQLkrdKkrrzLYmjD0y # 1l1j0MDrd8Dy0vsgRcEoxbGBIjAN1PINP0oH5LyFqNPmDf3vnM3M79bmqTZT41d1 # UlG6Y6kd+AXzCkXJr3+bqknOanggaEUxqTKoYamkHvZz+5dVvu6eLhXMyJVTuyRo # hCOA5PM2+GIvos5ZJ1LfXRq1nM1BsO5H0UKkyAemFZr2KV9X # SIG # End signature block ================================================ FILE: developing/Archive/tests/functions/Get-DbcCheck.Tests.ps1 ================================================ Remove-Module dbachecks -ErrorAction SilentlyContinue Import-Module "$PSScriptRoot\..\..\dbachecks.psd1" . "$PSScriptRoot\..\constants.ps1" Describe "Testing Get-DbCCheck" -Tag Get-DbCCheck, Unittest { Context "Input" { It "Should have a Tag Parameter"{ (Get-Command Get-DbCCheck).Parameters['Tag'] | Should -Not -BeNullOrEmpty -Because 'We are using this parameter' } It "Should have a Pattern Parameter"{ (Get-Command Get-DbCCheck).Parameters['Pattern'] | Should -Not -BeNullOrEmpty -Because 'We are using this parameter' } It "Should have a Group Parameter"{ (Get-Command Get-DbCCheck).Parameters['Group'] | Should -Not -BeNullOrEmpty -Because 'We are using this parameter' } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU+aKL5ZgO2MPUE6cSCTGF7Ejo # E1+gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQvloV/7lMGZwBdRNLwSvjba92T # bDANBgkqhkiG9w0BAQEFAASCAQBCIjXaTfC0P6PXOX8ZKLy0CzDDnRZwb6KDWD4I # ekCPdbQYkI441Atah2jlWCGxvfXWYCOD+lXjEpiLAOu63XPKkv278cVCfDbvYYh2 # J8OjRqMPd3BJvlISB9T9Y9SnGXx2JmoO+Hyd42gR5IsCxthW9BPFhvZwoEGU+8/H # hrbfgH7tPn+/uupuBjDhGyET3LrZCW0f5C3u6P33N/bYAxJhd188L/Vhoww722J2 # tKFJiyCWgqE0G+OCqVj63z1JDlT+k382htuWtfUZDehEsJlWvScmzq1i1QevkwlN # iiiDPc0RPhFLvJOhEXdG3YpqZva6xxdEWZyumFp3xjsT5xHX # SIG # End signature block ================================================ FILE: developing/Archive/tests/functions/Get-DbcConfig.Tests.ps1 ================================================ [cmdletbinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification='Because they are used just doesnt see them')] Param() $commandname = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") . "$PSScriptRoot\..\constants.ps1" Describe "$commandname Unit Tests" -Tags UnitTest { Context "Command executes properly and returns proper info" { BeforeAll { $results = Get-DbcConfig $specific = Get-DbcConfig -Name policy.database.autoclose $multiple = Get-DbcConfig -Name skip.tempdb1118,skip.tempdbfilecount } It "returns a number of configs" { ($results).Count -gt 10 | Should -BeTrue } It "returns a single bool" { $specific.Value -eq $true -or $specific.Value -eq $false | Should -BeTrue } It "returns results for each config provided" { $multiple.Count -eq 2 | Should -BeTrue } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUjnpD6usDE2Ytxn6EjA6yBB0a # LWGgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTQ/pUvmZstFa2qJx23JrbBAnX9 # bjANBgkqhkiG9w0BAQEFAASCAQA9UOPnHcDxc+8e+zJLeopk2Mt/AhZBlhSr2NrE # V/vQCksOb4jVfQtv/wPFdU9+lGVarwNlJOa6xWiKq5C52XCTq3THvqqd01K4kkJH # H61jr5q0ylqeyhTDY6zfvft1nx+nVaR7goVaVPeGTeorvXgMwYNtFkatdP5C9ckI # eiAylh/Tz2D8i/vh50jTePwNCDw64gT+rYGyt1QCuNAqWKfAS8SvDSl6sWAYzhSC # oG4PD0Jx5dIEva7BwjuNrWPr/sV6AQHrI6AjUTZiW2VSUnM7vLfKvy798ZoV487G # 4PFgKfsZ1kSckUbDwgZtC03hCToprsh4vYIDcy9+PYxSB663 # SIG # End signature block ================================================ FILE: developing/Archive/tests/functions/Get-DbcConfigValue.Tests.ps1 ================================================ [cmdletbinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification='Because they are used just doesnt see them')] Param() $commandname = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") . "$PSScriptRoot\..\constants.ps1" Describe "$commandname Unit Tests" -Tags UnitTest { Context "Command executes properly and returns proper info" { BeforeAll { $results = Get-DbcConfigValue -Name policy.database.autoclose } It "returns a single bool" { $results -eq $true -or $results -eq $false | Should -BeTrue } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUnPTLzEcDXLdmsE97pKgEZRYy # EaegggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTk8IOjDoRx1m1KaMdWf2fkb7vY # mjANBgkqhkiG9w0BAQEFAASCAQBeVLVjcjOCGGmoqQHqB/Vdpn9HPtsP7rQNCFg6 # tEGpaqO7BHBbPZOcLWvJPd6G8zK4o1M54O7xqaY8X43mA9WMvk4LZCD/zdPa6LWR # C/yRZcyQf9Ca3h2QFB4+LrHa3WXBf2fhsX3NhFFoiqFYVmrt1Nkq489O0e0fy0v3 # IPCRgbmX2D2gUV2IUpmA19Nd1z0MtPLLPncU2x+bFMQgToLCYxf6cN8Koeuytgj8 # 9lWZ1Q2umbwtWzeRiW/PA7JJ5h539F+iGKXGomCfHgBzTAqWoABN405VXAo4FX/7 # Jib9WtDIqdp1wDAzyjCG5uMc8F4KI1LldZQdHruOlll5waUX # SIG # End signature block ================================================ FILE: developing/Archive/tests/functions/Get-DbcTagCollection.Tests.ps1 ================================================ $commandname = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") . "$PSScriptRoot\..\constants.ps1" Describe "$commandname Unit Tests" -Tags UnitTest { Context "Command executes properly and returns proper info" { $results = Get-DbcTagCollection $count = ($results).Count It "returns a number of tags" { $count -gt 10 | Should -BeTrue } It "returns a unique number of tags" { ($results | Sort-Object | Select-Object -Unique).Count | Should -Be $count } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUFv2FO6gM4Xos6qAixAoES6/J # pbagggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBT9q4/nFgZ5r0wQADWLmPLiIJz8 # DzANBgkqhkiG9w0BAQEFAASCAQBOFBNJRbyDKiBWm+aYnb2Cm+4LUvc0RTdhspSh # MEwx/bAaI0esvYw4BJhOoCBllrtc7pJW+/1cGhTvvx/HaAfGQPqp7dSHHTYsRj8Q # 4OK7ornRm8rmPKiOY5AC83+g7ZSuTZ+cUukYEOmieoiEtoC2mNnpBv+Xg9N852PN # 79WX806uWf7bJTXbX5nCIvd9oqgALIVcsbQ8TEkGQgC5tt4VVBat5ZZh4sm1eKSD # AvcZ0Sb/zi5EQQVXbyv4LuuuU8E1bmpWKrvfS16HdW7yg31XGwm5VJ8D92W2WWKm # CTZFHyfdF8cp1RvDIwS/E4odFRWP66w+vijnSzE3CLcAjptH # SIG # End signature block ================================================ FILE: developing/Archive/tests/functions/Import-DbcConfig.Tests.ps1 ================================================ $commandname = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") . "$PSScriptRoot\..\constants.ps1" Describe "$commandname Unit Tests" -Tags UnitTest { Context "Command executes properly and returns proper info" { BeforeAll { Export-DbcConfig -Force *>$null } AfterAll { Remove-Item "$script:localapp\config.json" -ErrorAction SilentlyContinue } It "returns a bunch of results" { $results = Import-DbcConfig -Path "$script:localapp\config.json" -WarningAction SilentlyContinue -WarningVariable warns 3>$null ($results).Count -gt 10 | Should -BeTrue } It -Skip "returns some results for app.checkrepos" { #skip till I get the syntax right ($results | Where-Object name -eq app.checkrepos) -ne $null | Should -BeTrue } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUVEfB09qwuaqHyqMsj0slnnWS # lfmgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBT+oFRIiIegkkfrxXRlG9rfdb81 # 9zANBgkqhkiG9w0BAQEFAASCAQBbrHQR4MBOQk2mL/lmHG8buO1xVjGiVs1vAl0W # lKKvIrJ7QUjz2iO7hUu3PKARtBxBS1CWB3mUjMgxtgF3wpHsf/sgCgdWQygLIaXq # IaO9TcJGjclC7Kmle/hD8pMhVN2/Mua7cX5pq0lHGQKsu/0Jj4LoVwXMu7W9sLAg # GdAf1xKOgW6/FSTzi9A5n1EHdEI+DK/7lTYKUgTq/Xtkavlm6WVSeq4vaB73cdGf # tdlMBHm2vnJPYnyseNxprfQLw90XzjSCYFXE0H+MvUJ6twpwG3kz6jvw0SUDSLMw # 1DErBUaYfILccZKqI13zATBD2pRN7scq1CwZFm6bXIPK7UsQ # SIG # End signature block ================================================ FILE: developing/Archive/tests/functions/Invoke-DbcCheck.Tests.ps1 ================================================ $commandname = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") . "$PSScriptRoot\..\constants.ps1" Describe "$commandname Unit Tests" -Tags IntegrationTests, Integration { @(Get-DbcConfigValue testing.integration.instance).ForEach{ Context "Command executes properly and returns proper info on $psitem" { It "runs a check" { $results = Invoke-DbcCheck -ComputerName $psitem -Tag DiskCapacity -Passthru -Show None $results.TestResult | Should Not Be $null # Because nothing else works right now } } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU1zYGWWVD6aVzUjZVcNcySuSk # Fy6gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRtZWNhsj2ErrD56728KzQijuIX # EjANBgkqhkiG9w0BAQEFAASCAQAqxbMGd4UJdGGkotfLjWWWPKCIYZLB1+wxThHU # c3Qj6qr1yLYyjozRnViQGMGhco4bXTTuSCehQXDxko0m4ln1OT6mMv94mEgGzZGU # PyiRBIcK1lsV6f09KRD4h+jDtNrinkUCAQ9+lpOvX+6bEaWPCZjH9XIsYvKqEN0I # Z9IzqSxt5/3KED7GV2Z314YlW6TZ79vhghv5Sp4fPDUwvQqVwGOR6SdS5QM3VoE4 # NiimNswl8+nlIlHqpKtDkF353/lWHVCnuG5tBWn+FhX0V7N0I1nU/0RfhLjHsDWS # IEsNhD+cd6Zhi1yBrgHTBO5uMG44TCoCtNNjo3Mr8hBDG9bU # SIG # End signature block ================================================ FILE: developing/Archive/tests/functions/Invoke-DbcConfigFile.Tests.ps1 ================================================ $commandname = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") . "$PSScriptRoot\..\constants.ps1" Describe "$commandname Unit Tests" -Tags UnitTest { Context "Command executes properly and returns proper info" { BeforeAll { Remove-Item "$script:localapp\config.json" -ErrorAction SilentlyContinue } It "returns a warning" { Invoke-DbcConfigFile -Path "$script:localapp\config.json" -WarningAction SilentlyContinue -WarningVariable warning *>$null $warning | Should not be $null } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU5hKAnOebIWwtzECQ3CmorRbt # KXigggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBT35UDCYoBpRM1ICHlJK2uAj1MI # LTANBgkqhkiG9w0BAQEFAASCAQBIHsLcnRP0uEwIKtos80jeo9Y1H2gs6+ZKSJzO # 3rHvYtbB2EMZx4tYQMYMlRYCLWFKiZ+qbjpdhwjCYnug2+XcbIJWeJgR9+j4ZS2z # z2gFT0/C6j957AtDW00zBSta+A8bXAN5wjwpMbX+wvZpstkMC9svaowBpu2v0J2j # /e6JqdltHGfQi9jUmGIa4W7JpcmLoOhSpu17TlcUF+17G5VItM6EchBUsxmFH3DM # Zg48kQbZLeK88BKKdb8b9kMtm45OowXFVUDfeiUMDViZb1Nb96S2dqu2lttci6y5 # 1iz2IziqcLMb3cird1mOEa+wfWmehRtdaupdJgtn9Cy0NHmr # SIG # End signature block ================================================ FILE: developing/Archive/tests/functions/Set-DbcConfig.Tests.ps1 ================================================ [cmdletbinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification='Because they are used just doesnt see them')] Param() $commandname = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") . "$PSScriptRoot\..\constants.ps1" Describe "$commandname Unit Tests" -Tags UnitTest { Context "Command executes properly and returns proper info" { BeforeAll { $config = Get-DbcConfig -Name policy.dump.maxcount } AfterAll { $result = Set-DbcConfig -Name policy.dump.maxcount -Value $config.Value } $result = Set-DbcConfig -Name policy.dump.maxcount -Value ($config.Value + 1) It "sets a config" { $result.Value | Should -Be ($config.Value + 1) } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUMXfFTmifTVD5Eg3faOsEEtqo # +cigggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBS7zyZiTlxogVd75omcLLLzMhst # OTANBgkqhkiG9w0BAQEFAASCAQBheoVEIkczFmUzxFlBCDktW1jVFsx4SFezYm/t # Ex9du3WxDalP5Q43Ymcuw3ajbWMTmkXVvt3ueE89LFP0dbf7d9PYTJTLaOB1wYJH # OaCVedX4Xmjf3DnS2WtKAHKcnlhZ/vrUS3Hpwdk+bh/B/JxHmz07y/yr6mgR7eeb # qSuN3xXPQJDmvc6iYCRy20N4WCnTsjr+fh40YeqeE3fL6F9fJfanqa/WA2JxKebj # 8ltnlt78MLB48FAYiTBF7ib2kotO6H0ZDpWwIYb6gxjHffpIjMoJsJyakR/AQ90C # LmYVm5h+MO5PogKBCDqPtR6RhQQkRmmI5zOtnBv0U4JF1n1N # SIG # End signature block ================================================ FILE: developing/Archive/tests/functions/Set-DbcFile.Tests.ps1 ================================================ $commandname = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") Remove-Module dbachecks -ErrorAction SilentlyContinue # Import-Module "$PSScriptRoot\..\..\dbachecks.psd1" . "$PSScriptRoot\..\..\functions\Set-DbcFile.ps1" . "$PSScriptRoot\..\..\functions\Convert-DbcResult.ps1" . "$PSScriptRoot\..\constants.ps1" Describe "$commandname Unit Tests" -Tags UnitTest, Set-DbcFile { Context "Parameters and parameter sets" { $ParametersList = 'InputObject','FilePath', 'FileName', 'FileType', 'Append', 'Force' $ParametersList.ForEach{ It "$commandname Should have a mandatory parameter $psitem" { (Get-Command $commandname ).Parameters[$psitem].Attributes.Mandatory | Should -BeTrue -Because "These parameters need to be mandatory because of the Parameter Sets" } It "$commandname Should have a parameter $psitem" { (Get-Command $commandname ).Parameters[$psitem].Count | Should -Be 1 -Because "This parameter should exist" } } $ParameterSets = 'Default', 'Append', 'Force' $ParameterSets.ForEach{ It "$commandname should have a parameter set named $psitem" { (Get-Command Set-DbcFile).ParameterSets.Name | Should -Contain $psitem -Because "We need these parameter sets so users cannot run with force and append" } } } } Describe "$commandname Unit Tests - Execution" -Tags UnitTest, Set-DbcFile { Context "Execution" { # So that we dont get any output in the tests but can test for It Mock Write-PSFMessage { } -ParameterFilter { $Level -and $Level -eq 'Significant' } Mock Write-PSFMessage { } -ParameterFilter { $Level -and $Level -eq 'Verbose' } Mock Write-PSFMessage { } -ParameterFilter { $Level -and $Level -eq 'Output' } Mock Write-PSFMessage { } -ParameterFilter { $Level -and $Level -eq 'Warning' } # So that we dont create files Mock Export-Csv { } Mock ConvertTo-Json {'dummy'} Mock Out-File { } Mock Export-Clixml { } $TheTestResults = Get-Content $PSScriptRoot\results.json -raw | ConvertFrom-Json It "Should produce an error message if test results are not passed via pipeline and stop" { # mock for test-path to fail Mock Test-Path {} $Nothing | Set-DbcFile -FilePath DummyDirectory -FileName DummyFileName -FileType CSV -ErrorAction SilentlyContinue #Check that Test-Path mock was not called $assertMockParams = @{ 'CommandName' = 'Test-Path' 'Times' = 0 'Exactly' = $true 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we check for directory - we should not have - Because we need to know that the Mocks are working" #Check that correct Write-PsfMessage mock was called $assertMockParams = @{ 'CommandName' = 'Write-PsfMessage' 'Times' = 1 'Exactly' = $true 'ParameterFilter' = { $Level -and $Level -eq 'Significant' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we provide Significant output - Because we need to know that the Mocks are working" #Check that correct Write-PsfMessage mock was called $assertMockParams = @{ 'CommandName' = 'Write-PsfMessage' 'Times' = 1 'Exactly' = $true 'ParameterFilter' = { $Level -and $Level -eq 'Verbose' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we provide Verbose output - Because we need to know that the Mocks are working" #Check that correct Write-PsfMessage mock was called $assertMockParams = @{ 'CommandName' = 'Write-PsfMessage' 'Times' = 1 'Exactly' = $true 'ParameterFilter' = { $Level -and $Level -eq 'Warning' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we provide Warning output - Because we need to know that the Mocks are working" } It "Should produce an error message if the path does not exist or we cannot access it" { # mock for test-path to fail Mock Test-Path { $false } -ParameterFilter { $Path -and $Path -eq 'DummyDirectory' } Mock Test-Path { $false } -ParameterFilter { $Path -and $Path -eq 'DummyDirectory\DummyFileName' } Set-DbcFile -InputObject $TheTestResults -FilePath DummyDirectory -FileName DummyFileName -FileType CSV -verbose #Check that Test-Path mock was called $assertMockParams = @{ 'CommandName' = 'Test-Path' 'Times' = 1 'Exactly' = $true 'ParameterFilter' = { $Path -and $Path -eq 'DummyDirectory' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we check for directory - Because we need to know that the Mocks are working" #Check that Test-Path mock was not called $assertMockParams = @{ 'CommandName' = 'Test-Path' 'Times' = 0 'Exactly' = $true 'ParameterFilter' = { $Path -and $Path -eq 'DummyDirectory\DummyFileName' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we check for file - Because we need to know that the Mocks are working" #Check that correct Write-PsfMessage mock was called $assertMockParams = @{ 'CommandName' = 'Write-PsfMessage' 'Times' = 1 'Exactly' = $true 'ParameterFilter' = { $Level -and $Level -eq 'Significant' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we provide Significant output - Because we need to know that the Mocks are working" #Check that correct Write-PsfMessage mock was called $assertMockParams = @{ 'CommandName' = 'Write-PsfMessage' 'Times' = 2 'Exactly' = $true 'ParameterFilter' = { $Level -and $Level -eq 'Verbose' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we provide Verbose output - Because we need to know that the Mocks are working" } It "Should produce a message if the file exists and Force and Append were not specified" { # mock for test-path to fail Mock Test-Path { $true } -ParameterFilter { $Path -and $Path -eq 'DummyDirectory' } Mock Test-Path { $true } -ParameterFilter { $Path -and $Path -eq 'DummyDirectory\DummyFileName' } Set-DbcFile -InputObject $TheTestResults -FilePath DummyDirectory -FileName DummyFileName -FileType CSV -Verbose #Check that Test-Path mock was called $assertMockParams = @{ 'CommandName' = 'Test-Path' 'Times' = 1 'Exactly' = $true 'ParameterFilter' = { $Path -and $Path -eq 'DummyDirectory' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we check for directory - Because we need to know that the Mocks are working" #Check that Test-Path mock was not called $assertMockParams = @{ 'CommandName' = 'Test-Path' 'Times' = 1 'Exactly' = $true 'ParameterFilter' = { $Path -and $Path -eq 'DummyDirectory\DummyFileName' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we check for file - Because we need to know that the Mocks are working" #Check that correct Write-PsfMessage mock was called $assertMockParams = @{ 'CommandName' = 'Write-PsfMessage' 'Times' = 1 'Exactly' = $true 'ParameterFilter' = { $Level -and $Level -eq 'Significant' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we provide Significant output - Because we need to know that the Mocks are working" #Check that correct Write-PsfMessage mock was called $assertMockParams = @{ 'CommandName' = 'Write-PsfMessage' 'Times' = 3 'Exactly' = $true 'ParameterFilter' = { $Level -and $Level -eq 'Verbose' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we provide Verbose output - Because we need to know that the Mocks are working" } It "Should produce a verbose message if the file exists and Force was specified" { # mock for test-path to fail Mock Test-Path { $true } -ParameterFilter { $Path -and $Path -eq 'DummyDirectory' } Mock Test-Path { $true } -ParameterFilter { $Path -and $Path -eq 'DummyDirectory\DummyFileName' } Set-DbcFile -InputObject $TheTestResults -FilePath DummyDirectory -FileName DummyFileName -Force -FileType CSV #Check that Test-Path mock was called $assertMockParams = @{ 'CommandName' = 'Test-Path' 'Times' = 1 'Exactly' = $true 'ParameterFilter' = { $Path -and $Path -eq 'DummyDirectory' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we check for directory - Because we need to know that the Mocks are working" #Check that Test-Path mock was not called $assertMockParams = @{ 'CommandName' = 'Test-Path' 'Times' = 1 'Exactly' = $true 'ParameterFilter' = { $Path -and $Path -eq 'DummyDirectory\DummyFileName' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we check for file - Because we need to know that the Mocks are working" #Check that correct Write-PsfMessage mock was called $assertMockParams = @{ 'CommandName' = 'Write-PsfMessage' 'Times' = 5 'Exactly' = $true 'ParameterFilter' = { $Level -and $Level -eq 'Verbose' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we provide Verbose output - Because we need to know that the Mocks are working" #Check that correct Write-PsfMessage mock was called $assertMockParams = @{ 'CommandName' = 'Write-PsfMessage' 'Times' = 0 'Exactly' = $true 'ParameterFilter' = { $Level -and $Level -eq 'Significant' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we provide Significant output - Because we need to know that the Mocks are working" } It "Should produce a verbose message if the file exists and Append was specified and the filetype is not XML" { # mock for test-path to fail Mock Test-Path { $true } -ParameterFilter { $Path -and $Path -eq 'DummyDirectory' } Mock Test-Path { $true } -ParameterFilter { $Path -and $Path -eq 'DummyDirectory\DummyFileName' } Set-DbcFile -InputObject $TheTestResults -FilePath DummyDirectory -FileName DummyFileName -FileType CSV -Verbose #Check that Test-Path mock was called $assertMockParams = @{ 'CommandName' = 'Test-Path' 'Times' = 1 'Exactly' = $true 'ParameterFilter' = { $Path -and $Path -eq 'DummyDirectory' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we check for directory - Because we need to know that the Mocks are working" #Check that Test-Path mock was not called $assertMockParams = @{ 'CommandName' = 'Test-Path' 'Times' = 1 'Exactly' = $true 'ParameterFilter' = { $Path -and $Path -eq 'DummyDirectory\DummyFileName' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we check for file - Because we need to know that the Mocks are working" #Check that correct Write-PsfMessage mock was called $assertMockParams = @{ 'CommandName' = 'Write-PsfMessage' 'Times' = 3 'Exactly' = $true 'ParameterFilter' = { $Level -and $Level -eq 'Verbose' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we provide Verbose output - Because we need to know that the Mocks are working" #Check that correct Write-PsfMessage mock was called $assertMockParams = @{ 'CommandName' = 'Write-PsfMessage' 'Times' = 1 'Exactly' = $true 'ParameterFilter' = { $Level -and $Level -eq 'Significant' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we provide Significant output - Because we need to know that the Mocks are working" } It "Should produce a significant message if the file exists and Append was specified and the filetype is XML" { # mock for test-path to suceed Mock Test-Path { $true } -ParameterFilter { $Path -and $Path -eq 'DummyDirectory' } Mock Test-Path { $true } -ParameterFilter { $Path -and $Path -eq 'DummyDirectory\DummyFileName' } Set-DbcFile -InputObject $TheTestResults -FilePath DummyDirectory -FileName DummyFileName -FileType XML #Check that Test-Path mock was called $assertMockParams = @{ 'CommandName' = 'Test-Path' 'Times' = 1 'Exactly' = $true 'ParameterFilter' = { $Path -and $Path -eq 'DummyDirectory' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we check for directory - Because we need to know that the Mocks are working" #Check that Test-Path mock was not called $assertMockParams = @{ 'CommandName' = 'Test-Path' 'Times' = 1 'Exactly' = $true 'ParameterFilter' = { $Path -and $Path -eq 'DummyDirectory\DummyFileName' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we check for file - Because we need to know that the Mocks are working" #Check that correct Write-PsfMessage mock was called $assertMockParams = @{ 'CommandName' = 'Write-PsfMessage' 'Times' = 3 'Exactly' = $true 'ParameterFilter' = { $Level -and $Level -eq 'Verbose' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we provide Verbose output - Because we need to know that the Mocks are working" #Check that correct Write-PsfMessage mock was called $assertMockParams = @{ 'CommandName' = 'Write-PsfMessage' 'Times' = 1 'Exactly' = $true 'ParameterFilter' = { $Level -and $Level -eq 'Significant' } 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we provide Signicificant output - Because we need to know that the Mocks are working" } It "Should export to csv when called with filetype csv"{ # mock for test-path to suceed Mock Test-Path { $true } -ParameterFilter { $Path -and $Path -eq 'DummyDirectory' } Mock Test-Path { $false } -ParameterFilter { $Path -and $Path -eq 'DummyDirectory\DummyFileName' } Set-DbcFile -InputObject $TheTestResults -FilePath DummyDirectory -FileName DummyFileName -FileType CSV #Check that correct Export-Csv mock was called $assertMockParams = @{ 'CommandName' = 'Export-Csv' 'Times' = 1 'Exactly' = $true 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we output a csv - Because we need to know that the Mocks are working" } It "Should export to json when called with filetype json"{ # mock for test-path to suceed Mock Test-Path { $true } -ParameterFilter { $Path -and $Path -eq 'DummyDirectory' } Mock Test-Path { $false } -ParameterFilter { $Path -and $Path -eq 'DummyDirectory\DummyFileName' } Set-DbcFile -InputObject $TheTestResults -FilePath DummyDirectory -FileName DummyFileName -FileType json #Check that ConvertTo-Json mock was called $assertMockParams = @{ 'CommandName' = 'ConvertTo-Json' 'Times' = 1 'Exactly' = $true 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we output a json - Because we need to know that the Mocks are working" #Check that correct Out-File mock was called $assertMockParams = @{ 'CommandName' = 'Out-File' 'Times' = 1 'Exactly' = $true 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we output a json - Because we need to know that the Mocks are working" } It "Should export to XML when called with filetype xml"{ # mock for test-path to suceed Mock Test-Path { $true } -ParameterFilter { $Path -and $Path -eq 'DummyDirectory' } Mock Test-Path { $false } -ParameterFilter { $Path -and $Path -eq 'DummyDirectory\DummyFileName' } Set-DbcFile -InputObject $TheTestResults -FilePath DummyDirectory -FileName DummyFileName -FileType xml #Check that Export-Clixml mock was called $assertMockParams = @{ 'CommandName' = 'Export-Clixml' 'Times' = 1 'Exactly' = $true 'Scope' = 'It' } { Assert-MockCalled @assertMockParams } | Should -Not -Throw -Because "Did we output a XML - Because we need to know that the Mocks are working" } } } Describe "$commandname integration tests" -Tag UnitTest ,Set-DbcFile { $TheTestResults = Get-Content $PSScriptRoot\results.json -raw | ConvertFrom-Json | Convert-DbcResult -Label 'Testing' # So that we dont get any output in the tests but can test for It Mock Write-PSFMessage { } -ParameterFilter { $Level -and $Level -eq 'Output' } Context "File Creation"{ $TestCases = @{ FileName1 = 'DummyFileName' FileName2= 'DummyFileName1.csv' Filetype = 'csv' }, @{ FileName1 = 'DummyFileName' FileName2= 'DummyFileName1.json' Filetype = 'json' }, @{ FileName1 = 'DummyFileName' FileName2= 'DummyFileName1.xml' Filetype = 'xml' } It "Should create a file with an extension . even if the extension is not specified" -TestCases $TestCases{ Param($FileName1,$FileType) Set-DbcFile -InputObject $TheTestResults -FilePath $TestDrive -FileName $FileName1 -FileType $Filetype $FileName = "$TestDrive\$filename1" + '.' + $FileType $FileName| Should -Exist } It "Should create a file with an extension . if the extension is specified"-TestCases $TestCases{ Param($FileName2,$FileType) Set-DbcFile -InputObject $TheTestResults -FilePath $TestDrive -FileName $FileName2 -FileType $Filetype $FileName = "$TestDrive\$FileName2" $FileName| Should -Exist } } # Need ot have .* whereveer there is a date as the date is dynamic $JsonFileContent = @" [ { "Date": ".*", "Label": "Testing", "Describe": "Last Good DBCC CHECKDB", "Context": "Testing Last Good DBCC CHECKDB", "Name": "Database master has Data Purity Enabled", "Database": "master", "ComputerName": "localhost,15592", "Instance": "localhost,15592", "Result": "Passed", "FailureMessage": "" }, { "Date": ".*", "Label": "Testing", "Describe": "Last Good DBCC CHECKDB", "Context": "Testing Last Good DBCC CHECKDB", "Name": "Database master last good integrity check should be less than 3 days old", "Database": "master", "ComputerName": "localhost,15592", "Instance": "localhost,15592", "Result": "Failed", "FailureMessage": "Expected the actual value to be greater than .*, because You should have run a DBCC CheckDB inside that time, but got .*" }, ] "@ $CSVFileContent = @" "Date","Label","Describe","Context","Name","Database","ComputerName","Instance","Result","FailureMessage" ".*","Testing","Last Good DBCC CHECKDB","Testing Last Good DBCC CHECKDB","Database master last good integrity check should be less than 3 days old","master","localhost,15592","localhost,15592","Failed","Expected the actual value to be greater than 2019-12-21T15:21:38.3892727Z, because You should have run a DBCC CheckDB inside that time, but got 2019-12-21T14:41:58.0230000." ".*","Testing","Last Good DBCC CHECKDB","Testing Last Good DBCC CHECKDB","Database master has Data Purity Enabled","master","localhost,15592","localhost,15592","Passed","" "@ $XMLFileContent = @" Selected.System.Data.DataRow System.Management.Automation.PSCustomObject System.Object
.*
Testing Last Good DBCC CHECKDB Testing Last Good DBCC CHECKDB Database master last good integrity check should be less than 3 days old master localhost,15592 localhost,15592 Failed Expected the actual value to be greater than .*, because You should have run a DBCC CheckDB inside that time, but got .*
.*
Testing Last Good DBCC CHECKDB Testing Last Good DBCC CHECKDB Database master has Data Purity Enabled master localhost,15592 localhost,15592 Passed
"@ Context "File Content"{ $TestCases = @{ FileName1 = 'DummyFileName' FileName2= 'DummyFileName1.csv' Filetype = 'csv' FileContent = $CSVFileContent }, @{ FileName1 = 'DummyFileName' FileName2= 'DummyFileName1.json' Filetype = 'json' FileContent = $JsonFileContent }, @{ FileName1 = 'DummyFileName' FileName2= 'DummyFileName1.xml' Filetype = 'xml' FileContent = $XMLFileContent } It " File should have the correct contents" -TestCases $TestCases{ Param($FileName1,$FileType, $FileContent) $FileName = "$TestDrive\$filename1" + '.' + $FileType $TheTestResults | Set-DbcFile -FilePath $TestDrive -FileName $FileName1 -FileType $Filetype -Verbose $FileName5 = "c:\temp\$filename1" + '.' + $FileType Get-Content $FileName |Set-Content $FileName5 $FileName | Should -FileContentMatchMultiline $FileContent } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUaU2PiV/2/Zd/mivp1JQkfU0h # 64+gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTfRSlwVrEIKMwGmYGY7sPFIXAv # ojANBgkqhkiG9w0BAQEFAASCAQA37CSp24Izu7mKVjXGuNLdR74HI1OrzEgxyBtM # Y1R9g8CHU8KWJrPkkhiPO3MKghookjZVCW/IbELw/l/um7wjG0Rak13Ka+YGEyvN # /3EzzcaH55vA+wMsR3eBQCO/sNi1r8lorzw/jxsROgupEL3jzrYmHZXkbGikOe2V # BYSE6/Ln/uaw35VXujiJ/Ln7QbyedlccM6WfyCk38IUxttF0Ms3oUVqIrMV/3nkR # ofBdzULzyaS2iSHS/ZQ/A5XHgqhJhJz3D22LI74Jo2QAeueEhrRNNz/pVLd59z4i # 5G9PgBvGtRhVetWd6hsZW+ysKqXFZ1TxW50Fx3G604ejXnV9 # SIG # End signature block ================================================ FILE: developing/Archive/tests/functions/get-check.json ================================================ [ { "Group": "Agent", "Type": "Sqlinstance", "UniqueTag": "AgentServiceAccount", "AllTags": "AgentServiceAccount, ServiceAccount, Agent", "Config": "app.sqlinstance ", "Description": "Tests that the SQL Agent Account is running and set to automatic", "Describe": "SQL Agent Account" }, { "Group": "Agent", "Type": "Sqlinstance", "UniqueTag": "DbaOperator", "AllTags": "DbaOperator, Operator, Agent", "Config": "app.sqlinstance agent.dbaoperatorname agent.dbaoperatoremail ", "Description": "Tests that the specified (default blank) DBA Operators exist and have the correct email address", "Describe": "DBA Operators" }, { "Group": "Agent", "Type": "Sqlinstance", "UniqueTag": "FailsafeOperator", "AllTags": "FailsafeOperator, Operator, Agent", "Config": "app.sqlinstance agent.failsafeoperator ", "Description": "Tests that the specified (default blank) Failsafe Operator exists", "Describe": "Failsafe Operator" }, { "Group": "Agent", "Type": "Sqlinstance", "UniqueTag": "DatabaseMailProfile", "AllTags": "DatabaseMailProfile, Agent", "Config": "app.sqlinstance agent.databasemailprofile ", "Description": "Tests that the specified (default blank) Database Mail Profile exists", "Describe": "Database Mail Profile" }, { "Group": "Agent", "Type": "Sqlinstance", "UniqueTag": "FailedJob", "AllTags": "FailedJob, Agent", "Config": "app.sqlinstance ", "Description": "Tests that enabled Agent Jobs last outcome was succeeded", "Describe": "Failed Jobs" }, { "Group": "Agent", "Type": "Sqlinstance", "UniqueTag": "ValidJobOwner", "AllTags": "ValidJobOwner, Agent", "Config": "app.sqlinstance agent.validjobowner.name ", "Description": "Tests that all Agent Jobs have a Job Owner in the list specified (default sa)", "Describe": "Valid Job Owner" }, { "Group": "Agent", "Type": "Sqlinstance", "UniqueTag": "AgentAlert", "AllTags": "AgentAlert, Agent", "Config": "app.sqlinstance agent.alert.Severity agent.alert.messageid agent.alert.Job agent.alert.Notification ", "Description": "Tests that there are Agent Alerts set up for the specified (default 16-25) alert severities and ids (default 823-825) and if specified Agent Jobs and/or notifications", "Describe": "Agent Alerts" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "DatabaseCollation", "AllTags": "DatabaseCollation, Database", "Config": "app.sqlinstance policy.database.wrongcollation ", "Description": "Tests that the Database Collation matches the instance collation except for specified databases", "Describe": "Database Collation" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "SuspectPage", "AllTags": "SuspectPage, Database", "Config": "app.sqlinstance ", "Description": "Tests that there are 0 Suspect Pages for the database", "Describe": "Suspect Page" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "TestLastBackup", "AllTags": "TestLastBackup, Backup, Database", "Config": "app.sqlinstance skip.backup.testing policy.backup.testserver policy.backup.datadir policy.backup.logdir ", "Description": "Restores the last backup of a database onto a specified (default blank so will use the same instance) restore instance and checks if the DBCC result was successful as well as the DBCC result. This can obviously take some time for large databases!", "Describe": "Last Backup Restore Test" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "TestLastBackupVerifyOnly", "AllTags": "TestLastBackupVerifyOnly, Backup, Database", "Config": "app.sqlinstance policy.backup.newdbgraceperiod ", "Description": "Does a verify only restore of the last backup of the database and test the result", "Describe": "Last Backup VerifyOnly" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "ValidDatabaseOwner", "AllTags": "ValidDatabaseOwner, Database", "Config": "app.sqlinstance policy.validdbowner.name policy.validdbowner.excludedb ", "Description": "Tests that the database owner is in the specified (default blank) list", "Describe": "Valid Database Owner" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "InvalidDatabaseOwner", "AllTags": "InvalidDatabaseOwner, Database", "Config": "app.sqlinstance policy.invaliddbowner.name policy.invaliddbowner.excludedb ", "Description": "Tests that the Database Owner is NOT in the specified (default blank) list", "Describe": "Invalid Database Owner" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "LastGoodCheckDb", "AllTags": "LastGoodCheckDb, Database", "Config": "app.sqlinstance policy.dbcc.maxdays skip.dbcc.datapuritycheck policy.backup.newdbgraceperiod ", "Description": "Tests that there was a Last Good DBCC CHECKDB within the specified limit (default blank) and if specified that the DATA_PURITY flag is set", "Describe": "Last Good DBCC CHECKDB" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "IdentityUsage", "AllTags": "IdentityUsage, Database", "Config": "app.sqlinstance policy.identity.usagepercent ", "Description": "Tests that identity columns values are not above the specified percentage (default blank) of the maximum value for that data type", "Describe": "Column Identity Usage" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "RecoveryModel", "AllTags": "RecoveryModel, DISA, Database", "Config": "app.sqlinstance policy.recoverymodel.type policy.recoverymodel.excludedb ", "Description": "Tests that the Recovery model for all of the databases is set as specified (default blank) except for any specified", "Describe": "Recovery Model" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "DuplicateIndex", "AllTags": "DuplicateIndex, Database", "Config": "app.sqlinstance ", "Description": "Tests for any duplicate indexes", "Describe": "Duplicate Index" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "UnusedIndex", "AllTags": "UnusedIndex, Database", "Config": "app.sqlinstance ", "Description": "Tests for any unused indexes", "Describe": "Unused Index" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "DisabledIndex", "AllTags": "DisabledIndex, Database", "Config": "app.sqlinstance ", "Description": "Tests for any disabled indexes", "Describe": "Disabled Index" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "DatabaseGrowthEvent", "AllTags": "DatabaseGrowthEvent, Database", "Config": "app.sqlinstance policy.database.filegrowthexcludedb ", "Description": "Tests for any database growth events in the default system trace", "Describe": "Database Growth Event" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "PageVerify", "AllTags": "PageVerify, Database", "Config": "app.sqlinstance policy.pageverify ", "Description": "Tests the page verify settings", "Describe": "Page Verify" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "AutoClose", "AllTags": "AutoClose, Database", "Config": "app.sqlinstance policy.database.autoclose ", "Description": "Tests the auto-close setting", "Describe": "Auto Close" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "AutoShrink", "AllTags": "AutoShrink, Database", "Config": "app.sqlinstance policy.database.autoshrink ", "Description": "Tests the Auto Shrink setting", "Describe": "Auto Shrink" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "LastFullBackup", "AllTags": "LastFullBackup, LastBackup, Backup, DISA, Database", "Config": "app.sqlinstance policy.backup.fullmaxdays policy.backup.newdbgraceperiod skip.backup.readonly ", "Description": "Tests if the last full backup of a database is less than the specified number of days (default 7) except for offline databases and read-only databases (read-only if specified) and databases created recently (if specified)", "Describe": "Last Full Backup Times" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "LastDiffBackup", "AllTags": "LastDiffBackup, LastBackup, Backup, DISA, Database", "Config": "app.sqlinstance skip.diffbackuptest policy.backup.diffmaxhours policy.backup.newdbgraceperiod skip.backup.readonly ", "Description": "Tests if the last diff backup of a database is less than the specified number of hours (default 24) except for offline databases and read-only databases (read-only if specified) and databases created recently (if specified)", "Describe": "Last Diff Backup Times" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "LastLogBackup", "AllTags": "LastLogBackup, LastBackup, Backup, DISA, Database", "Config": "app.sqlinstance policy.backup.logmaxminutes policy.backup.newdbgraceperiod skip.backup.readonly ", "Description": "Tests if the last log backup of a database is less than the specified number of minutes (default 30) except for simple databases, offline databases and read-only databases (read-only if specified) and databases created recently (if specified)", "Describe": "Last Log Backup Times" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "VirtualLogFile", "AllTags": "VirtualLogFile, Database", "Config": "app.sqlinstance policy.database.maxvlf ", "Description": "Tests the number of the Virtual Log Files are less than the specified number", "Describe": "Virtual Log Files" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "LogfileCount", "AllTags": "LogfileCount, Database", "Config": "app.sqlinstance skip.database.logfilecounttest policy.database.logfilecount ", "Description": "Tests that the number of log files are less than the specified amount (default is 1) in all databases except those specified to be skipped by default", "Describe": "Log File Count Checks" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "LogfileSize", "AllTags": "LogfileSize, Database", "Config": "app.sqlinstance policy.database.logfilesizepercentage policy.database.logfilesizecomparison ", "Description": "Tests that the database log files are less than the specified percentage of the specified comparison (maximum size or average - default is average) of the data file size (default 100)", "Describe": "Log File Size Checks" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "FutureFileGrowth", "AllTags": "FutureFileGrowth, Database", "Config": "app.sqlinstance policy.database.filegrowthfreespacethreshold policy.database.filegrowthexcludedb skip.database.filegrowthdisabled ", "Description": "Tests if a database (except for those specified to be skipped explicitly) has free space less than the specified percentage (default 20)", "Describe": "Future File Growth" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "FileGroupBalanced", "AllTags": "FileGroupBalanced, Database", "Config": "app.sqlinstance policy.database.filebalancetolerance ", "Description": "Tests that all of the files within each filegroup are sized within the specified percentage (default 5) of the average", "Describe": "Correctly sized Filegroup members" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "CertificateExpiration", "AllTags": "CertificateExpiration, Database", "Config": "app.sqlinstance policy.certificateexpiration.warningwindow policy.certificateexpiration.excludedb ", "Description": "Tests that all certificates have not expired and are not due to expire within the specified (default 1) number of months", "Describe": "Certificate Expiration" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "AutoCreateStatistics", "AllTags": "AutoCreateStatistics, Database", "Config": "app.sqlinstance policy.database.autocreatestatistics ", "Description": "Tests the Auto Create Statistics property on each database is set to the specified (default false) value", "Describe": "Auto Create Statistics" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "AutoUpdateStatistics", "AllTags": "AutoUpdateStatistics, Database", "Config": "app.sqlinstance policy.database.autoupdatestatistics ", "Description": "Tests the Auto Update Statistics property on each database is set to the specified (default true) value", "Describe": "Auto Update Statistics" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "AutoUpdateStatisticsAsynchronously", "AllTags": "AutoUpdateStatisticsAsynchronously, Database", "Config": "app.sqlinstance policy.database.autoupdatestatisticsasynchronously ", "Description": "Tests the Auto Update Statistics Asynchronously property on each database is set to the specified (default false) value", "Describe": "Auto Update Statistics Asynchronously" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "DatafileAutoGrowthType", "AllTags": "DatafileAutoGrowthType, Database", "Config": "app.sqlinstance policy.database.filegrowthtype policy.database.filegrowthvalue policy.database.filegrowthexcludedb skip.database.filegrowthdisabled ", "Description": "Tests that the Datafile Auto Growth type and value on each database except those specified is set to the specified (default type = kb, value = 65535) values", "Describe": "Datafile Auto Growth Configuration" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "Trustworthy", "AllTags": "Trustworthy, DISA, Database", "Config": "app.sqlinstance ", "Description": "Tests that the Trustworthy Option for each database is set to false", "Describe": "Trustworthy Option" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "OrphanedUser", "AllTags": "OrphanedUser, Database", "Config": "app.sqlinstance ", "Description": "Tests that each database has 0 orphaned users", "Describe": "Database Orphaned User" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "PseudoSimple", "AllTags": "PseudoSimple, Database", "Config": "app.sqlinstance ", "Description": "Tests that databases are not in PseudoSimple Recovery Model", "Describe": "PseudoSimple Recovery Model" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "CompatibilityLevel", "AllTags": "CompatibilityLevel, Database", "Config": "app.sqlinstance ", "Description": "tests that the servers compatibility level matches the compatibility level", "Describe": "Compatibility Level" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "FKCKTrusted", "AllTags": "FKCKTrusted, Database", "Config": "app.sqlinstance ", "Description": "Tests that each foreign key and each constraint is trusted", "Describe": "Foreign keys and check constraints not trusted" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "MaxDopDatabase", "AllTags": "MaxDopDatabase, MaxDop, Database", "Config": "app.sqlinstance policy.database.maxdop policy.database.maxdopexcludedb ", "Description": "Tests that the database level MaxDop settings for all databases on all instances from version 2016 up are set to the specified value (default 0)", "Describe": "Database MaxDop" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "DatabaseStatus", "AllTags": "DatabaseStatus, Database", "Config": "app.sqlinstance command.invokedbccheck.excludedatabases policy.database.status.excludereadonly policy.database.status.excludeoffline policy.database.status.excluderestoring ", "Description": "Tests that there are no databases on an instance that are in a state of AutoClose, Offline, ReadOnly, Restoring, Recovery, Recovery Pending, EmergencyMode, Suspect or StandBy. Databases that are in ReadOnly,Offline and Restoring mode can be specified (default none)", "Describe": "Database Status" }, { "Group": "Database", "Type": "Sqlinstance", "UniqueTag": "DatabaseExists", "AllTags": "DatabaseExists, Database", "Config": "app.sqlinstance database.exists ", "Description": "Tests that the databases are specified are on the instance (Note - Does not check if they are available - Use DatabaseStatus for that))", "Describe": "Database Exists" }, { "Group": "Domain", "Type": "ComputerName", "UniqueTag": "DomainName", "AllTags": "DomainName, Domain", "Config": "app.computername domain.name ", "Description": "Uses WMI Win32_ComputerSystem to check that the host machine is on the correct domain", "Describe": "Active Directory Domain Name" }, { "Group": "Domain", "Type": "ComputerName", "UniqueTag": "OrganizationalUnit", "AllTags": "OrganizationalUnit, Domain", "Config": "app.computername domain.domaincontroller domain.organizationalunit ", "Description": "Currently skipped - Active Directory OU", "Describe": "Active Directory OU" }, { "Group": "HADR", "Type": "ClusterNode", "UniqueTag": "ClusterHealth", "AllTags": "ClusterHealth, HADR", "Config": "app.cluster skip.hadr.listener.pingcheck domain.name policy.hadr.tcpport ", "Description": "Runs a suite of tests against an Availability Group on a Windows cluster to ensure that everything is as it should be. Tests cluster resources are online, cluster nodes are up, at least one IP Address for the AG listener is available, that each replica and listener are pingable (listener ping check can be skipped), can be connected to via T-SQL, have the correct domain name and TCP port, that each replica is synchronised/ing, is connected, is not in an unknown state, each database is synchronised/ing, failover ready and joined to the domain and that the Always On Health Extended Event sessions are running and set to auto-start", "Describe": "Cluster $clustername Health using Node $clustervm" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "SqlEngineServiceAccount", "AllTags": "SqlEngineServiceAccount, ServiceAccount, Instance", "Config": "app.sqlinstance ", "Description": "Tests that the SQL Engine Service is started and set to auto-start", "Describe": "SQL Engine Service" }, { "Group": "Instance", "Type": "ComputerName", "UniqueTag": "SqlBrowserServiceAccount", "AllTags": "SqlBrowserServiceAccount, ServiceAccount, Instance", "Config": "app.computername ", "Description": "Tests that the SQL Browser Service is started and set to auto-start if there are multiple instances and stopped and set to disabled if there is only one ", "Describe": "SQL Browser Service" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "TempDbConfiguration", "AllTags": "TempDbConfiguration, Instance", "Config": "app.sqlinstance skip.TempDb1118 skip.tempdbfileCount skip.TempDbFileGrowthPercent skip.TempDbFilesonC skip.TempDbFileSizeMax ", "Description": "Tests that the TempDB Configuration is correct, that TF118 is enabled, there are the recommended number of files, autogrowth is not set to percent, that the files can grow and that they are not located on the C drive (each of these tests can be configured individually to be skipped", "Describe": "TempDB Configuration" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "AdHocWorkload", "AllTags": "AdHocWorkload, Instance", "Config": "app.sqlinstance ", "Description": "Tests that the AAd Hoc Workload Optimization is enabled", "Describe": "Ad Hoc Workload Optimization" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "BackupPathAccess", "AllTags": "BackupPathAccess, Storage, DISA, Instance", "Config": "app.sqlinstance policy.storage.backuppath ", "Description": "Tests that the SQL Service account has access to the default backup path or the specified folder path", "Describe": "Backup Path Access" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "DAC", "AllTags": "DAC, Instance", "Config": "app.sqlinstance policy.dacallowed ", "Description": "Tests that the Dedicated Administrator Connection configuration setting matches the specified value (default true)", "Describe": "Dedicated Administrator Connection" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "NetworkLatency", "AllTags": "NetworkLatency, Connectivity, Instance", "Config": "app.sqlinstance policy.network.latencymaxms ", "Description": "Tests that the Network Latency is less than the specified (default 40) ms", "Describe": "Network Latency" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "LinkedServerConnection", "AllTags": "LinkedServerConnection, Connectivity, Instance", "Config": "app.sqlinstance ", "Description": "Tests for successful connection to all Linked Servers", "Describe": "Linked Servers" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "MaxMemory", "AllTags": "MaxMemory, Instance", "Config": "app.sqlinstance ", "Description": "Tests an instances Max Memory", "Describe": "Max Memory" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "OrphanedFile", "AllTags": "OrphanedFile, Instance", "Config": "app.sqlinstance ", "Description": "Tests that there are 0 orphaned data files", "Describe": "Orphaned Files" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "ServerNameMatch", "AllTags": "ServerNameMatch, Instance", "Config": "app.sqlinstance ", "Description": "Tests that the SQL + Windows names match", "Describe": "SQL + Windows names match" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "MemoryDump", "AllTags": "MemoryDump, Instance", "Config": "app.sqlinstance policy.dump.maxcount ", "Description": "Tests that there are less than the specified (default 1) number of SQL Memory Dumps", "Describe": "SQL Memory Dumps" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "SupportedBuild", "AllTags": "SupportedBuild, DISA, Instance", "Config": "app.sqlinstance policy.build.warningwindow ", "Description": "Tests that the instance is still under Microsoft support and that it will still be under support in a specified (default 6) months", "Describe": "Supported Build" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "SaRenamed", "AllTags": "SaRenamed, DISA, Instance", "Config": "app.sqlinstance ", "Description": "Tests that the SA Login has been renamed", "Describe": "SA Login Renamed" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "DefaultBackupCompression", "AllTags": "DefaultBackupCompression, Instance", "Config": "app.sqlinstance policy.backup.defaultbackupcompression ", "Description": "Tests that an instances Default Backup Compression is set to the specified (default true) setting", "Describe": "Default Backup Compression" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "XESessionStopped", "AllTags": "XESessionStopped, ExtendedEvent, Instance", "Config": "app.sqlinstance policy.xevent.requiredstoppedsession ", "Description": "Tests that the specified (default blank) XE Sessions are stopped", "Describe": "XE Sessions That should be Stopped" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "XESessionRunning", "AllTags": "XESessionRunning, ExtendedEvent, Instance", "Config": "app.sqlinstance policy.xevent.requiredrunningsession ", "Description": "Tests that the specified (default blank) XE Sessions that are expected to be running are running", "Describe": "XE Sessions That should be Running" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "XESessionRunningAllowed", "AllTags": "XESessionRunningAllowed, ExtendedEvent, Instance", "Config": "app.sqlinstance policy.xevent.validrunningsession ", "Description": "Tests that the specified (default blank) XE Sessions that are allowed to be running are running", "Describe": "XE Sessions That Are Allowed to Be Running" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "OLEAutomation", "AllTags": "OLEAutomation, Instance", "Config": "app.sqlinstance policy.oleautomation ", "Description": "Tests that OLE Automation is set to the specified (default false) setting", "Describe": "OLE Automation" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "WhoIsActiveInstalled", "AllTags": "WhoIsActiveInstalled, Instance", "Config": "app.sqlinstance policy.whoisactive.database ", "Description": "Tests that sp_whoisactive is Installed by testing the specified (default master) database for the stored procedure", "Describe": "sp_whoisactive is Installed" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "ModelDbGrowth", "AllTags": "ModelDbGrowth, Instance", "Config": "app.sqlinstance skip.instance.modeldbgrowth ", "Description": "Tests that the Model Database Growth settings are not set to default", "Describe": "Model Database Growth" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "ADUser", "AllTags": "ADUser, Domain, Instance", "Config": "app.sqlinstance policy.adloginuser.excludecheck policy.adlogingroup.excludecheck ", "Description": "Tests that Ad Users and Groups, except those specified, that are logins on a SQL Server exist in Active Directory, do not have an expired password, are not locked out, are enabled in AD and on the SQL Server ", "Describe": "Ad Users and Groups " }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "ErrorLog", "AllTags": "ErrorLog, Instance", "Config": "app.sqlinstance policy.errorlog.warningwindow ", "Description": "Tests that the SQL Server Error Log does not have any Severity 17-24 level entries within the specified (default 2) days", "Describe": "Error Log Entries" }, { "Group": "Instance", "Type": "Sqlinstance", "UniqueTag": "MaxDopInstance", "AllTags": "MaxDopInstance, MaxDop, Instance", "Config": "app.sqlinstance policy.instancemaxdop.userecommended policy.instancemaxdop.maxdop policy.instancemaxdop.excludeinstance ", "Description": "Tests that the instance level MaxDop settings on all instances (except those specified default blank) are set to the recommended value if specified (default false) or to the specified value (default 0)", "Describe": "Instance MaxDop" }, { "Group": "LogShipping", "Type": "Sqlinstance", "UniqueTag": "LogShippingPrimary", "AllTags": "LogShippingPrimary, LogShipping", "Config": "app.sqlinstance ", "Description": "Tests that the Log Shipping Primary status is ok", "Describe": "Log Shipping Status Primary" }, { "Group": "LogShipping", "Type": "Sqlinstance", "UniqueTag": "LogShippingSecondary", "AllTags": "LogShippingSecondary, LogShipping", "Config": "app.sqlinstance ", "Description": "Tests that the Log Shipping Secondary status is ok", "Describe": "Log Shipping Status Secondary" }, { "Group": "MaintenanceSolution", "Type": "Sqlinstance", "UniqueTag": "OlaInstalled", "AllTags": "OlaInstalled, MaintenanceSolution", "Config": "app.sqlinstance policy.ola.database ", "Description": "Tests that Ola maintenance solution is installed by testing the specified (default master) database for the command log table and the stored procedures", "Describe": "Ola maintenance solution installed" }, { "Group": "MaintenanceSolution", "Type": "Sqlinstance", "UniqueTag": "SystemFull", "AllTags": "SystemFull, OlaJobs, MaintenanceSolution", "Config": "app.sqlinstance ola.JobName.SystemFull policy.ola.SystemFullenabled policy.ola.SystemFullscheduled policy.ola.SystemFullretention ", "Description": "Tests that the Ola - System Full Agent Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled and that the backup retention setting for the job is set as specified (default 192 (hours))", "Describe": "Ola - $SysFullJobName" }, { "Group": "MaintenanceSolution", "Type": "Sqlinstance", "UniqueTag": "UserFull", "AllTags": "UserFull, OlaJobs, MaintenanceSolution", "Config": "app.sqlinstance ola.JobName.UserFull policy.ola.UserFullenabled policy.ola.UserFullscheduled policy.ola.UserFullretention ", "Description": "Tests that the Ola - User Full Agent Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled and that the backup retention setting for the job is set as specified (default 192 (hours))", "Describe": "Ola - $UserFullJobName" }, { "Group": "MaintenanceSolution", "Type": "Sqlinstance", "UniqueTag": "UserDiff", "AllTags": "UserDiff, OlaJobs, MaintenanceSolution", "Config": "app.sqlinstance ola.JobName.UserDiff policy.ola.UserDiffenabled policy.ola.UserDiffscheduled policy.ola.UserDiffretention ", "Description": "Tests that the Ola - User Diff Agent Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled and that the backup retention setting for the job is set as specified (default 192 (hours))", "Describe": "Ola - $UserDiffJobName" }, { "Group": "MaintenanceSolution", "Type": "Sqlinstance", "UniqueTag": "UserLog", "AllTags": "UserLog, OlaJobs, MaintenanceSolution", "Config": "app.sqlinstance ola.JobName.UserLog policy.ola.UserLogenabled policy.ola.UserLogscheduled policy.ola.UserLogretention ", "Description": "Tests that the Ola - User Log Agent Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled and that the backup retention setting for the job is set as specified (default 192 (hours))", "Describe": "Ola - $UserLogJobName" }, { "Group": "MaintenanceSolution", "Type": "Sqlinstance", "UniqueTag": "CommandLog", "AllTags": "CommandLog, OlaJobs, MaintenanceSolution", "Config": "app.sqlinstance ola.JobName.CommandLogCleanup policy.ola.CommandLogenabled policy.ola.CommandLogscheduled policy.ola.CommandLogCleanUp ", "Description": "Tests that the Ola - Command Log Cleanup Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled and that the clean up setting for the job is set as specified (default 30 (days))", "Describe": "Ola - $CommandLogJobName" }, { "Group": "MaintenanceSolution", "Type": "Sqlinstance", "UniqueTag": "SystemIntegrityCheck", "AllTags": "SystemIntegrityCheck, OlaJobs, MaintenanceSolution", "Config": "app.sqlinstance ola.JobName.SystemIntegrity policy.ola.SystemIntegrityCheckenabled policy.ola.SystemIntegrityCheckscheduled ", "Description": "Tests that the Ola - System Integrity Check Agent Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled", "Describe": "Ola - $SysIntegrityJobName" }, { "Group": "MaintenanceSolution", "Type": "Sqlinstance", "UniqueTag": "UserIntegrityCheck", "AllTags": "UserIntegrityCheck, OlaJobs, MaintenanceSolution", "Config": "app.sqlinstance ola.JobName.UserIntegrity policy.ola.UserIntegrityCheckenabled policy.ola.UserIntegrityCheckscheduled ", "Description": "Tests that the Ola - User Integrity Check Agent Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled", "Describe": "Ola - $UserIntegrityJobName" }, { "Group": "MaintenanceSolution", "Type": "Sqlinstance", "UniqueTag": "UserIndexOptimize", "AllTags": "UserIndexOptimize, OlaJobs, MaintenanceSolution", "Config": "app.sqlinstance ola.JobName.UserIndex policy.ola.UserIndexOptimizeenabled policy.ola.UserIndexOptimizescheduled ", "Description": "Tests that the Ola - User Index Optimise Agent Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled", "Describe": "Ola - $UserIndexJobName" }, { "Group": "MaintenanceSolution", "Type": "Sqlinstance", "UniqueTag": "OutputFileCleanup", "AllTags": "OutputFileCleanup, OlaJobs, MaintenanceSolution", "Config": "app.sqlinstance ola.JobName.OutputFileCleanup policy.ola.OutputFileCleanupenabled policy.ola.OutputFileCleanupscheduled policy.ola.OutputFileCleanUp ", "Description": "Tests that the Ola - Output File Cleanup Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled and that the clean up setting for the job is set as specified (default 30 (days))", "Describe": "Ola - $OutputFileJobName" }, { "Group": "MaintenanceSolution", "Type": "Sqlinstance", "UniqueTag": "DeleteBackupHistory", "AllTags": "DeleteBackupHistory, OlaJobs, MaintenanceSolution", "Config": "app.sqlinstance ola.JobName.DeleteBackupHistory policy.ola.DeleteBackupHistoryenabled policy.ola.DeleteBackupHistoryscheduled policy.ola.DeleteBackupHistoryCleanUp ", "Description": "Tests that the Ola - Delete Backup History Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled and that the clean up setting for the job is set as specified (default 30 (days))", "Describe": "Ola - $DeleteBackupJobName" }, { "Group": "MaintenanceSolution", "Type": "Sqlinstance", "UniqueTag": "PurgeJobHistory", "AllTags": "PurgeJobHistory, OlaJobs, MaintenanceSolution", "Config": "app.sqlinstance ola.JobName.PurgeBackupHistory policy.ola.PurgeJobHistoryenabled policy.ola.PurgeJobHistoryscheduled policy.ola.PurgeJobHistoryCleanUp ", "Description": "Tests that the Ola - Purge Job History Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled and that the clean up setting for the job is set as specified (default 30 (days))", "Describe": "Ola - $PurgeBackupJobName" }, { "Group": "Server", "Type": "ComputerName", "UniqueTag": "PowerPlan", "AllTags": "PowerPlan, Server", "Config": "app.computername ", "Description": "Tests that the Server Power Plan is set to High Performance", "Describe": "Server Power Plan Configuration" }, { "Group": "Server", "Type": "Sqlinstance", "UniqueTag": "InstanceConnection", "AllTags": "InstanceConnection, Connectivity, Server", "Config": "app.sqlinstance skip.connection.remoting skip.connection.ping policy.connection.authscheme ", "Description": "Tests that a SQL query can be run, that the specified authentication scheme (default kerboros) is being used, that the host responds to one ping and that the host supports PS Remoting", "Describe": "Instance Connection" }, { "Group": "Server", "Type": "ComputerName", "UniqueTag": "SPN", "AllTags": "SPN, Server", "Config": "app.computername ", "Description": "Tests that all default SQL SPNs have been correctly registered", "Describe": "SPNs" }, { "Group": "Server", "Type": "ComputerName", "UniqueTag": "DiskCapacity", "AllTags": "DiskCapacity, Storage, DISA, Server", "Config": "app.computername policy.diskspace.percentfree ", "Description": "Tests that each drive has at least the specified percentage (default 20) free space", "Describe": "Disk Space" }, { "Group": "Server", "Type": "ComputerName", "UniqueTag": "PingComputer", "AllTags": "PingComputer, Server", "Config": "app.computername policy.connection.pingmaxms policy.connection.pingcount skip.connection.ping ", "Description": "Tests that a host has been pinged a specified number of times (default 3) and that the average response time is less than specified (default 10ms)", "Describe": "Ping Computer" }, { "Group": "Server", "Type": "ComputerName", "UniqueTag": "CPUPrioritisation", "AllTags": "CPUPrioritisation, Server", "Config": "app.computername policy.server.cpuprioritisation ", "Description": "Tests that the CPU is prioritised for background activity over user UI experience. unless specified to ignore (default true)", "Describe": "CPUPrioritisation" }, { "Group": "Server", "Type": "ComputerName", "UniqueTag": "DiskAllocationUnit", "AllTags": "DiskAllocationUnit, Server", "Config": "app.computername ", "Description": "Tests that the disks available to the server are formatted for optimum performance (64KB allocation unit)", "Describe": "Disk Allocation Unit" } ] ================================================ FILE: developing/Archive/tests/functions/results.json ================================================ { "TagFilter": [ "AutoClose", "lastgoodcheckdb", "BackupPathAccess", "FailedJob" ], "ExcludeTagFilter": [ "FailsafeOperator", "DatabaseMailEnabled", "DatabaseMailProfile", "SqlEngineServiceAccount", "OrphanedFile", "ServerNameMatch", "SqlBrowserServiceAccount" ], "TestNameFilter": null, "ScriptBlockFilter": null, "TotalCount": 20, "PassedCount": 14, "FailedCount": 6, "SkippedCount": 0, "PendingCount": 0, "InconclusiveCount": 0, "Time": { "Ticks": 47923307, "Days": 0, "Hours": 0, "Milliseconds": 792, "Minutes": 0, "Seconds": 4, "TotalDays": 5.5466790509259256E-05, "TotalHours": 0.0013312029722222221, "TotalMilliseconds": 4792.3307, "TotalMinutes": 0.079872178333333335, "TotalSeconds": 4.7923307 }, "TestResult": [ { "FailureMessage": "Expected the actual value to be greater than 2019-12-21T15:21:38.3892727Z, because You should have run a DBCC CheckDB inside that time, but got 2019-12-21T14:41:58.0230000.", "Result": "Failed", "Describe": "Last Good DBCC CHECKDB", "Time": "00:00:00.0056746", "Show": 1023, "StackTrace": "at , D:\\OneDrive\\Documents\\GitHub\\dbachecks\\checks\\Database.Tests.ps1: line 200\r\n200: $psitem.LastGoodCheckDb | Should -BeGreaterThan (Get-Date).ToUniversalTime().AddDays( - ($maxdays)) -Because \"You should have run a DBCC CheckDB inside that time\"", "Passed": false, "Parameters": "System.Collections.Specialized.OrderedDictionary", "Context": "Testing Last Good DBCC CHECKDB on localhost,15592", "Name": "Database master last good integrity check should be less than 3 days old on a37085985dc6", "ErrorRecord": "Expected the actual value to be greater than 2019-12-21T15:21:38.3892727Z, because You should have run a DBCC CheckDB inside that time, but got 2019-12-21T14:41:58.0230000.", "ParameterizedSuiteName": "" }, { "FailureMessage": "", "Result": "Passed", "Describe": "Last Good DBCC CHECKDB", "Time": "00:00:00.0032216", "Show": 1023, "StackTrace": "", "Passed": true, "Parameters": "System.Collections.Specialized.OrderedDictionary", "Context": "Testing Last Good DBCC CHECKDB on localhost,15592", "Name": "Database master has Data Purity Enabled on a37085985dc6", "ErrorRecord": null, "ParameterizedSuiteName": "" } ] } ================================================ FILE: developing/Archive/tests/readme.md ================================================ # Tests Folder ## Description This folder holds the Unit and integration tests for the dbachecks module ## assertions This holds the functions to be able to run the unit tests for the checks ## checks This holds the Pester Tests for the checks ## functions This holds the Pester Tests for the external adn internal functions ## This folder holds the generic tests for the module, the help, the script analyzer, the generic unit tests for the checks layout ================================================ FILE: developing/Howto.md ================================================ # Developing with Sampler set up Super quick introduction. I have altered the project to use Sampler by Gael to scaffold and later to improve the CI/CD pipeline. I have also updated the devcontainer so that we have 3 containers 2 based on dbatools/sqlinstance and dbatools/sqlinstance2 but also a SQL2022 container with the sqlinstance objects copied into it. The default container also has GitVersion and Sampler installed as well as few other bits to make thigns easier and to save having to do the build everytime (as installing gitversion was a PITA and lengthy) The containers are all now hosted in the dbachecks docker hub account. What does this mean? It means that as well as using a dev container to develop in, thus ensuring that everyone is using the same environment, we will also be using the Sampler build and test process to ensure that we are __always__ using a clean build of the code we are writing and testing. :-) So to develop you need to understand the following: The code in the source directory is the code that will be built and deployed to the PowerShell Gallery. This is the directory that you will be changing the code in. NOTE - You will get really frustrated if you alter the code in the output directory and then build it again and find it doesnt work and the code all vanished. ASK ME HOW I KNOW !!! The code in the output directory is the code that is built by Sampler. It is in the gitignore file so that it is not committed to the repo. This is the code that you can test with the 3 SQL instances. The advantage is that the Sampler build process will create a clean environment and add the built module into the PSModulePath. # Workflow ## Once in a session - Run `.\build.ps1 -ResolveDependency -Tasks noop` to download all required dependencies and set up the environment. ## Coding - Code in the source directory - Save the files - Run the build.ps1 script - with Tasks build `./build.ps1 -Tasks build` - This will build the code and copy it to the output directory. image image image Once you have finished doing some coding and want to test - With Tasks build test `./build.ps1 -Tasks build,test` - This will build the code and run the Pester Tests. image - if you have failed tests, you can - Run Pester manually `Invoke-Pester tests` image - You can check the test results in the browser by creating a html page `.\tests\extent.exe -i .\output\testResults\NUnitXml_dbachecks_v2.0.18.Linux.PSv.7.3.0.xml -o .\output\testResults\reports -r v3html` and then __outside of the container__ `ii .\output\testResults\reports\index.html # outside of container` image - Fix the broken tests or add more code and rinse and repeat. ================================================ FILE: developing/Oslo Demo.ps1 ================================================ # Oslo Demo ./build.ps1 -tasks build #region setup $containers = $SQLInstances = $dbachecks1, $dbachecks2, $dbachecks3 = 'dbachecks1', 'dbachecks2', 'dbachecks3' $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $show = 'All' $PSDefaultParameterValues = @{ "*:SQlInstance" = $SQLInstances "*:SqlCredential" = $cred } #endregion #region What do we have? Get-DbaDatabase | Select-Object Sqlinstance, Name, Status Get-DbaAgentJob | Select-Object Sqlinstance, Name, Enabled #end region Get-DbaLastBackup | Select-Object Sqlinstance, Database, LastFullBackup | Format-Table # lets run a couple of tests # this one shows that the old existing code will work # the legacy switch is set to true by default Invoke-DbcCheck -Check InstanceConnection, DatabaseStatus -Show $show # So lets show the shiny new faster code - legacy switch set to false Invoke-DbcCheck -Check InstanceConnection, DatabaseStatus -Show $show -legacy $false # The Authentication check failed but we would like to pass - lets set config Set-DbcConfig -Name policy.connection.authscheme -Value SQL # run again Invoke-DbcCheck -Check InstanceConnection, DatabaseStatus -Show $show -legacy $false # Hmmm, we know that we will never be able to remote onto these containers so let talk about skipping. No Claudio not that sort of skipping!! Set-DbcConfig -Name skip.connection.remoting -Value $true # run again Invoke-DbcCheck -Check InstanceConnection, DatabaseStatus -Show $show -legacy $false # So much quicker !!! OK for one check it will be slower. For two it will probably be about the same but for 3 or more it will be quicker. Much quicket. Exrapolate that to 100 checks and a 1000 instances you can see the difference. # This is how we know - We perf test our PowerShell code # This will take about 80-100 seconds to run so run first then talk! $Checks = 'ErrorLogCount', 'XpCmdShellDisabled', 'WhoIsActiveInstalled', 'CLREnabled', 'TwoDigitYearCutoff', 'MaxDopInstance', 'ErrorLogCount', 'ModelDbGrowth', 'DefaultBackupCompression', 'SaExist', 'SaDisabled', 'SaRenamed', 'DefaultFilePath', 'AdHocDistributedQueriesEnabled', 'AdHocWorkload', 'DefaultTrace', 'OleAutomationProceduresDisabled', 'CrossDBOwnershipChaining', 'ScanForStartupProceduresDisabled', 'RemoteAccessDisabled', 'SQLMailXPsDisabled', 'DAC', 'OLEAutomation', 'ServerNameMatch', 'OrphanedFile', 'MaxMemory', 'PublicPermission' Invoke-PerfAndValidateCheck -Checks $Checks # I want to use the results in a different way # ok lets run the checks and save the out put to a variable so that we can show you what happens. Notice we need the -PassThru switch $CheckResults = Invoke-DbcCheck -Check InstanceConnection, DatabaseStatus -Show $show -legacy $false -PassThru # this is our base results object $CheckResults # lets convert it to something useful $SomethingUseful = $CheckResults | Convert-DbcResult $SomethingUseful $SomethingUseful | Format-Table #TODO: fix this Checking Instance Connection on on dbachecks3 $SomethingUseful | Select-Object -First 1 # Label huh - what is that? # label these results so that they can be filtered later $Coffee = $CheckResults | Convert-DbcResult -Label 'CoffeeFilter' $Coffee | Select-Object -First 1 # Now we can set those to a file if we want $CheckResults | Convert-DbcResult -Label 'CoffeeFilter' | Set-DbcFile -FileType Json -FilePath . -FileName oslo -Verbose $CheckResults | Convert-DbcResult -Label 'Whiskey' | Set-DbcFile -FileType Json -FilePath . -FileName oslo -Append code ./oslo.json # or put them into a database table $CheckResults | Convert-DbcResult -Label 'claudiodidthis' | Write-DbcTable -SqlInstance dbachecks1 -SqlCredential $cred -Database tempdb Invoke-DbaQuery -SqlInstance dbachecks1 -SqlCredential $cred -Database tempdb -Query 'SELECT COUNT(*) FROM CheckResults' # AUDIENCE AND OTHER PRESENTERS - WE NEED REMINDERS HERE !!! # YOU CANT DO THIS FROM HERE - Open Windows terminal on the host and run Start-DbcPowerBi -FromDatabase # AUDIENCE AND OTHER PRESENTERS - WE NEED REMINDERS HERE !!! # then use localhost,7401 tempdb and u:sqladmin p:dbatools.IO # question turn off a container and talk about the fails? ## made some funky results for the Power Bi $CheckResults = Invoke-DbcCheck -Check Instance, Database -Show $show -legacy $false -PassThru $CheckResults | Convert-DbcResult -Label 'DatabaseInstance' | Write-DbcTable -SqlInstance dbachecks1 -SqlCredential $cred -Database tempdb -Verbose $CheckResults = Invoke-DbcCheck -Check compatibilitylevel -Show $show -legacy $false -PassThru ================================================ FILE: developing/PSConfEU demo.md ================================================ # PSConfEU demo 1. Develop in the source repository - copy existing check & rewrite - add check to `source/checks/Databasev5.Tests.ps1` - add configuration to `source/internal/configurations/configuration.ps1` - `skip.database.pseudosimple` - `policy.database.pseudosimpleexcludedb` - add object info to `source/internal/functions/Get-AllDatabaseInfo.ps1` 2. Build the module ```PowerShell ./build.ps1 -Tasks build ``` 3. Sampler automatically adds the new version to your path ```PowerShell get-module dbachecks -ListAvailable | select name, modulebase ``` 4. Import new version of the module (if you get a bogus error the first time retry it) ```PowerShell Import-Module dbachecks -force ``` 5. Test out the new code ```PowerShell # save the password to make for easy connections $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $show = 'All' $checks = 'RecoveryModel' #$sqlinstances = 'localhost,7401', 'localhost,7402', 'localhost,7403' $sqlinstances = 'dbachecks1', 'dbachecks2', 'dbachecks3' # need client aliases for this to work New-DbaClientAlias # Run v4 checks $v4code = Invoke-DbcCheck -SqlInstance $Sqlinstances -SqlCredential $cred -Check $Checks -legacy $true -Show $show -PassThru # Run v5 checks $v5code = Invoke-DbcCheck -SqlInstance $Sqlinstances -SqlCredential $cred -Check $Checks -legacy $false -Show $show -PassThru -Verbose Invoke-PerfAndValidateCheck -SQLInstances $sqlinstances -Checks $Checks Invoke-PerfAndValidateCheck -SQLInstances $sqlinstances -Checks $Checks -PerfDetail Invoke-PerfAndValidateCheck -SQLInstances $sqlinstances -Checks $Checks -showTestResults ``` ================================================ FILE: developing/Robs-Instance.ps1 ================================================ ./build.ps1 -Tasks build $Checks = 'ErrorLogCount', 'XESessionExists', 'XESessionStopped', 'XpCmdShellDisabled', 'WhoIsActiveInstalled', 'CLREnabled', 'TwoDigitYearCutoff', 'MaxDopInstance', 'ErrorLogCount', 'ModelDbGrowth', 'DefaultBackupCompression', 'SaExist', 'SaDisabled', 'SaRenamed', 'DefaultFilePath', 'AdHocDistributedQueriesEnabled', 'AdHocWorkload', 'DefaultTrace', 'OleAutomationProceduresDisabled', 'CrossDBOwnershipChaining', 'ScanForStartupProceduresDisabled', 'RemoteAccessDisabled', 'SQLMailXPsDisabled', 'DAC', 'OLEAutomation', 'ServerNameMatch', 'OrphanedFile', 'MaxMemory', 'NetworkLatency', 'PublicPermission' $Checks = 'XESessionRunningAllowed', 'XESessionRunning', 'XESessionRunningAllowed', 'XESessionExists', 'XESessionStopped', 'XpCmdShellDisabled' $Checks = 'TraceFlagsNotExpected', 'TraceFlagsExpected' $Checks = 'ServerNameMatch' $Checks = 'BackupPathAccess' $Checks = 'LatestBuild' $Checks = 'NetworkLatency' $Checks = 'LinkedServerConnection' $Checks = 'MaxMemory' $Checks = 'OrphanedFile' $Checks = 'MemoryDump' $Checks = 'HideInstance' $Checks = 'LoginAuditFailed' $Checks = 'LoginAuditSuccessful' $Checks = 'LoginCheckPolicy' $Checks = 'SuspectPageLimit' $Checks = 'SupportedBuild' $Checks = 'LoginMustChange' $Checks = 'LoginAuditSuccessful', 'LoginAuditFailed' Set-DbcConfig -Name skip.security.PublicPermission -Value $false $Checks = 'PublicRolePermission' $Checks = 'PUblicPermission' $Checks = 'Database' $Checks = 'AgentServiceAccount', 'DbaOperator', 'DatabaseMailProfile', 'AgentMailProfile' $DatabaseTags = (Get-DbcCheck -Group Database).UniqueTag $Checks = $DatabaseTags[1..5] Invoke-PerfAndValidateCheck -Checks $Checks Invoke-PerfAndValidateCheck -Checks $Checks -PerfDetail $containers = $SQLInstances = $dbachecks1, $dbachecks2, $dbachecks3 = 'dbachecks1', 'dbachecks2', 'dbachecks3' $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $show = 'All' $v4code = Invoke-DbcCheck -SqlInstance $Sqlinstances -SqlCredential $cred -Check $Checks -legacy $true -Show $show -PassThru -verbose # Run v5 checks $v5code = Invoke-DbcCheck -SqlInstance $Sqlinstances -SqlCredential $cred -Check $Checks -legacy $false -Show $show -PassThru -Verbose Set-DbcConfig -Name policy.xevent.requiredrunningsession -Value system_health Set-DbcConfig -Name policy.xevent.requiredrunningsession -Value system_health , AlwaysOn_health Set-DbcConfig -Name policy.xevent.requiredrunningsession -Value system_health , AlwaysOn_health, QuickSessionStandard Set-DbcConfig -Name policy.xevent.validrunningsession -Value system_health , AlwaysOn_health Set-DbcConfig -Name policy.xevent.validrunningsession -Value AlwaysOn_health $SQLInstances = $dbachecks1, $dbachecks2, $dbachecks3 = 'dbachecks1', 'dbachecks2', 'dbachecks3' $password = ConvertTo-SecureString "dbatools.IO" -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "sqladmin", $password $show = 'All' $traci = Trace-Script -ScriptBlock { $v5code = Invoke-DbcCheck -SqlInstance $Sqlinstances -SqlCredential $cred -Check $Checks -legacy $false -Show $show -PassThru } $traci1 = Trace-Script -ScriptBlock { $v5code = Invoke-DbcCheck -SqlInstance $Sqlinstances -SqlCredential $cred -Check $Checks -legacy $false -Show $show -PassThru } $traci = Trace-Script -ScriptBlock { $v4code = Invoke-DbcCheck -SqlInstance $Sqlinstances -SqlCredential $cred -Check $Checks -legacy $true -Show $show -PassThru } Invoke-DbcCheck -SqlInstance $Sqlinstances -SqlCredential $cred -Check failsafeoperator -legacy $false -Show $show -verbose ================================================ FILE: developing/Setting up for Sampler.ps1 ================================================ # Setting up for Sampler Install-Module -Name 'Sampler' -Scope 'CurrentUser' -AllowPrerelease $samplerModule = Import-Module -Name Sampler -PassThru $invokePlasterParameters = @{ TemplatePath = Join-Path -Path $samplerModule.ModuleBase -ChildPath 'Templates/Sampler' DestinationPath = '..\' ModuleType = 'CompleteSample' ModuleName = Split-Path -Leaf $PWD SourceDirectory = 'source' } Invoke-Plaster @invokePlasterParameters -Verbose .\build.ps1 -ResolveDependency -Tasks noop ./build.ps1 -Tasks ? ./build.ps1 -Tasks build ./build.ps1 -Tasks build, tests # If we get test failures whilst developing, we can check the test results in the browser by creating a html page .\tests\extent.exe -i .\output\testResults\NUnitXml_dbachecks_v2.0.18.Linux.PSv.7.3.0.xml -o .\output\testResults\reports -r v3html ii .\output\testResults\reports\index.html # outside of container # the other option is to the tests with Invoke-Pester Invoke-Pester ./tests ================================================ FILE: developing/settingupfor2022.ps1 ================================================ docker run -p 52001:1433 dbatools/sqlinstance2 docker run -p 52000:1433 -v sqlserver:/var/opt/sqlserver -d dbatools/sqlinstance --name mssql1 docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=dbatools.IO" -p 52002:1433 --name mssql3 --hostname mssql3 -v sqlserver:/var/opt/sqlserver -d mcr.microsoft.com/mssql/server:2022-latest # thank you Andrew docker exec -u 0 mssql1 bash -c "chown mssql /var/opt/sqlserver" docker exec -u 0 mssql3 bash -c "chown mssql /var/opt/sqlserver" $mssql1cred = Get-Credential $mssql2cred = Get-Credential $mssql3cred = Get-Credential $sql1 = Connect-DbaInstance -SqlInstance 'localhost,52000' -SqlCredential $mssql2cred $sql2 = Connect-DbaInstance -SqlInstance 'localhost,52001' -SqlCredential $mssql2cred $sql3 = Connect-DbaInstance -SqlInstance 'localhost,52002' -SqlCredential $mssql3cred Get-DbaLogin -SqlInstance $sql1,$sql2,$sql3 | ft Get-DbaDatabase -SqlInstance $sql1,$sql2,$sql3 | ft Get-DbaAgentJob -SqlInstance $sql1,$sql2,$sql3 | ft Get-DbaDbCertificate -SqlInstance $sql1,$sql2,$sql3 | ft docker run -p 52000:1433 -v sqlserver:/var/opt/sqlserver -d dbatools/sqlinstance --name mssql1 docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=dbatools.IO" -p 52002:1433 --name mssql3 --hostname mssql3 -v sqlserver:/var/opt/sqlserver -d mcr.microsoft.com/mssql/server:2022-latest Backup-DbaDatabase -SqlInstance $sql1 -BackupDirectory /var/opt/sqlserver -Type Full Start-DbaMigration -Source $sql1 -Destination $sql3 -UseLastBackup ================================================ FILE: docs/RELEASE.md ================================================ ## 23rd August 2021 Fixed bug where custom tests left an empty DbcResult #846 Added feature to overwrite config file if it already exists for Export-DbcConfig #844 Enabled ping latency testing in PowerShell Core ##Latest ## 23rd August 2021 Removed the Verbose for the Pester load - Apologies, this was Rob! Thank you [@MikeyBronowski](https://www.github.com/MikeyBronowski) Get the file at the end so Export-DbcConfig can be used with Invoke-Item addresses #843 #845 Thank you [@MikeyBronowski](https://www.github.com/MikeyBronowski) spelling and full stops #842 Thank you [ashdar](https://github.com/ashdar) Check for existence in the Tag list before adding a Tag to the Tag list #853 Thank you [ashdar](https://github.com/ashdar) Updated PowerPlan Assertion #850 Thank you [tboggiano](https://github.com/tboggiano) CIS check for SQL Mail XPS for SQL Server 2008 and below (was) #779 Thank you [tboggiano](https://github.com/tboggiano) Added function to set CIS config (was) #776 Thank you [tboggiano](https://github.com/tboggiano) CIS check for TCP IP Protocols (was) #775 ## April 7th 2021 Thank you [@mikedavem](https://www.github.com/mikedavem) Fixed rogue verbose when importing [#834](https://github.com/sqlcollaborative/dbachecks/issues/834) Thank you [@mikedavem](https://www.github.com/mikedavem) Test NetBios Over TCP/IP should be disabled for cluster network interface [#833](https://github.com/sqlcollaborative/dbachecks/issues/833) Thank you [@conseilit](https://www.github.com/conseilit) Add LogfilePercentUsed check. Log might fill even if simple recovery model or full recovery model + Tlog backup in case of replication, CDC, HADR issues. [#831](https://github.com/sqlcollaborative/dbachecks/issues/831) [#832](https://github.com/sqlcollaborative/dbachecks/issues/832) Thank you [@conseilit](https://www.github.com/conseilit) Getting SQL Server instance DateTime prevent Log Backup checks to fail if the instance is not in the same timezone than the computer running dbaChecks scripts. [#830](https://github.com/sqlcollaborative/dbachecks/issues/830) Thank you [@MikeyBronowski](https://www.github.com/MikeyBronowski) Get-DbcConfig Adding support to multiple names [#829](https://github.com/sqlcollaborative/dbachecks/issues/829) Thank you [@MikeyBronowski](https://www.github.com/MikeyBronowski) Spellings [#827](https://github.com/sqlcollaborative/dbachecks/issues/827) Thank you [@TheAntGreen](https://www.github.com/TheAntGreen) updated variables to make errors obvious [#825](https://github.com/sqlcollaborative/dbachecks/issues/825) Thank you [@MrBlueSky](https://www.github.com/MrBlueSky) - add info to suggest using Duplicate index command [#807](https://github.com/sqlcollaborative/dbachecks/issues/807) Thank you [@PsPsam](https://www.github.com/PsPsam) - Ping check to work on core and 5.1 [#763](https://github.com/sqlcollaborative/dbachecks/issues/763) Thank you [@zikato](https://www.github.com/zikato) - certificate expiration gives two failures if in the past [#785](https://github.com/sqlcollaborative/dbachecks/issues/785) Thank you [@mikedavem](https://www.github.com/mikedavem) - allow more than 99 days for retention for Olas jobs [#835](https://github.com/sqlcollaborative/dbachecks/issues/835) Thank you [@Shashtsoh](https://www.github.com/Shashtsoh) - Remove aliases to work in core [#837](https://github.com/sqlcollaborative/dbachecks/issues/837) Thank you [@a4ic6n](https://www.github.com/a4ic6n) - Max Memory check false succeeds [#836](https://github.com/sqlcollaborative/dbachecks/issues/836) ## December 14th 2020 Thank you tboggiano Browser check altered for instance count #758 Thank you zikato - Fixing datafile auto growth #786 Thank you fatherjack Typos #767 Thank you tboggiano Query Store enabled and disabled test improvements #791 Thank you relsna fixed issue with error log window #814 Thank you @TheAntGreen Typos #815 Thank you @TheAntGreen Add additional filter to filter out negative run_durations #816 Thank you @TheAntGreen Add policy for additional excluded dbs from the SAFE CLR check #817 Thank you @MikeyBronowski Fix the check for enabled alerts #819 Thank you @MikeyBronowski Updating the link in documentation #820 Thank you @mikedavem Updated HADR checks with additional checks #822 Thank you @mikedavem Database backup diff check - fix issue #812 #824 ## Date November 23rd 2020 Finally Rob gets around to working on PRs - Really sorry it has taken so long Fixes for bug 780 & 783 #784 - Thank you @TheAntGreen Fix local windows groups, additional filter needed on the object filter #789 - Thank you @TheAntGreen $null check for anything running SQL2008R2 or below as containment doesnt exist in those versions. #790 - Thank you @TheAntGreen Fix for IsClustered checks for service startup types #792 - Thank you @TheAntGreen CertCheck took ages to run, was still checking excluded DB's then filtering, change to not query the excluded DBs #793 - Thank you @TheAntGreen Fixed few typos in docs #799 - Thank you @jpomfret Fixed few typos in docs #799 - Thank you @TheAntGreen DuplicateIndex Check - Added new configuration option to allow people to filter out databases, as SSRS DB's have duplicate indexes and names are configuration in older versions, defaults to ReportServer & ReportServerTempDB GuestUserConnect - Changes method to Get-Database instead of InstanceSMO so its easier to filter out none accessable databases as the check would report false positives for offline or restoring databases NotExpectedTraceFlag - added a filter to filter out any trace flags which WHERE expected to prevent false positive alerts #801 - Thank you @TheAntGreen Add policy to exclude databases on the trustworthy check #806 - Thank you @TheAntGreen Unused Index Check wasn't executing correctly #808 - Thank you @TheAntGreen #803 Addition of the date filter for File Autogrowth detection #809 - Thank you @TheAntGreen New Check - Agent Mail Profile #811 - Thank you @TheAntGreen Scan for startup procs, use config option to override the value in use #813 - Thank you @TheAntGreen ##Latest ## Date September 22nd 2020 Only Importing Pester v4 and lower to reduce Pester v5 errors ## Date July 13th 2020 Thank you jpomfret Added skip.backup.readonly config #777 Thank you jpomfret typos #771 Thank you jpomfret Added MSDB suspect pages table check #768 Thank you markaugust Added instance name to Agent Service ACcount checks #766 Thank you tboggiano fixed Agent Run time calculation #746 ## Date 9th May 2020 UPDATED TO VERSION 2 New Commands Convert-DbcResult - To parse results and add Label, ComputerName, Instance and Database Set-DbcFile - To save the parsed results to a file json, csv or xml Write-DbcTable - to add results to a database New Parameter -FromDatabase on Star-DbcPowerBi - to open new Power Bi template file New PowerBi template file for reporting on results from the database Improved Spelling Updated Unit Tests for Checks to enabled results to be parsed Improved Check Titles Configuration for Max history days for Job duration Stop trying to check inaccessible databases for checks Improved Query Store checks Ensure long running agent jobs ignores durations longer than 24 hours Ignore jobs that never stop from the duration check ##Latest ## Date 29th March 2020 UPDATED MINIMUM POWERSHELL VERSION Updated Required versions of Pester, dbatools and PSFramework modules Thank you @dstrait Fix variable for SaDisabled check #750 Fix errant braces in SQL Browser Service Check #751 Fix PingComputer Check #752 Thank you markaugust Fix to ensure AG Name is in HADR checks #755 Thank you Tracey Boggiano Added Contained Database auth check and Query Store Enabled Checks #756 Thank you Rob Added exclude database config for Query store checks Version check for Query Store Checks Some spellings! ##Latest ## Date 18th March 2020 Thank you Tracey tboggiano New CIS user-defined CLRs to be set to SAFE_ACCESS #734 CIS tests for if service accounts are local admins #736 Thank you Rob Getting service accounts tests to pass if no service Made long running jobs check work as expected Improved Database Mail check Made sure disk allocations dont run on Core Thank you mikedavem Fixed bug in disk allocation check exclusions Added multiple ags to the HADR check #742 ## Date 14th March 2020 Thank you Tracey tboggiano New CIS Check Hide Instance #728 New CIS Check Symmetric Key #732 New CIS Check Agent Proxy not have access to public Role #732 ## Date 8th January 2020 Thank you Tracey tboggiano New CIS Check Guest Account connect permissions #725 New CIS Check BuiltIn Admins login #726 New CIS Check public role permissions #729 New CIS Check local windows groups do not have logins #731 Update sa login check #730 Thank you Rob Added Tag parameter to Get-DbcCheck Updated tests to work with PowerShell 7 ## Date 22nd December Thank you Tracey tboggiano Two New CIS Checks Contained databases should be auto-closed #721 sa login disabled and should not exist #719 Thank you Rob Fix bug in Agent Tests #723 ## Date 28th November Thank you Tracey tboggiano Added new CIS Check for the latest SQL build #716 Thank you Rob Making the SQL Engine Service Check configurable #706 ## Date 26th November Thank you Tracey @tboggiano Added new CIS Check for OLE AUtomation Procedures to be disabled #707 Moving the Cross DB Ownership Chaining check into the AllInstance check to help speed up checks #708 Thank you Rob Fixing the Tags so that they are picked up by AllInstanceInfo Fixes #715 ## Date 16th November Thank you Matt @matt2005 Removed rogue else from Agents Tests #713 ## Date 17th October Thank you Shane @SOZDBA Improved Documentation Thank you Gareth NewMan Added New Check - Default File Path ## Date 1st October 2019 Thank you Rob Fixed some merge issues with a load of code :-( Created GitHub Action to run Pester Checks on PR Thank you @TracyBoggiano Added New Checks RemoteAccessDisabled ScanForStartUpProcedures Thank you Gareth Newman Improved wording in tests #700 , #697 Fix incorrect calculation in last agent run time #696 #698 Fixed bug in AllInstanceInfo Thank you Richard Imenes Fixed dead links in readme #702 Thank you Benjamin Schenk Fixed Send-MailMessage in readme #705 ## Date 30th July 2019 Thank you Rob ;-) Added two new checks #239 LastJobRunTime and LongRunningJob Added four new configs skip.agent.longrunningjobs skip.agent.lastjobruntime agent.longrunningjob.percentage agent.lastjobruntime.percentage ## Date 29th July 2019 Thank you @TracyBoggiano Added tags for checks that will be part of CIS checks #642 CIS project started Added check for default trace enabled #684 ## Date 23rd July 2019 Thank you @dstrait, @Sozdba Fix tests that use time to work if client and instance are in different time zones #610 Fixed Maintenance Solution clean up time test #633 Improved Run time #635 Improved Error Log warning window honouring #637 Ignore SQL 2005 for some tests #630,629,#628 Skip TF1118 test if SQL2016 or above ## Date 8th July 2019 Thanks to Chuck for notifying of error Fixed Update-DbcPowerBiDataSource ## Date 2nd July 2019 dbachecks works with PowerShell Core #620 dbachecks works with dbatools v1 #624 Minimum PowerShell Now 5.0 #568 Prettier output in test names for @cl because she is ace #495 Fixes for none-readable secondaries causing tests to fail #611 Added ability to exclude disks from disk allocation check #561 Added ability to exclude cancelled jobs from failed job check #552 Added max job history for failed jobs #552 Some extra tags added ## Date 22nd May 2019 at Techorama in Room 12 Thank You @SOZDBA, @djfcc, @wsmelton Improved validation for IP addresses in clusters Ignored Off-line databases for Pseudo Recovery Checks Some internal testing changes ## Date 05/02/2019 Thank you Chrissy! @cl added default environment #596 altered configuration validation for mail to stop errors Ensured database status check doesnt fail as readonly for snapshots ## Date 31/01/2019 Thank you Chrissy! add support for inline config file, fixes #501 #594 ## Date 29/01/2019 Added skip for authentication scheme #587 Added WhatIf to Update-DbcPowerBiDataSource Thank you @shaneis #590 $null to the left Thank you @jwmoss #588 ## Date 19/01/2019 Thank you Claudio Added extra check for Job History Settings #582 Added extra check for Error Log Count #583 Added integration test code and docker compose file ##Latest ## Date 22/11/2018 Spelling - Thanks RonaldHensbergen Fix for #576 When calling just Invoke-DbcCheck without a Check it fails to run the Server Tests correctly ## Date 12/11/2018 Added more information to the output - thanks @ClaudioESSilva Spelling - Thanks ChrisTuckerNM Fix for #564 - Error Importing DbcConfig in PowerShell 4 - Thanks @niphod ## Date 29/10/2018 Fixed #435 Page verify on SQL 2000 and SQL2005 Reduced number of calls to the instance for database checks improving performance ## Date 27/10/2018 Fixed #435 Page verify on SQL 2000 and SQL2005 Reduced number of calls to the instance for database checks improving performance ## Date 17/10/2018 Spelling and Because added - Thank you @LowlyDBA New Check for XPCmdShell enabled added ## Date 11/10/2018 Added Check for CLR Enabled Added Check for Cross Database Ownership Chaining Added Check for Database Mail XPs Added Check for Ad Hoc Distributed Queries Added Tag for security Demo CI/CD at Polar Conf ## Date 24/09/2018 Moved the Instance Connection Check to the Instance Tests Fixed bug with Set-DbcConfig not adding none-arrays! New Check for Expected Trace Flags New Check for Not Expected TraceFlags Stopped dbatools chatty messages polluting the test results ## Date 07/09/2018 Updated dbatools required module to 0.9.410 Renamed all dbatools commands to new naming convention Fixed Bug with JSON file naming Improved Server Checks to remove Red and improve speed for none contactable servers Altered all server checks to use assertions and added pester Tests Removed left over ogv entry ## Date 05/09/2018 New Check for 2 digit cut off thanks @CláudioESSilva https://claudioessilva.eu/2018/09/04/dont-cutoff-yourself-when-dealing-with-dates-in-t-sql-did-you-know/ Fixed bug with adding NoneContactable Instances to variable Improved error handling for HADR checks ## Date 28/08/2018 Added MaxBehind to SupportedBuild Tests - Thank you @LowlyDBA Ensured the Database parameter checks only the specified Databases - Thank you @jpomfret Updated Set-DbcConfig to allow Append to append arrays to arrays closes #535 Altered json filename creation to avoid max characters error Altered PowerBi to display information correctly with filename changes ## Date 24/08/2017 Fixed Error with using Credential and stopped changing path when running checks from custom repos - Thank you @sammyxx ## Date 23/08/2017 Update to the help message for clusters by @LowlyDBA Potential Breaking Change - Removed Tags from names of json files so that PowerBi will correctly show Environment names ## Date 15/08/2018 Fixed issue 521 ExcludeDatabase parameter doesn't work - THANK YOU @jpomfret THANK YOU @jpomfret - Issue 509 -Database should only check databases listed and exclude all others Further update to Update-DbcPowerBiDataSource to allow Environment as well as specify filename Improved performance of the Server checks Improved performance of the Instance checks Improved performance of the Database checks Improved performance of the ErrorLog checks Removed Send-DbcSendMailMessage until it can be re-coded ## Date 13/08/2018 Fixed #504 by enabling FileName parameter on Update-PowerBiDataSource Added in new function to begin to reduce the number of calls to each instance Reduced required Pester version to 4.3.1 Further PowerShell V4 improvements ## Date 06/08/2018 Added New Check for tempdb data file sizes to be the same - Thank you @garethnewman #512 Altered Services Check so that clustered instances start mode is checked correctly thank you @kylejdoyle #516 Skip PowerPlan test if no connection thanks @cl #490 Fixed bug with XESession and PSv4 thank you @kylejdoyle #517 Error silently on failing Service check (thanks Rob ;-) ) Fixed dbatools command names Fixed PSv4 support for importing the module also ## Date 31/07/2018 Added check for Database Exists - Thanks @sqldbawithbeard Added excluded databases config to each Database Check and wrote Pester Test for that #506 Added msdb to exclusion fro duplicate index #506 Fixed offline install bug #484 ## Date 30/07/2018 Updated Required Module versions - Thank you @cl Updated Agent Checks to fail a test on no connection rather than throw all the PowerShell errors - Thanks @sqldbawithbeard Updated HADR Checks for PS4 compatibility Issue #513 ## Date 28/06/2018 Don't check versions before 2008 for AdHocWorkloads Thank you John McCall @LowlyDBA More Spelling! Thank you John McCall @LowlyDBA Updated required version and dbatools error log command name Thank you Our Glorious Chrissy @cl ## Date 30/05/2018 New Release Notes command added Spelling ## Date 29/05/2012 ================================================ FILE: docs/functions/Clear-DbcPowerBiDataSource.md ================================================ # Clear-DbcPowerBiDataSource ## SYNOPSIS Clears the data source directory created by Update-DbcPowerBiDataSource ## SYNTAX ``` Clear-DbcPowerBiDataSource [[-Path] ] [[-Environment] ] [-EnableException] [] ``` ## DESCRIPTION Clears the data source directory created by Update-DbcPowerBiDataSource ("C:\windows\temp\dbachecks\*.json" by default). This command makes it easier to clean up data used by PowerBI via Start-DbcPowerBi. ## EXAMPLES ### EXAMPLE 1 ``` Clear-DbcPowerBiDataSource ``` Removes "$env:windir\temp\dbachecks\*.json" ### EXAMPLE 2 ``` Clear-DbcPowerBiDataSource -Environment Production ``` Removes "$env:windir\temp\dbachecks\*Production*.json" ## PARAMETERS ### -Path The directory to your JSON files, which will be removed. "C:\windows\temp\dbachecks\*.json" by default ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 1 Default value: "$env:windir\temp\dbachecks" Accept pipeline input: False Accept wildcard characters: False ``` ### -Environment Removes the JSON files for a specific environment ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 2 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ## NOTES ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Clear-DbcPowerBiDataSource/](https://dbachecks.readthedocs.io/en/latest/functions/Clear-DbcPowerBiDataSource/) ================================================ FILE: docs/functions/Convert-DbcResult.md ================================================ # Convert-DbcResult ## SYNOPSIS Takes the results of Invoke-DbcCheck, parses it and converts it to a datatable object ## SYNTAX ``` Convert-DbcResult [-TestResults] [[-Label] ] [] ``` ## DESCRIPTION You need to run Invoke-DbcCheck with the PassThru parameter and this command will take the results and parse them creating a datatable object with column headings Date Label Describe Context Name Database ComputerName Instance Result FailureMessage so that it can be written to a database with Write-DbcTable (or Write-DbaDataTable) or to a file with Set-DbcFile ## EXAMPLES ### EXAMPLE 1 ``` Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check ``` Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check ### EXAMPLE 2 ``` Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Write-DbcTable -SqlInstance sql2017n5 -Database tempdb -Table newdbachecks ``` Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and writes it to a table newdbachecks in tempdb on SQL2017N5 (NB Don't use tempdb!!) ### EXAMPLE 3 ``` Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Set-DbcFile -FilePath C:\temp\dbachecks\ -FileName Auto-close.json -FileType Json ``` Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and outputs to JSON and saves in C:\temp\dbachecks\Auto-close.json ## PARAMETERS ### -TestResults The output of Invoke-DbcCheck (WITH -PassThru) ```yaml Type: PSObject Parameter Sets: (All) Aliases: Required: True Position: 1 Default value: None Accept pipeline input: True (ByValue) Accept wildcard characters: False ``` ### -Label An optional label to add to the set of results to identify them - Think Morning-Checks or New-instance ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 2 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ### System.Data.DataTable ## NOTES Initial - RMS 28/12/2019 ## RELATED LINKS ================================================ FILE: docs/functions/Export-DbcConfig.md ================================================ # Export-DbcConfig ## SYNOPSIS Exports dbachecks configs to a json file to make it easier to modify or be used for specific configurations. ## SYNTAX ``` Export-DbcConfig [[-Path] ] [-Force] [] ``` ## DESCRIPTION Exports dbachecks configs to a json file to make it easier to modify or be used for specific configurations. ## EXAMPLES ### EXAMPLE 1 ``` Export-DbcConfig ``` Exports config to "$script:localapp\config.json" ### EXAMPLE 2 ``` Export-DbcConfig -Path \\nfs\projects\config.json ``` Exports config to \\\\nfs\projects\config.json ### EXAMPLE 3 ``` $config = Export-DbcConfig | Invoke-Item ``` Exports config to "$script:localapp\config.json" as and opens it in a default application. ## PARAMETERS ### -Path The path to export to, by default is "$script:localapp\config.json" ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 1 Default value: "$script:localapp\config.json" Accept pipeline input: False Accept wildcard characters: False ``` ### -Force Overwrite Existing file ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ### System.String ## NOTES ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Export-DbcConfig/](https://dbachecks.readthedocs.io/en/latest/functions/Export-DbcConfig/) ================================================ FILE: docs/functions/Get-DbcCheck.md ================================================ # Get-DbcCheck ## SYNOPSIS Lists all checks, tags and unique identifiers ## SYNTAX ``` Get-DbcCheck [[-Tag] ] [[-Pattern] ] [[-Group] ] [] ``` ## DESCRIPTION Lists all checks, tags and unique identifiers ## EXAMPLES ### EXAMPLE 1 ``` Get-DbcCheck ``` Retrieves all of the available checks ### EXAMPLE 2 ``` Get-DbcCheck backups ``` Retrieves all of the available tags that match backups ## PARAMETERS ### -Tag The tag to return information about ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 1 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Pattern May be any string, supports wildcards. ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 2 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Group To be able to filter by group ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 3 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ## NOTES ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Get-DbcCheck/](https://dbachecks.readthedocs.io/en/latest/functions/Get-DbcCheck/) ================================================ FILE: docs/functions/Get-DbcConfig.md ================================================ # Get-DbcConfig ## SYNOPSIS Retrieves configuration elements by name. ## SYNTAX ``` Get-DbcConfig [[-Name] ] [-EnableException] [] ``` ## DESCRIPTION Retrieves configuration elements by name. Can be used to search the existing configuration list. ## EXAMPLES ### EXAMPLE 1 ``` Get-DbcConfig app.sqlinstance ``` Retrieves the configuration element for the configuration app.sqlinstance ## PARAMETERS ### -Name Default: "*" The name of the configuration element(s) to retrieve. May be any string, supports wildcards. ```yaml Type: String[] Parameter Sets: (All) Aliases: Required: False Position: 1 Default value: * Accept pipeline input: False Accept wildcard characters: False ``` ### -EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ## NOTES ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Get-DbcConfig/](https://dbachecks.readthedocs.io/en/latest/functions/Get-DbcConfig/) ================================================ FILE: docs/functions/Get-DbcConfigValue.md ================================================ # Get-DbcConfigValue ## SYNOPSIS Retrieves raw configuration values by name. ## SYNTAX ``` Get-DbcConfigValue [[-Name] ] [-EnableException] [] ``` ## DESCRIPTION Retrieves raw configuration values by name. Can be used to search the existing configuration list. ## EXAMPLES ### EXAMPLE 1 ``` Get-DbcConfigValue app.sqlinstance ``` Retrieves the raw value for the key "app.sqlinstance" ## PARAMETERS ### -Name Default: "*" The name of the configuration element(s) to retrieve. May be any string, supports wildcards. ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 1 Default value: * Accept pipeline input: False Accept wildcard characters: False ``` ### -EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ## NOTES ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Get-DbcConfig/](https://dbachecks.readthedocs.io/en/latest/functions/Get-DbcConfig/) ================================================ FILE: docs/functions/Get-DbcReleaseNote.md ================================================ # Get-DbcReleaseNote ## SYNOPSIS Returns the release notes for the module - organised by date ## SYNTAX ``` Get-DbcReleaseNote [-Latest] ``` ## DESCRIPTION Grabs the release notes for the dbachecks module and returns either the latest or all of them ## EXAMPLES ### EXAMPLE 1 ``` Get-DbcReleaseNote ``` Returns the release notes for the dbachecks module ### EXAMPLE 2 ``` Get-DbcReleaseNote -Latest ``` Returns just the latest release notes for the dbachecks module ## PARAMETERS ### -Latest A Switch to return the latest release notes only ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ## INPUTS ## OUTPUTS ## NOTES 30/05/2012 - RMS ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Get-DbcReleaseNote/](https://dbachecks.readthedocs.io/en/latest/functions/Get-DbcReleaseNote/) ================================================ FILE: docs/functions/Get-DbcTagCollection.md ================================================ # Get-DbcTagCollection ## SYNOPSIS Retrieves a list of all available tags. Simplistic, similar to Get-Verb. ## SYNTAX ``` Get-DbcTagCollection [[-Name] ] [-EnableException] [] ``` ## DESCRIPTION Retrieves a list of all available tags. Simplistic, similar to Get-Verb. ## EXAMPLES ### EXAMPLE 1 ``` Get-DbcTag ``` Retrieves all of the available tags for -Tag and -ExcludeTag ### EXAMPLE 2 ``` Get-DbcTag backups ``` Retrieves all of the available tags for -Tag and -ExcludeTag that are -like backups ## PARAMETERS ### -Name Default: "*" The name of the tag to retrieve. May be any string, supports wildcards. ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 1 Default value: * Accept pipeline input: False Accept wildcard characters: False ``` ### -EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ## NOTES ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Get-DbcTagCollection/](https://dbachecks.readthedocs.io/en/latest/functions/Get-DbcTagCollection/) ================================================ FILE: docs/functions/Import-DbcConfig.md ================================================ # Import-DbcConfig ## SYNOPSIS Imports dbachecks configs from a json file ## SYNTAX ``` Import-DbcConfig [[-Path] ] [-Temporary] [-EnableException] [] ``` ## DESCRIPTION Imports dbachecks configs from a json file ## EXAMPLES ### EXAMPLE 1 ``` Import-DbcConfig ``` Imports config from "$script:localapp\config.json" ### EXAMPLE 2 ``` Import-DbcConfig -Path \\nas\projects\config.json ``` Imports config from \\\\nas\projects\config.json ## PARAMETERS ### -Path The path to import from, by default is "$script:localapp\config.json" ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 1 Default value: "$script:localapp\config.json" Accept pipeline input: False Accept wildcard characters: False ``` ### -Temporary The settings are not persisted outside the current session. By default, settings will be remembered across all PowerShell sessions. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ## NOTES ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Import-DbcConfig/](https://dbachecks.readthedocs.io/en/latest/functions/Import-DbcConfig/) ================================================ FILE: docs/functions/Invoke-DbcCheck.md ================================================ # Invoke-DbcCheck ## SYNOPSIS Invoke-DbcCheck is a SQL-centric Invoke-Pester wrapper ## SYNTAX ### Default (Default) ``` Invoke-DbcCheck [-Script ] [-TestName ] [-EnableExit] [[-Check] ] [-ExcludeCheck ] [-PassThru] [-SqlInstance ] [-ComputerName ] [-SqlCredential ] [-Credential ] [-Database ] [-ExcludeDatabase ] [-Value ] [-ConfigFile ] [-CodeCoverage ] [-CodeCoverageOutputFile ] [-CodeCoverageOutputFileFormat ] [-Strict] [-OutputFormat ] [-AllChecks] [-Quiet] [-PesterOption ] [-Show ] [-ConfigAgentAlertJob ] [-ConfigAgentAlertMessageid ] [-ConfigAgentAlertNotification ] [-ConfigAgentAlertSeverity ] [-ConfigAgentDatabasemailprofile ] [-ConfigAgentDbaoperatoremail ] [-ConfigAgentDbaoperatorname ] [-ConfigAgentFailedjobExcludecancelled ] [-ConfigAgentFailedjobSince ] [-ConfigAgentFailsafeoperator ] [-ConfigAgentHistoryMaximumhistoryrows ] [-ConfigAgentHistoryMaximumjobhistoryrows ] [-ConfigAgentLastjobruntimePercentage ] [-ConfigAgentLongrunningjobPercentage ] [-ConfigAgentValidjobownerName ] [-ConfigAppCheckrepos ] [-ConfigAppCluster ] [-ConfigAppComputername ] [-ConfigAppLocalapp ] [-ConfigAppMaildirectory ] [-ConfigAppSqlcredential ] [-ConfigAppSqlinstance ] [-ConfigAppWincredential ] [-ConfigCommandInvokedbccheckExcludecheck ] [-ConfigCommandInvokedbccheckExcludedatabases ] [-ConfigDatabaseExists ] [-ConfigDatabaseQuerystoredisabledExcludedb ] [-ConfigDatabaseQuerystoreenabledExcludedb ] [-ConfigDomainDomaincontroller ] [-ConfigDomainName ] [-ConfigDomainOrganizationalunit ] [-ConfigGlobalNotcontactable ] [-ConfigMailFailurethreshhold ] [-ConfigMailFrom ] [-ConfigMailSmtpserver ] [-ConfigMailSubject ] [-ConfigMailTo ] [-ConfigOlaJobNameCommandLogCleanup ] [-ConfigOlaJobNameDeleteBackupHistory ] [-ConfigOlaJobNameOutputFileCleanup ] [-ConfigOlaJobNamePurgeBackupHistory ] [-ConfigOlaJobNameSystemFull ] [-ConfigOlaJobNameSystemIntegrity ] [-ConfigOlaJobNameUserDiff ] [-ConfigOlaJobNameUserFull ] [-ConfigOlaJobNameUserIndex ] [-ConfigOlaJobNameUserIntegrity ] [-ConfigOlaJobNameUserLog ] [-ConfigPolicyAdlogingroupExcludecheck ] [-ConfigPolicyAdloginuserExcludecheck ] [-ConfigPolicyBackupDatadir ] [-ConfigPolicyBackupDefaultbackupcompression ] [-ConfigPolicyBackupDiffmaxhours ] [-ConfigPolicyBackupFullmaxdays ] [-ConfigPolicyBackupLogdir ] [-ConfigPolicyBackupLogmaxminutes ] [-ConfigPolicyBackupNewdbgraceperiod ] [-ConfigPolicyBackupTestserver ] [-ConfigPolicyBuildBehind ] [-ConfigPolicyBuildWarningwindow ] [-ConfigPolicyCertificateexpirationExcludedb ] [-ConfigPolicyCertificateexpirationWarningwindow ] [-ConfigPolicyClusterHostrecordttl ] [-ConfigPolicyClusterNetworkProtocolsIPV4 ] [-ConfigPolicyClusterRegisterallprovidersIP ] [-ConfigPolicyConnectionAuthscheme ] [-ConfigPolicyConnectionPingcount ] [-ConfigPolicyConnectionPingmaxms ] [-ConfigPolicyDacallowed ] [-ConfigPolicyDatabaseAutoclose ] [-ConfigPolicyDatabaseAutocreatestatistics ] [-ConfigPolicyDatabaseAutoshrink ] [-ConfigPolicyDatabaseAutoupdatestatistics ] [-ConfigPolicyDatabaseAutoupdatestatisticsasynchronously ] [-ConfigPolicyDatabaseClrassembliessafeexcludedb ] [-ConfigPolicyDatabaseDuplicateindexexcludedb ] [-ConfigPolicyDatabaseFilebalancetolerance ] [-ConfigPolicyDatabaseFilegrowthdaystocheck ] [-ConfigPolicyDatabaseFilegrowthexcludedb ] [-ConfigPolicyDatabaseFilegrowthfreespacethreshold ] [-ConfigPolicyDatabaseFilegrowthtype ] [-ConfigPolicyDatabaseFilegrowthvalue ] [-ConfigPolicyDatabaseLogfilecount ] [-ConfigPolicyDatabaseLogfilepercentused ] [-ConfigPolicyDatabaseLogfilesizecomparison ] [-ConfigPolicyDatabaseLogfilesizepercentage ] [-ConfigPolicyDatabaseMaxdop ] [-ConfigPolicyDatabaseMaxdopexcludedb ] [-ConfigPolicyDatabaseMaxvlf ] [-ConfigPolicyDatabaseStatusExcludeoffline ] [-ConfigPolicyDatabaseStatusExcludereadonly ] [-ConfigPolicyDatabaseStatusExcluderestoring ] [-ConfigPolicyDatabaseTrustworthyexcludedb ] [-ConfigPolicyDatabaseWrongcollation ] [-ConfigPolicyDbccMaxdays ] [-ConfigPolicyDiskspacePercentfree ] [-ConfigPolicyDumpMaxcount ] [-ConfigPolicyErrorlogLogcount ] [-ConfigPolicyErrorlogWarningwindow ] [-ConfigPolicyHadrAgtcpport ] [-ConfigPolicyHadrEndpointname ] [-ConfigPolicyHadrEndpointport ] [-ConfigPolicyHadrFailureconditionlevel ] [-ConfigPolicyHadrHealthchecktimeout ] [-ConfigPolicyHadrLeasetimeout ] [-ConfigPolicyHadrSessiontimeout ] [-ConfigPolicyHadrTcpport ] [-ConfigPolicyIdentityUsagepercent ] [-ConfigPolicyInstanceMemorydumpsdaystocheck ] [-ConfigPolicyInstanceSqlenginestart ] [-ConfigPolicyInstanceSqlenginestate ] [-ConfigPolicyInstancemaxdopExcludeinstance ] [-ConfigPolicyInstancemaxdopMaxdop ] [-ConfigPolicyInstancemaxdopUserecommended ] [-ConfigPolicyInvaliddbownerExcludedb ] [-ConfigPolicyInvaliddbownerName ] [-ConfigPolicyNetworkLatencymaxms ] [-ConfigPolicyOlaCommandLogCleanUp ] [-ConfigPolicyOlaCommandLogenabled ] [-ConfigPolicyOlaCommandLogscheduled ] [-ConfigPolicyOlaDatabase ] [-ConfigPolicyOlaDeleteBackupHistoryCleanUp ] [-ConfigPolicyOlaDeleteBackupHistoryenabled ] [-ConfigPolicyOlaDeleteBackupHistoryscheduled ] [-ConfigPolicyOlaInstalled ] [-ConfigPolicyOlaOutputFileCleanUp ] [-ConfigPolicyOlaOutputFileCleanupenabled ] [-ConfigPolicyOlaOutputFileCleanupscheduled ] [-ConfigPolicyOlaPurgeJobHistoryCleanUp ] [-ConfigPolicyOlaPurgeJobHistoryenabled ] [-ConfigPolicyOlaPurgeJobHistoryscheduled ] [-ConfigPolicyOlaSystemfullenabled ] [-ConfigPolicyOlaSystemfullretention ] [-ConfigPolicyOlaSystemfullscheduled ] [-ConfigPolicyOlaSystemIntegrityCheckenabled ] [-ConfigPolicyOlaSystemIntegrityCheckscheduled ] [-ConfigPolicyOlaUserdiffenabled ] [-ConfigPolicyOlaUserdiffretention ] [-ConfigPolicyOlaUserdiffscheduled ] [-ConfigPolicyOlaUserfullenabled ] [-ConfigPolicyOlaUserfullretention ] [-ConfigPolicyOlaUserfullscheduled ] [-ConfigPolicyOlaUserIndexOptimizeenabled ] [-ConfigPolicyOlaUserIndexOptimizescheduled ] [-ConfigPolicyOlaUserIntegrityCheckenabled ] [-ConfigPolicyOlaUserIntegrityCheckscheduled ] [-ConfigPolicyOlaUserlogenabled ] [-ConfigPolicyOlaUserlogretention ] [-ConfigPolicyOlaUserlogscheduled ] [-ConfigPolicyOleautomation ] [-ConfigPolicyPageverify ] [-ConfigPolicyRecoverymodelExcludedb ] [-ConfigPolicyRecoverymodelType ] [-ConfigPolicySecurityAdhocdistributedqueriesenabled ] [-ConfigPolicySecurityClrenabled ] [-ConfigPolicySecurityContainedbautoclose ] [-ConfigPolicySecurityCrossdbownershipchaining ] [-ConfigPolicySecurityDatabasemailenabled ] [-ConfigPolicySecurityLatestbuild ] [-ConfigPolicySecurityOleautomationproceduresdisabled ] [-ConfigPolicySecurityRemoteaccessdisabled ] [-ConfigPolicySecurityScanforstartupproceduresdisabled ] [-ConfigPolicySecurityXpcmdshelldisabled ] [-ConfigPolicyServerCpuprioritisation ] [-ConfigPolicyServerExcludeDiskAllocationUnit ] [-ConfigPolicyStorageBackuppath ] [-ConfigPolicySuspectpagesThreshold ] [-ConfigPolicyTraceflagsExpected ] [-ConfigPolicyTraceflagsNotexpected ] [-ConfigPolicyTwodigityearcutoff ] [-ConfigPolicyValiddbownerExcludedb ] [-ConfigPolicyValiddbownerName ] [-ConfigPolicyWhoisactiveDatabase ] [-ConfigPolicyXeventRequiredrunningsession ] [-ConfigPolicyXeventRequiredstoppedsession ] [-ConfigPolicyXeventValidrunningsession ] [-ConfigSkipAgentAlert ] [-ConfigSkipAgentLastjobruntime ] [-ConfigSkipAgentLongrunningjobs ] [-ConfigSkipBackupReadonly ] [-ConfigSkipBackupSecondaries ] [-ConfigSkipBackupTesting ] [-ConfigSkipClusterNetclusterinterface ] [-ConfigSkipConnectionAuth ] [-ConfigSkipConnectionPing ] [-ConfigSkipConnectionRemoting ] [-ConfigSkipDatabaseFilegrowthdisabled ] [-ConfigSkipDatabaseLogfilecounttest ] [-ConfigSkipDatafilegrowthdisabled ] [-ConfigSkipDbccDatapuritycheck ] [-ConfigSkipDiffbackuptest ] [-ConfigSkipHadrListenerPingcheck ] [-ConfigSkipHadrListenerTcpport ] [-ConfigSkipHadrReplicaTcpport ] [-ConfigSkipInstanceDefaulttrace ] [-ConfigSkipInstanceLatestbuild ] [-ConfigSkipInstanceModeldbgrowth ] [-ConfigSkipInstanceOleautomationproceduresdisabled ] [-ConfigSkipInstanceRemoteaccessdisabled ] [-ConfigSkipInstanceScanforstartupproceduresdisabled ] [-ConfigSkipInstanceSuspectpagelimit ] [-ConfigSkipLogfilecounttest ] [-ConfigSkipLogshiptesting ] [-ConfigSkipSecurityAgentserviceadmin ] [-ConfigSkipSecurityAsymmetrickeysize ] [-ConfigSkipSecurityBuiltinadmin ] [-ConfigSkipSecurityClrassembliessafe ] [-ConfigSkipSecurityContainedbautoclose ] [-ConfigSkipSecurityContainedDBSQLAuth ] [-ConfigSkipSecurityEngineserviceadmin ] [-ConfigSkipSecurityFulltextserviceadmin ] [-ConfigSkipSecurityGuestuserconnect ] [-ConfigSkipSecurityHideinstance ] [-ConfigSkipSecurityLocalwindowsgroup ] [-ConfigSkipSecurityLoginauditlevelfailed ] [-ConfigSkipSecurityLoginauditlevelsuccessful ] [-ConfigSkipSecurityLoginCheckPolicy ] [-ConfigSkipSecurityLoginMustChange ] [-ConfigSkipSecurityLoginPasswordExpiration ] [-ConfigSkipSecurityNonstandardport ] [-ConfigSkipSecurityPublicPermission ] [-ConfigSkipSecurityPublicrolepermission ] [-ConfigSkipSecurityQuerystoredisabled ] [-ConfigSkipSecurityQuerystoreenabled ] [-ConfigSkipSecuritySadisabled ] [-ConfigSkipSecuritySaexist ] [-ConfigSkipSecurityServerprotocol ] [-ConfigSkipSecuritySqlagentproxiesnopublicrole ] [-ConfigSkipSecuritySQLMailXPsDisabled ] [-ConfigSkipSecuritySymmetrickeyencryptionlevel ] [-ConfigSkipTempdb1118 ] [-ConfigSkipTempdbfilecount ] [-ConfigSkipTempdbfilegrowthpercent ] [-ConfigSkipTempdbfilesizemax ] [-ConfigSkipTempdbfilesonc ] [-ConfigTestingIntegrationInstance ] [] ``` ### NewOutputSet ``` Invoke-DbcCheck [-Script ] [-TestName ] [-EnableExit] [[-Check] ] [-ExcludeCheck ] [-PassThru] [-SqlInstance ] [-ComputerName ] [-SqlCredential ] [-Credential ] [-Database ] [-ExcludeDatabase ] [-Value ] [-ConfigFile ] [-CodeCoverage ] [-CodeCoverageOutputFile ] [-CodeCoverageOutputFileFormat ] [-Strict] -OutputFile [-OutputFormat ] [-AllChecks] [-Quiet] [-PesterOption ] [-Show ] [-ConfigAgentAlertJob ] [-ConfigAgentAlertMessageid ] [-ConfigAgentAlertNotification ] [-ConfigAgentAlertSeverity ] [-ConfigAgentDatabasemailprofile ] [-ConfigAgentDbaoperatoremail ] [-ConfigAgentDbaoperatorname ] [-ConfigAgentFailedjobExcludecancelled ] [-ConfigAgentFailedjobSince ] [-ConfigAgentFailsafeoperator ] [-ConfigAgentHistoryMaximumhistoryrows ] [-ConfigAgentHistoryMaximumjobhistoryrows ] [-ConfigAgentLastjobruntimePercentage ] [-ConfigAgentLongrunningjobPercentage ] [-ConfigAgentValidjobownerName ] [-ConfigAppCheckrepos ] [-ConfigAppCluster ] [-ConfigAppComputername ] [-ConfigAppLocalapp ] [-ConfigAppMaildirectory ] [-ConfigAppSqlcredential ] [-ConfigAppSqlinstance ] [-ConfigAppWincredential ] [-ConfigCommandInvokedbccheckExcludecheck ] [-ConfigCommandInvokedbccheckExcludedatabases ] [-ConfigDatabaseExists ] [-ConfigDatabaseQuerystoredisabledExcludedb ] [-ConfigDatabaseQuerystoreenabledExcludedb ] [-ConfigDomainDomaincontroller ] [-ConfigDomainName ] [-ConfigDomainOrganizationalunit ] [-ConfigGlobalNotcontactable ] [-ConfigMailFailurethreshhold ] [-ConfigMailFrom ] [-ConfigMailSmtpserver ] [-ConfigMailSubject ] [-ConfigMailTo ] [-ConfigOlaJobNameCommandLogCleanup ] [-ConfigOlaJobNameDeleteBackupHistory ] [-ConfigOlaJobNameOutputFileCleanup ] [-ConfigOlaJobNamePurgeBackupHistory ] [-ConfigOlaJobNameSystemFull ] [-ConfigOlaJobNameSystemIntegrity ] [-ConfigOlaJobNameUserDiff ] [-ConfigOlaJobNameUserFull ] [-ConfigOlaJobNameUserIndex ] [-ConfigOlaJobNameUserIntegrity ] [-ConfigOlaJobNameUserLog ] [-ConfigPolicyAdlogingroupExcludecheck ] [-ConfigPolicyAdloginuserExcludecheck ] [-ConfigPolicyBackupDatadir ] [-ConfigPolicyBackupDefaultbackupcompression ] [-ConfigPolicyBackupDiffmaxhours ] [-ConfigPolicyBackupFullmaxdays ] [-ConfigPolicyBackupLogdir ] [-ConfigPolicyBackupLogmaxminutes ] [-ConfigPolicyBackupNewdbgraceperiod ] [-ConfigPolicyBackupTestserver ] [-ConfigPolicyBuildBehind ] [-ConfigPolicyBuildWarningwindow ] [-ConfigPolicyCertificateexpirationExcludedb ] [-ConfigPolicyCertificateexpirationWarningwindow ] [-ConfigPolicyClusterHostrecordttl ] [-ConfigPolicyClusterNetworkProtocolsIPV4 ] [-ConfigPolicyClusterRegisterallprovidersIP ] [-ConfigPolicyConnectionAuthscheme ] [-ConfigPolicyConnectionPingcount ] [-ConfigPolicyConnectionPingmaxms ] [-ConfigPolicyDacallowed ] [-ConfigPolicyDatabaseAutoclose ] [-ConfigPolicyDatabaseAutocreatestatistics ] [-ConfigPolicyDatabaseAutoshrink ] [-ConfigPolicyDatabaseAutoupdatestatistics ] [-ConfigPolicyDatabaseAutoupdatestatisticsasynchronously ] [-ConfigPolicyDatabaseClrassembliessafeexcludedb ] [-ConfigPolicyDatabaseDuplicateindexexcludedb ] [-ConfigPolicyDatabaseFilebalancetolerance ] [-ConfigPolicyDatabaseFilegrowthdaystocheck ] [-ConfigPolicyDatabaseFilegrowthexcludedb ] [-ConfigPolicyDatabaseFilegrowthfreespacethreshold ] [-ConfigPolicyDatabaseFilegrowthtype ] [-ConfigPolicyDatabaseFilegrowthvalue ] [-ConfigPolicyDatabaseLogfilecount ] [-ConfigPolicyDatabaseLogfilepercentused ] [-ConfigPolicyDatabaseLogfilesizecomparison ] [-ConfigPolicyDatabaseLogfilesizepercentage ] [-ConfigPolicyDatabaseMaxdop ] [-ConfigPolicyDatabaseMaxdopexcludedb ] [-ConfigPolicyDatabaseMaxvlf ] [-ConfigPolicyDatabaseStatusExcludeoffline ] [-ConfigPolicyDatabaseStatusExcludereadonly ] [-ConfigPolicyDatabaseStatusExcluderestoring ] [-ConfigPolicyDatabaseTrustworthyexcludedb ] [-ConfigPolicyDatabaseWrongcollation ] [-ConfigPolicyDbccMaxdays ] [-ConfigPolicyDiskspacePercentfree ] [-ConfigPolicyDumpMaxcount ] [-ConfigPolicyErrorlogLogcount ] [-ConfigPolicyErrorlogWarningwindow ] [-ConfigPolicyHadrAgtcpport ] [-ConfigPolicyHadrEndpointname ] [-ConfigPolicyHadrEndpointport ] [-ConfigPolicyHadrFailureconditionlevel ] [-ConfigPolicyHadrHealthchecktimeout ] [-ConfigPolicyHadrLeasetimeout ] [-ConfigPolicyHadrSessiontimeout ] [-ConfigPolicyHadrTcpport ] [-ConfigPolicyIdentityUsagepercent ] [-ConfigPolicyInstanceMemorydumpsdaystocheck ] [-ConfigPolicyInstanceSqlenginestart ] [-ConfigPolicyInstanceSqlenginestate ] [-ConfigPolicyInstancemaxdopExcludeinstance ] [-ConfigPolicyInstancemaxdopMaxdop ] [-ConfigPolicyInstancemaxdopUserecommended ] [-ConfigPolicyInvaliddbownerExcludedb ] [-ConfigPolicyInvaliddbownerName ] [-ConfigPolicyNetworkLatencymaxms ] [-ConfigPolicyOlaCommandLogCleanUp ] [-ConfigPolicyOlaCommandLogenabled ] [-ConfigPolicyOlaCommandLogscheduled ] [-ConfigPolicyOlaDatabase ] [-ConfigPolicyOlaDeleteBackupHistoryCleanUp ] [-ConfigPolicyOlaDeleteBackupHistoryenabled ] [-ConfigPolicyOlaDeleteBackupHistoryscheduled ] [-ConfigPolicyOlaInstalled ] [-ConfigPolicyOlaOutputFileCleanUp ] [-ConfigPolicyOlaOutputFileCleanupenabled ] [-ConfigPolicyOlaOutputFileCleanupscheduled ] [-ConfigPolicyOlaPurgeJobHistoryCleanUp ] [-ConfigPolicyOlaPurgeJobHistoryenabled ] [-ConfigPolicyOlaPurgeJobHistoryscheduled ] [-ConfigPolicyOlaSystemfullenabled ] [-ConfigPolicyOlaSystemfullretention ] [-ConfigPolicyOlaSystemfullscheduled ] [-ConfigPolicyOlaSystemIntegrityCheckenabled ] [-ConfigPolicyOlaSystemIntegrityCheckscheduled ] [-ConfigPolicyOlaUserdiffenabled ] [-ConfigPolicyOlaUserdiffretention ] [-ConfigPolicyOlaUserdiffscheduled ] [-ConfigPolicyOlaUserfullenabled ] [-ConfigPolicyOlaUserfullretention ] [-ConfigPolicyOlaUserfullscheduled ] [-ConfigPolicyOlaUserIndexOptimizeenabled ] [-ConfigPolicyOlaUserIndexOptimizescheduled ] [-ConfigPolicyOlaUserIntegrityCheckenabled ] [-ConfigPolicyOlaUserIntegrityCheckscheduled ] [-ConfigPolicyOlaUserlogenabled ] [-ConfigPolicyOlaUserlogretention ] [-ConfigPolicyOlaUserlogscheduled ] [-ConfigPolicyOleautomation ] [-ConfigPolicyPageverify ] [-ConfigPolicyRecoverymodelExcludedb ] [-ConfigPolicyRecoverymodelType ] [-ConfigPolicySecurityAdhocdistributedqueriesenabled ] [-ConfigPolicySecurityClrenabled ] [-ConfigPolicySecurityContainedbautoclose ] [-ConfigPolicySecurityCrossdbownershipchaining ] [-ConfigPolicySecurityDatabasemailenabled ] [-ConfigPolicySecurityLatestbuild ] [-ConfigPolicySecurityOleautomationproceduresdisabled ] [-ConfigPolicySecurityRemoteaccessdisabled ] [-ConfigPolicySecurityScanforstartupproceduresdisabled ] [-ConfigPolicySecurityXpcmdshelldisabled ] [-ConfigPolicyServerCpuprioritisation ] [-ConfigPolicyServerExcludeDiskAllocationUnit ] [-ConfigPolicyStorageBackuppath ] [-ConfigPolicySuspectpagesThreshold ] [-ConfigPolicyTraceflagsExpected ] [-ConfigPolicyTraceflagsNotexpected ] [-ConfigPolicyTwodigityearcutoff ] [-ConfigPolicyValiddbownerExcludedb ] [-ConfigPolicyValiddbownerName ] [-ConfigPolicyWhoisactiveDatabase ] [-ConfigPolicyXeventRequiredrunningsession ] [-ConfigPolicyXeventRequiredstoppedsession ] [-ConfigPolicyXeventValidrunningsession ] [-ConfigSkipAgentAlert ] [-ConfigSkipAgentLastjobruntime ] [-ConfigSkipAgentLongrunningjobs ] [-ConfigSkipBackupReadonly ] [-ConfigSkipBackupSecondaries ] [-ConfigSkipBackupTesting ] [-ConfigSkipClusterNetclusterinterface ] [-ConfigSkipConnectionAuth ] [-ConfigSkipConnectionPing ] [-ConfigSkipConnectionRemoting ] [-ConfigSkipDatabaseFilegrowthdisabled ] [-ConfigSkipDatabaseLogfilecounttest ] [-ConfigSkipDatafilegrowthdisabled ] [-ConfigSkipDbccDatapuritycheck ] [-ConfigSkipDiffbackuptest ] [-ConfigSkipHadrListenerPingcheck ] [-ConfigSkipHadrListenerTcpport ] [-ConfigSkipHadrReplicaTcpport ] [-ConfigSkipInstanceDefaulttrace ] [-ConfigSkipInstanceLatestbuild ] [-ConfigSkipInstanceModeldbgrowth ] [-ConfigSkipInstanceOleautomationproceduresdisabled ] [-ConfigSkipInstanceRemoteaccessdisabled ] [-ConfigSkipInstanceScanforstartupproceduresdisabled ] [-ConfigSkipInstanceSuspectpagelimit ] [-ConfigSkipLogfilecounttest ] [-ConfigSkipLogshiptesting ] [-ConfigSkipSecurityAgentserviceadmin ] [-ConfigSkipSecurityAsymmetrickeysize ] [-ConfigSkipSecurityBuiltinadmin ] [-ConfigSkipSecurityClrassembliessafe ] [-ConfigSkipSecurityContainedbautoclose ] [-ConfigSkipSecurityContainedDBSQLAuth ] [-ConfigSkipSecurityEngineserviceadmin ] [-ConfigSkipSecurityFulltextserviceadmin ] [-ConfigSkipSecurityGuestuserconnect ] [-ConfigSkipSecurityHideinstance ] [-ConfigSkipSecurityLocalwindowsgroup ] [-ConfigSkipSecurityLoginauditlevelfailed ] [-ConfigSkipSecurityLoginauditlevelsuccessful ] [-ConfigSkipSecurityLoginCheckPolicy ] [-ConfigSkipSecurityLoginMustChange ] [-ConfigSkipSecurityLoginPasswordExpiration ] [-ConfigSkipSecurityNonstandardport ] [-ConfigSkipSecurityPublicPermission ] [-ConfigSkipSecurityPublicrolepermission ] [-ConfigSkipSecurityQuerystoredisabled ] [-ConfigSkipSecurityQuerystoreenabled ] [-ConfigSkipSecuritySadisabled ] [-ConfigSkipSecuritySaexist ] [-ConfigSkipSecurityServerprotocol ] [-ConfigSkipSecuritySqlagentproxiesnopublicrole ] [-ConfigSkipSecuritySQLMailXPsDisabled ] [-ConfigSkipSecuritySymmetrickeyencryptionlevel ] [-ConfigSkipTempdb1118 ] [-ConfigSkipTempdbfilecount ] [-ConfigSkipTempdbfilegrowthpercent ] [-ConfigSkipTempdbfilesizemax ] [-ConfigSkipTempdbfilesonc ] [-ConfigTestingIntegrationInstance ] [] ``` ## DESCRIPTION The Invoke-DbcCheck function runs Pester tests, including *.Tests.ps1 files and Pester tests in PowerShell scripts. Extended description about Pester: Get-Help -Name Invoke-Pester ## EXAMPLES ### EXAMPLE 1 ``` Invoke-DbcCheck -Tag Backup -SqlInstance sql2016 ``` Runs all of the checks tagged Backup against the sql2016 instance ### EXAMPLE 2 ``` Invoke-DbcCheck -Tag RecoveryModel -SqlInstance sql2017, sqlcluster -SqlCredential (Get-Credential sqladmin) ``` Runs the Recovery model check against the SQL instances sql2017, sqlcluster using the sqladmin SQL login with the password provided interactively ### EXAMPLE 3 ``` Invoke-DbcCheck -Check Database -ExcludeCheck AutoShrink -ConfigFile \\share\repo\prod.json ``` Runs all of the checks tagged Database except for the AutoShrink check against the SQL Instances set in the config under app.sqlinstance Imports configuration file, \\\\share\repo\prod.json, prior to executing checks. ### EXAMPLE 4 ``` # Set the servers you'll be working with Set-DbcConfig -Name app.sqlinstance -Value sql2016, sql2017, sql2008, sql2008\express Set-DbcConfig -Name app.computername -Value sql2016, sql2017, sql2008 ``` # Look at the current configs Get-DbcConfig # Invoke a few tests Invoke-DbcCheck -Tags SuspectPage, LastBackup Runs the Suspect Pages and Last Backup checks against the SQL Instances sql2016, sql2017, sql2008, sql2008\express after setting them in the configuration ### EXAMPLE 5 ``` Invoke-DbcCheck -SqlInstance sql2017 -Tags SuspectPage, LastBackup -Show Summary -PassThru | Update-DbcPowerBiDataSource ``` Start-DbcPowerBi Runs the Suspect Page and Last Backup checks against the SQL Instances set in the config under app.sqlinstance only showing the summary of the results of the checks. It then updates the source json for the XML which is stored at C:\Windows\temp\dbachecks\ and then opens the PowerBi report in PowerBi Desktop ### EXAMPLE 6 ``` Get-Help -Name Invoke-Pester -Examples ``` Want to get super deep? You can look at Invoke-Pester's example's and run them against Invoke-DbcCheck since it's a wrapper. https://github.com/pester/Pester/wiki/Invoke-Pester Describe about_Pester ## PARAMETERS ### -Script Get-Help -Name Invoke-Pester -Parameter Script ```yaml Type: Object[] Parameter Sets: (All) Aliases: Path, relative_path Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -TestName Get-Help -Name Invoke-Pester -Parameter TestName ```yaml Type: String[] Parameter Sets: (All) Aliases: Name Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -EnableExit Get-Help -Name Invoke-Pester -Parameter EnableExit ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -Check Runs only tests in Describe blocks with the specified Tag parameter values. Wildcard characters and Tag values that include spaces or whitespace characters are not supported. When you specify multiple Tag values, Invoke-DbcCheck runs tests that have any of the listed tags (it ORs the tags). However, when you specify TestName and Tag values, Invoke-DbcCheck runs only describe blocks that have one of the specified TestName values and one of the specified Tag values. If you use both Tag and ExcludeTag, ExcludeTag takes precedence. ```yaml Type: String[] Parameter Sets: (All) Aliases: Tags, Tag, Checks Required: False Position: 1 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ExcludeCheck Omits tests in Describe blocks with the specified Tag parameter values. Wildcard characters and Tag values that include spaces or whitespace characters are not supported. When you specify multiple ExcludeTag values, Invoke-DbcCheck omits tests that have any of the listed tags (it ORs the tags). However, when you specify TestName and ExcludeTag values, Invoke-DbcCheck omits only describe blocks that have one of the specified TestName values and one of the specified Tag values. If you use both Tag and ExcludeTag, ExcludeTag takes precedence ```yaml Type: String[] Parameter Sets: (All) Aliases: ExcludeTags, ExcludeTag, ExcludeChecks Required: False Position: Named Default value: (Get-PSFConfigValue -FullName 'dbachecks.command.invokedbccheck.excludecheck' -Fallback @()) Accept pipeline input: False Accept wildcard characters: False ``` ### -PassThru Returns a custom object (PSCustomObject) that contains the test results. By default, Invoke-DbcCheck writes to the host program, not to the output stream (stdout). If you try to save the result in a variable, the variable is empty unless you use the PassThru parameter. To suppress the host output, use the Quiet parameter. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -SqlInstance A list of SQL Servers to run the tests against. If this is not provided, it will be gathered from: Get-DbatoolsConfig -Name app.sqlinstance ```yaml Type: DbaInstanceParameter[] Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ComputerName A list of computers to run the tests against. If this is not provided, it will be gathered from: Get-DbatoolsConfig -Name app.computername ```yaml Type: DbaInstanceParameter[] Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -SqlCredential Alternate SQL Server-based credential. ```yaml Type: PSCredential Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Credential Alternate Windows credential. ```yaml Type: PSCredential Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Database A list of databases to include if your check is database centric. ```yaml Type: Object[] Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ExcludeDatabase A list of databases to exclude if your check is database centric. ```yaml Type: Object[] Parameter Sets: (All) Aliases: Required: False Position: Named Default value: (Get-PSFConfigValue -FullName 'dbachecks.command.invokedbccheck.excludedatabase' -Fallback @()) Accept pipeline input: False Accept wildcard characters: False ``` ### -Value A value.. it's hard to explain ```yaml Type: String[] Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigFile The path to the exported dbachecks config file. ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -CodeCoverage Get-Help -Name Invoke-Pester -Parameter CodeCoverage ```yaml Type: Object[] Parameter Sets: (All) Aliases: Required: False Position: Named Default value: @() Accept pipeline input: False Accept wildcard characters: False ``` ### -CodeCoverageOutputFile Get-Help -Name Invoke-Pester -Parameter CodeCoverageOutputFile ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -CodeCoverageOutputFileFormat Get-Help -Name Invoke-Pester -Parameter CodeCoverageOutputFileFormat ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: Named Default value: JaCoCo Accept pipeline input: False Accept wildcard characters: False ``` ### -Strict Makes Pending and Skipped tests to Failed tests. Useful for continuous integration where you need to make sure all tests passed. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -OutputFile Get-Help -Name Invoke-Pester -Parameter OutputFile ```yaml Type: String Parameter Sets: NewOutputSet Aliases: Required: True Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -OutputFormat The format of output. Currently, only NUnitXML is supported. ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -AllChecks In the unlikely event that you'd like to run all checks, specify -AllChecks. These checks still confirm to the skip settings in Get-DbcConfig. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -Quiet The parameter Quiet is deprecated since Pester v. 4.0 and will be deleted in the next major version of Pester. Please use the parameter Show with value 'None' instead. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -PesterOption Get-Help -Name Invoke-Pester -Parameter PesterOption ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Show Customizes the output Pester writes to the screen. Available options are None Default Passed Failed Pending Skipped Inconclusive Describe Context Summary Header All Fails The options can be combined to define presets. Common use cases are: None - to write no output to the screen. All - to write all available information (this is default option). Fails - to write everything except Passed (but including Describes etc.). A common setting is also Failed, Summary, to write only failed tests and test summary. This parameter does not affect the PassThru custom object or the XML output that is written when you use the Output parameters. ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: Named Default value: All Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAgentAlertJob {{ Fill ConfigAgentAlertJob Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAgentAlertMessageid {{ Fill ConfigAgentAlertMessageid Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAgentAlertNotification {{ Fill ConfigAgentAlertNotification Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAgentAlertSeverity {{ Fill ConfigAgentAlertSeverity Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAgentDatabasemailprofile {{ Fill ConfigAgentDatabasemailprofile Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAgentDbaoperatoremail {{ Fill ConfigAgentDbaoperatoremail Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAgentDbaoperatorname {{ Fill ConfigAgentDbaoperatorname Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAgentFailedjobExcludecancelled {{ Fill ConfigAgentFailedjobExcludecancelled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAgentFailedjobSince {{ Fill ConfigAgentFailedjobSince Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAgentFailsafeoperator {{ Fill ConfigAgentFailsafeoperator Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAgentHistoryMaximumhistoryrows {{ Fill ConfigAgentHistoryMaximumhistoryrows Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAgentHistoryMaximumjobhistoryrows {{ Fill ConfigAgentHistoryMaximumjobhistoryrows Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAgentLastjobruntimePercentage {{ Fill ConfigAgentLastjobruntimePercentage Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAgentLongrunningjobPercentage {{ Fill ConfigAgentLongrunningjobPercentage Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAgentValidjobownerName {{ Fill ConfigAgentValidjobownerName Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAppCheckrepos {{ Fill ConfigAppCheckrepos Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAppCluster {{ Fill ConfigAppCluster Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAppComputername {{ Fill ConfigAppComputername Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAppLocalapp {{ Fill ConfigAppLocalapp Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAppMaildirectory {{ Fill ConfigAppMaildirectory Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAppSqlcredential {{ Fill ConfigAppSqlcredential Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAppSqlinstance {{ Fill ConfigAppSqlinstance Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigAppWincredential {{ Fill ConfigAppWincredential Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigCommandInvokedbccheckExcludecheck {{ Fill ConfigCommandInvokedbccheckExcludecheck Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigCommandInvokedbccheckExcludedatabases {{ Fill ConfigCommandInvokedbccheckExcludedatabases Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigDatabaseExists {{ Fill ConfigDatabaseExists Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigDatabaseQuerystoredisabledExcludedb {{ Fill ConfigDatabaseQuerystoredisabledExcludedb Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigDatabaseQuerystoreenabledExcludedb {{ Fill ConfigDatabaseQuerystoreenabledExcludedb Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigDomainDomaincontroller {{ Fill ConfigDomainDomaincontroller Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigDomainName {{ Fill ConfigDomainName Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigDomainOrganizationalunit {{ Fill ConfigDomainOrganizationalunit Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigGlobalNotcontactable {{ Fill ConfigGlobalNotcontactable Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigMailFailurethreshhold {{ Fill ConfigMailFailurethreshhold Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigMailFrom {{ Fill ConfigMailFrom Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigMailSmtpserver {{ Fill ConfigMailSmtpserver Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigMailSubject {{ Fill ConfigMailSubject Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigMailTo {{ Fill ConfigMailTo Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigOlaJobNameCommandLogCleanup {{ Fill ConfigOlaJobNameCommandLogCleanup Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigOlaJobNameDeleteBackupHistory {{ Fill ConfigOlaJobNameDeleteBackupHistory Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigOlaJobNameOutputFileCleanup {{ Fill ConfigOlaJobNameOutputFileCleanup Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigOlaJobNamePurgeBackupHistory {{ Fill ConfigOlaJobNamePurgeBackupHistory Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigOlaJobNameSystemFull {{ Fill ConfigOlaJobNameSystemFull Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigOlaJobNameSystemIntegrity {{ Fill ConfigOlaJobNameSystemIntegrity Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigOlaJobNameUserDiff {{ Fill ConfigOlaJobNameUserDiff Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigOlaJobNameUserFull {{ Fill ConfigOlaJobNameUserFull Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigOlaJobNameUserIndex {{ Fill ConfigOlaJobNameUserIndex Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigOlaJobNameUserIntegrity {{ Fill ConfigOlaJobNameUserIntegrity Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigOlaJobNameUserLog {{ Fill ConfigOlaJobNameUserLog Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyAdlogingroupExcludecheck {{ Fill ConfigPolicyAdlogingroupExcludecheck Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyAdloginuserExcludecheck {{ Fill ConfigPolicyAdloginuserExcludecheck Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyBackupDatadir {{ Fill ConfigPolicyBackupDatadir Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyBackupDefaultbackupcompression {{ Fill ConfigPolicyBackupDefaultbackupcompression Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyBackupDiffmaxhours {{ Fill ConfigPolicyBackupDiffmaxhours Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyBackupFullmaxdays {{ Fill ConfigPolicyBackupFullmaxdays Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyBackupLogdir {{ Fill ConfigPolicyBackupLogdir Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyBackupLogmaxminutes {{ Fill ConfigPolicyBackupLogmaxminutes Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyBackupNewdbgraceperiod {{ Fill ConfigPolicyBackupNewdbgraceperiod Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyBackupTestserver {{ Fill ConfigPolicyBackupTestserver Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyBuildBehind {{ Fill ConfigPolicyBuildBehind Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyBuildWarningwindow {{ Fill ConfigPolicyBuildWarningwindow Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyCertificateexpirationExcludedb {{ Fill ConfigPolicyCertificateexpirationExcludedb Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyCertificateexpirationWarningwindow {{ Fill ConfigPolicyCertificateexpirationWarningwindow Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyClusterHostrecordttl {{ Fill ConfigPolicyClusterHostrecordttl Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyClusterNetworkProtocolsIPV4 {{ Fill ConfigPolicyClusterNetworkProtocolsIPV4 Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyClusterRegisterallprovidersIP {{ Fill ConfigPolicyClusterRegisterallprovidersIP Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyConnectionAuthscheme {{ Fill ConfigPolicyConnectionAuthscheme Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyConnectionPingcount {{ Fill ConfigPolicyConnectionPingcount Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyConnectionPingmaxms {{ Fill ConfigPolicyConnectionPingmaxms Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDacallowed {{ Fill ConfigPolicyDacallowed Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseAutoclose {{ Fill ConfigPolicyDatabaseAutoclose Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseAutocreatestatistics {{ Fill ConfigPolicyDatabaseAutocreatestatistics Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseAutoshrink {{ Fill ConfigPolicyDatabaseAutoshrink Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseAutoupdatestatistics {{ Fill ConfigPolicyDatabaseAutoupdatestatistics Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseAutoupdatestatisticsasynchronously {{ Fill ConfigPolicyDatabaseAutoupdatestatisticsasynchronously Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseClrassembliessafeexcludedb {{ Fill ConfigPolicyDatabaseClrassembliessafeexcludedb Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseDuplicateindexexcludedb {{ Fill ConfigPolicyDatabaseDuplicateindexexcludedb Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseFilebalancetolerance {{ Fill ConfigPolicyDatabaseFilebalancetolerance Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseFilegrowthdaystocheck {{ Fill ConfigPolicyDatabaseFilegrowthdaystocheck Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseFilegrowthexcludedb {{ Fill ConfigPolicyDatabaseFilegrowthexcludedb Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseFilegrowthfreespacethreshold {{ Fill ConfigPolicyDatabaseFilegrowthfreespacethreshold Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseFilegrowthtype {{ Fill ConfigPolicyDatabaseFilegrowthtype Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseFilegrowthvalue {{ Fill ConfigPolicyDatabaseFilegrowthvalue Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseLogfilecount {{ Fill ConfigPolicyDatabaseLogfilecount Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseLogfilepercentused {{ Fill ConfigPolicyDatabaseLogfilepercentused Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseLogfilesizecomparison {{ Fill ConfigPolicyDatabaseLogfilesizecomparison Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseLogfilesizepercentage {{ Fill ConfigPolicyDatabaseLogfilesizepercentage Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseMaxdop {{ Fill ConfigPolicyDatabaseMaxdop Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseMaxdopexcludedb {{ Fill ConfigPolicyDatabaseMaxdopexcludedb Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseMaxvlf {{ Fill ConfigPolicyDatabaseMaxvlf Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseStatusExcludeoffline {{ Fill ConfigPolicyDatabaseStatusExcludeoffline Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseStatusExcludereadonly {{ Fill ConfigPolicyDatabaseStatusExcludereadonly Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseStatusExcluderestoring {{ Fill ConfigPolicyDatabaseStatusExcluderestoring Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseTrustworthyexcludedb {{ Fill ConfigPolicyDatabaseTrustworthyexcludedb Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDatabaseWrongcollation {{ Fill ConfigPolicyDatabaseWrongcollation Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDbccMaxdays {{ Fill ConfigPolicyDbccMaxdays Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDiskspacePercentfree {{ Fill ConfigPolicyDiskspacePercentfree Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyDumpMaxcount {{ Fill ConfigPolicyDumpMaxcount Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyErrorlogLogcount {{ Fill ConfigPolicyErrorlogLogcount Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyErrorlogWarningwindow {{ Fill ConfigPolicyErrorlogWarningwindow Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyHadrAgtcpport {{ Fill ConfigPolicyHadrAgtcpport Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyHadrEndpointname {{ Fill ConfigPolicyHadrEndpointname Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyHadrEndpointport {{ Fill ConfigPolicyHadrEndpointport Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyHadrFailureconditionlevel {{ Fill ConfigPolicyHadrFailureconditionlevel Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyHadrHealthchecktimeout {{ Fill ConfigPolicyHadrHealthchecktimeout Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyHadrLeasetimeout {{ Fill ConfigPolicyHadrLeasetimeout Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyHadrSessiontimeout {{ Fill ConfigPolicyHadrSessiontimeout Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyHadrTcpport {{ Fill ConfigPolicyHadrTcpport Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyIdentityUsagepercent {{ Fill ConfigPolicyIdentityUsagepercent Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyInstancemaxdopExcludeinstance {{ Fill ConfigPolicyInstancemaxdopExcludeinstance Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyInstancemaxdopMaxdop {{ Fill ConfigPolicyInstancemaxdopMaxdop Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyInstancemaxdopUserecommended {{ Fill ConfigPolicyInstancemaxdopUserecommended Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyInstanceMemorydumpsdaystocheck {{ Fill ConfigPolicyInstanceMemorydumpsdaystocheck Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyInstanceSqlenginestart {{ Fill ConfigPolicyInstanceSqlenginestart Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyInstanceSqlenginestate {{ Fill ConfigPolicyInstanceSqlenginestate Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyInvaliddbownerExcludedb {{ Fill ConfigPolicyInvaliddbownerExcludedb Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyInvaliddbownerName {{ Fill ConfigPolicyInvaliddbownerName Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyNetworkLatencymaxms {{ Fill ConfigPolicyNetworkLatencymaxms Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaCommandLogCleanUp {{ Fill ConfigPolicyOlaCommandLogCleanUp Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaCommandLogenabled {{ Fill ConfigPolicyOlaCommandLogenabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaCommandLogscheduled {{ Fill ConfigPolicyOlaCommandLogscheduled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaDatabase {{ Fill ConfigPolicyOlaDatabase Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaDeleteBackupHistoryCleanUp {{ Fill ConfigPolicyOlaDeleteBackupHistoryCleanUp Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaDeleteBackupHistoryenabled {{ Fill ConfigPolicyOlaDeleteBackupHistoryenabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaDeleteBackupHistoryscheduled {{ Fill ConfigPolicyOlaDeleteBackupHistoryscheduled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaInstalled {{ Fill ConfigPolicyOlaInstalled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaOutputFileCleanUp {{ Fill ConfigPolicyOlaOutputFileCleanUp Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaOutputFileCleanupenabled {{ Fill ConfigPolicyOlaOutputFileCleanupenabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaOutputFileCleanupscheduled {{ Fill ConfigPolicyOlaOutputFileCleanupscheduled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaPurgeJobHistoryCleanUp {{ Fill ConfigPolicyOlaPurgeJobHistoryCleanUp Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaPurgeJobHistoryenabled {{ Fill ConfigPolicyOlaPurgeJobHistoryenabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaPurgeJobHistoryscheduled {{ Fill ConfigPolicyOlaPurgeJobHistoryscheduled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaSystemfullenabled {{ Fill ConfigPolicyOlaSystemfullenabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaSystemfullretention {{ Fill ConfigPolicyOlaSystemfullretention Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaSystemfullscheduled {{ Fill ConfigPolicyOlaSystemfullscheduled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaSystemIntegrityCheckenabled {{ Fill ConfigPolicyOlaSystemIntegrityCheckenabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaSystemIntegrityCheckscheduled {{ Fill ConfigPolicyOlaSystemIntegrityCheckscheduled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaUserdiffenabled {{ Fill ConfigPolicyOlaUserdiffenabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaUserdiffretention {{ Fill ConfigPolicyOlaUserdiffretention Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaUserdiffscheduled {{ Fill ConfigPolicyOlaUserdiffscheduled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaUserfullenabled {{ Fill ConfigPolicyOlaUserfullenabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaUserfullretention {{ Fill ConfigPolicyOlaUserfullretention Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaUserfullscheduled {{ Fill ConfigPolicyOlaUserfullscheduled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaUserIndexOptimizeenabled {{ Fill ConfigPolicyOlaUserIndexOptimizeenabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaUserIndexOptimizescheduled {{ Fill ConfigPolicyOlaUserIndexOptimizescheduled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaUserIntegrityCheckenabled {{ Fill ConfigPolicyOlaUserIntegrityCheckenabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaUserIntegrityCheckscheduled {{ Fill ConfigPolicyOlaUserIntegrityCheckscheduled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaUserlogenabled {{ Fill ConfigPolicyOlaUserlogenabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaUserlogretention {{ Fill ConfigPolicyOlaUserlogretention Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOlaUserlogscheduled {{ Fill ConfigPolicyOlaUserlogscheduled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyOleautomation {{ Fill ConfigPolicyOleautomation Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyPageverify {{ Fill ConfigPolicyPageverify Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyRecoverymodelExcludedb {{ Fill ConfigPolicyRecoverymodelExcludedb Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyRecoverymodelType {{ Fill ConfigPolicyRecoverymodelType Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicySecurityAdhocdistributedqueriesenabled {{ Fill ConfigPolicySecurityAdhocdistributedqueriesenabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicySecurityClrenabled {{ Fill ConfigPolicySecurityClrenabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicySecurityContainedbautoclose {{ Fill ConfigPolicySecurityContainedbautoclose Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicySecurityCrossdbownershipchaining {{ Fill ConfigPolicySecurityCrossdbownershipchaining Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicySecurityDatabasemailenabled {{ Fill ConfigPolicySecurityDatabasemailenabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicySecurityLatestbuild {{ Fill ConfigPolicySecurityLatestbuild Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicySecurityOleautomationproceduresdisabled {{ Fill ConfigPolicySecurityOleautomationproceduresdisabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicySecurityRemoteaccessdisabled {{ Fill ConfigPolicySecurityRemoteaccessdisabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicySecurityScanforstartupproceduresdisabled {{ Fill ConfigPolicySecurityScanforstartupproceduresdisabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicySecurityXpcmdshelldisabled {{ Fill ConfigPolicySecurityXpcmdshelldisabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyServerCpuprioritisation {{ Fill ConfigPolicyServerCpuprioritisation Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyServerExcludeDiskAllocationUnit {{ Fill ConfigPolicyServerExcludeDiskAllocationUnit Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyStorageBackuppath {{ Fill ConfigPolicyStorageBackuppath Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicySuspectpagesThreshold {{ Fill ConfigPolicySuspectpagesThreshold Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyTraceflagsExpected {{ Fill ConfigPolicyTraceflagsExpected Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyTraceflagsNotexpected {{ Fill ConfigPolicyTraceflagsNotexpected Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyTwodigityearcutoff {{ Fill ConfigPolicyTwodigityearcutoff Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyValiddbownerExcludedb {{ Fill ConfigPolicyValiddbownerExcludedb Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyValiddbownerName {{ Fill ConfigPolicyValiddbownerName Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyWhoisactiveDatabase {{ Fill ConfigPolicyWhoisactiveDatabase Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyXeventRequiredrunningsession {{ Fill ConfigPolicyXeventRequiredrunningsession Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyXeventRequiredstoppedsession {{ Fill ConfigPolicyXeventRequiredstoppedsession Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigPolicyXeventValidrunningsession {{ Fill ConfigPolicyXeventValidrunningsession Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipAgentAlert {{ Fill ConfigSkipAgentAlert Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipAgentLastjobruntime {{ Fill ConfigSkipAgentLastjobruntime Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipAgentLongrunningjobs {{ Fill ConfigSkipAgentLongrunningjobs Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipBackupReadonly {{ Fill ConfigSkipBackupReadonly Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipBackupSecondaries {{ Fill ConfigSkipBackupSecondaries Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipBackupTesting {{ Fill ConfigSkipBackupTesting Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipClusterNetclusterinterface {{ Fill ConfigSkipClusterNetclusterinterface Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipConnectionAuth {{ Fill ConfigSkipConnectionAuth Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipConnectionPing {{ Fill ConfigSkipConnectionPing Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipConnectionRemoting {{ Fill ConfigSkipConnectionRemoting Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipDatabaseFilegrowthdisabled {{ Fill ConfigSkipDatabaseFilegrowthdisabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipDatabaseLogfilecounttest {{ Fill ConfigSkipDatabaseLogfilecounttest Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipDatafilegrowthdisabled {{ Fill ConfigSkipDatafilegrowthdisabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipDbccDatapuritycheck {{ Fill ConfigSkipDbccDatapuritycheck Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipDiffbackuptest {{ Fill ConfigSkipDiffbackuptest Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipHadrListenerPingcheck {{ Fill ConfigSkipHadrListenerPingcheck Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipHadrListenerTcpport {{ Fill ConfigSkipHadrListenerTcpport Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipHadrReplicaTcpport {{ Fill ConfigSkipHadrReplicaTcpport Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipInstanceDefaulttrace {{ Fill ConfigSkipInstanceDefaulttrace Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipInstanceLatestbuild {{ Fill ConfigSkipInstanceLatestbuild Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipInstanceModeldbgrowth {{ Fill ConfigSkipInstanceModeldbgrowth Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipInstanceOleautomationproceduresdisabled {{ Fill ConfigSkipInstanceOleautomationproceduresdisabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipInstanceRemoteaccessdisabled {{ Fill ConfigSkipInstanceRemoteaccessdisabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipInstanceScanforstartupproceduresdisabled {{ Fill ConfigSkipInstanceScanforstartupproceduresdisabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipInstanceSuspectpagelimit {{ Fill ConfigSkipInstanceSuspectpagelimit Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipLogfilecounttest {{ Fill ConfigSkipLogfilecounttest Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipLogshiptesting {{ Fill ConfigSkipLogshiptesting Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityAgentserviceadmin {{ Fill ConfigSkipSecurityAgentserviceadmin Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityAsymmetrickeysize {{ Fill ConfigSkipSecurityAsymmetrickeysize Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityBuiltinadmin {{ Fill ConfigSkipSecurityBuiltinadmin Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityClrassembliessafe {{ Fill ConfigSkipSecurityClrassembliessafe Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityContainedbautoclose {{ Fill ConfigSkipSecurityContainedbautoclose Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityContainedDBSQLAuth {{ Fill ConfigSkipSecurityContainedDBSQLAuth Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityEngineserviceadmin {{ Fill ConfigSkipSecurityEngineserviceadmin Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityFulltextserviceadmin {{ Fill ConfigSkipSecurityFulltextserviceadmin Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityGuestuserconnect {{ Fill ConfigSkipSecurityGuestuserconnect Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityHideinstance {{ Fill ConfigSkipSecurityHideinstance Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityLocalwindowsgroup {{ Fill ConfigSkipSecurityLocalwindowsgroup Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityLoginauditlevelfailed {{ Fill ConfigSkipSecurityLoginauditlevelfailed Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityLoginauditlevelsuccessful {{ Fill ConfigSkipSecurityLoginauditlevelsuccessful Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityLoginCheckPolicy {{ Fill ConfigSkipSecurityLoginCheckPolicy Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityLoginMustChange {{ Fill ConfigSkipSecurityLoginMustChange Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityLoginPasswordExpiration {{ Fill ConfigSkipSecurityLoginPasswordExpiration Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityNonstandardport {{ Fill ConfigSkipSecurityNonstandardport Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityPublicPermission {{ Fill ConfigSkipSecurityPublicPermission Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityPublicrolepermission {{ Fill ConfigSkipSecurityPublicrolepermission Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityQuerystoredisabled {{ Fill ConfigSkipSecurityQuerystoredisabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityQuerystoreenabled {{ Fill ConfigSkipSecurityQuerystoreenabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecuritySadisabled {{ Fill ConfigSkipSecuritySadisabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecuritySaexist {{ Fill ConfigSkipSecuritySaexist Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecurityServerprotocol {{ Fill ConfigSkipSecurityServerprotocol Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecuritySqlagentproxiesnopublicrole {{ Fill ConfigSkipSecuritySqlagentproxiesnopublicrole Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecuritySQLMailXPsDisabled {{ Fill ConfigSkipSecuritySQLMailXPsDisabled Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipSecuritySymmetrickeyencryptionlevel {{ Fill ConfigSkipSecuritySymmetrickeyencryptionlevel Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipTempdb1118 {{ Fill ConfigSkipTempdb1118 Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipTempdbfilecount {{ Fill ConfigSkipTempdbfilecount Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipTempdbfilegrowthpercent {{ Fill ConfigSkipTempdbfilegrowthpercent Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipTempdbfilesizemax {{ Fill ConfigSkipTempdbfilesizemax Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigSkipTempdbfilesonc {{ Fill ConfigSkipTempdbfilesonc Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -ConfigTestingIntegrationInstance {{ Fill ConfigTestingIntegrationInstance Description }} ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ## NOTES ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Invoke-DbcCheck/](https://dbachecks.readthedocs.io/en/latest/functions/Invoke-DbcCheck/) ================================================ FILE: docs/functions/Invoke-DbcConfigFile.md ================================================ # Invoke-DbcConfigFile ## SYNOPSIS Opens the default location of the json config file for easy edits. ## SYNTAX ``` Invoke-DbcConfigFile [[-Path] ] [-EnableException] [] ``` ## DESCRIPTION Opens the default location of the json config file for easy edits. Follow with Import-DbcConfig to import changes. ## EXAMPLES ### EXAMPLE 1 ``` Invoke-DbcConfigFile ``` Opens "$script:localapp\config.json" for editing. Follow with Import-DbcConfig. ## PARAMETERS ### -Path The path to open, by default is "$script:localapp\config.json" ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 1 Default value: "$script:localapp\config.json" Accept pipeline input: False Accept wildcard characters: False ``` ### -EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ## NOTES ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Invoke-DbcConfigFile/](https://dbachecks.readthedocs.io/en/latest/functions/Invoke-DbcConfigFile/) ================================================ FILE: docs/functions/Reset-DbcConfig.md ================================================ # Reset-DbcConfig ## SYNOPSIS Resets configuration entries to their default values. ## SYNTAX ``` Reset-DbcConfig [[-Name] ] [] ``` ## DESCRIPTION This function unregisters configuration values and then registers them back with the default values and type. This can be used to get the dbachecks back to default state of configuration, or to resolve problems with a specific setting. ## EXAMPLES ### EXAMPLE 1 ``` Reset-DbcConfig ``` Resets all the configuration values for dbachecks. ### EXAMPLE 2 ``` Reset-DbcConfig -Name policy.recoverymodel.type ``` Resets the policy.recoverymodel.type to the default value and type. ## PARAMETERS ### -Name Name of the configuration key. ```yaml Type: String[] Parameter Sets: (All) Aliases: Required: False Position: 1 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ## NOTES ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Reset-DbcConfig/](https://dbachecks.readthedocs.io/en/latest/functions/Reset-DbcConfig/) ================================================ FILE: docs/functions/Save-DbcRequiredModules.md ================================================ # Save-DbcRequiredModules ## SYNOPSIS Saves all required modules, including dbachecks, dbatools, Pester and PSFramework to a directory. Ideal for offline installs. ## SYNTAX ``` Save-DbcRequiredModules [-Path] [-EnableException] [] ``` ## DESCRIPTION Saves all required modules, including dbachecks, dbatools, Pester and PSFramework to a directory. Ideal for offline installs. ## EXAMPLES ### EXAMPLE 1 ``` Save-DbcRequiredModules -Path C:\temp\downlaods ``` Saves all required modules and dbachecks to C:\temp\downloads ## PARAMETERS ### -Path The directory where the modules will be saved. Directory will be created if it does not exist. ```yaml Type: String Parameter Sets: (All) Aliases: Required: True Position: 1 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ## NOTES ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Save-DbcRequiredModules/](https://dbachecks.readthedocs.io/en/latest/functions/Save-DbcRequiredModules/) ================================================ FILE: docs/functions/Set-DbcCisConfig.md ================================================ # Set-DbcCisConfig ## SYNOPSIS Sets values for CIS checks. ## SYNTAX ``` Set-DbcCisConfig [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION Sets CIS checks to defaults values that were different than normals values. Then sets CIS test that are set to skip by default to run. ## EXAMPLES ### EXAMPLE 1 ``` Set-DbcCisConfig ``` sets the configuration for CIS checks ## PARAMETERS ### -WhatIf Shows what would happen if the cmdlet runs. The cmdlet is not run. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: wi Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Confirm Prompts you for confirmation before running the cmdlet. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: cf Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ## NOTES ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Set-DbcCisConfig/](https://dbachecks.readthedocs.io/en/latest/functions/Set-DbcCisConfig/) ================================================ FILE: docs/functions/Set-DbcConfig.md ================================================ # Set-DbcConfig ## SYNOPSIS Sets configuration values for specific checks. ## SYNTAX ``` Set-DbcConfig [[-Name] ] [[-Value] ] [[-Handler] ] [-Append] [-Temporary] [-EnableException] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION Changes configuration values which enable each check to have specific thresholds ## EXAMPLES ### EXAMPLE 1 ``` Set-DbcConfig -Name app.sqlinstance -Value sql2016, sql2017, sqlcluster ``` Sets the SQL Instances which will be checked by default using Invoke-DbcCheck to sql2016, sql2017, sqlcluster ### EXAMPLE 2 ``` Set-DbcConfig -Name policy.validdbowner.name -Value 'TheBeard\sqldbowner' ``` Sets the value of the configuration for the expected database owners to TheBeard\sqldbowner ### EXAMPLE 3 ``` Set-DbcConfig -Name policy.database.status.excludereadonly -Value 'TheBeard' ``` Sets the value of the configuration for databases that are expected to be readonly to TheBeard ### EXAMPLE 4 ``` Set-DbcConfig -Name agent.validjobowner.name -Value 'TheBeard\SQLJobOwner' -Append ``` Adds 'TheBeard\SQLJobOwner' to the value of the configuration for accounts that are expected to be owners of SQL Agent Jobs ## PARAMETERS ### -Name Name of the configuration entry. ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 1 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Value The value to assign. ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: 2 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Handler A scriptblock that is executed when a value is being set. Is only executed if the validation was successful (assuming there was a validation, of course) ```yaml Type: ScriptBlock Parameter Sets: (All) Aliases: Required: False Position: 3 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Append Adds the value to the existing configuration instead of overwriting it ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -Temporary The setting is not persisted outside the current session. By default, settings will be remembered across all powershell sessions. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -WhatIf Shows what would happen if the cmdlet runs. The cmdlet is not run. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: wi Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Confirm Prompts you for confirmation before running the cmdlet. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: cf Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ## NOTES ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Set-DbcConfig/](https://dbachecks.readthedocs.io/en/latest/functions/Set-DbcConfig/) ================================================ FILE: docs/functions/Set-DbcFile.md ================================================ # Set-DbcFile ## SYNOPSIS Writes the result of Invoke-DbcCheck to a file (after converting with Convert-DbcResult) ## SYNTAX ### Default (Default) ``` Set-DbcFile -InputObject -FilePath -FileName -FileType [-WhatIf] [-Confirm] [] ``` ### Force ``` Set-DbcFile -InputObject -FilePath -FileName -FileType [-Force] [-WhatIf] [-Confirm] [] ``` ### Append ``` Set-DbcFile -InputObject -FilePath -FileName -FileType [-Append] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION When a check has been run with Invoke-DbcCheck (and -PassThru) and then converted with Convert-DbcResult This command will write the results to a CSV, JSON or XML file ## EXAMPLES ### EXAMPLE 1 ``` $Date = Get-Date -Format "yyyy-MM-dd" Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Set-DbcFile -FilePath C:\temp\dbachecks\ -FileName Auto-close_$Date -FileType xml ``` Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and outputs to xml and saves in C:\temp\dbachecks\Auto-close_DATE.xml ### EXAMPLE 2 ``` Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Set-DbcFile -FilePath C:\temp\dbachecks\ -FileName Auto-close.xml -FileType xml ``` Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and outputs to xml and saves in C:\temp\dbachecks\Auto-close.xml ### EXAMPLE 3 ``` Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Set-DbcFile -FilePath C:\temp\dbachecks\ -FileName Auto-close.csv -FileType csv ``` Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and outputs to csv and saves in C:\temp\dbachecks\Auto-close.csv ### EXAMPLE 4 ``` Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Set-DbcFile -FilePath C:\temp\dbachecks\ -FileName Auto-close.json -FileType Json ``` Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and outputs to JSON and saves in C:\temp\dbachecks\Auto-close.json ### EXAMPLE 5 ``` Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Set-DbcFile -FilePath C:\temp\dbachecks\ -FileName Auto-close.json -FileType Json -Append ``` Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and outputs to JSON and saves in C:\temp\dbachecks\Auto-close.json appending the results to the existing file ### EXAMPLE 6 ``` Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Set-DbcFile -FilePath C:\temp\dbachecks\ -FileName Auto-close.json -FileType Json -Force ``` Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and outputs to JSON and saves in C:\temp\dbachecks\Auto-close.json overwriting the existing file ## PARAMETERS ### -InputObject The datatable created by Convert-DbcResult ```yaml Type: Object Parameter Sets: (All) Aliases: Required: True Position: Named Default value: None Accept pipeline input: True (ByValue) Accept wildcard characters: False ``` ### -FilePath The directory for the file ```yaml Type: String Parameter Sets: (All) Aliases: Required: True Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -FileName The name of the file ```yaml Type: String Parameter Sets: (All) Aliases: Required: True Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -FileType The type of file -CSV,JSON,XML ```yaml Type: String Parameter Sets: (All) Aliases: Required: True Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Append Add to an existing file or not ```yaml Type: SwitchParameter Parameter Sets: Append Aliases: Required: True Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -Force Overwrite Existing file ```yaml Type: SwitchParameter Parameter Sets: Force Aliases: Required: True Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -WhatIf Shows what would happen if the cmdlet runs. The cmdlet is not run. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: wi Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Confirm Prompts you for confirmation before running the cmdlet. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: cf Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ### System.String ## NOTES Initial - RMS 28/12/2019 ## RELATED LINKS ================================================ FILE: docs/functions/Start-DbcPowerBi.md ================================================ # Start-DbcPowerBi ## SYNOPSIS Launches one of the included dbachecks Power BI dashboards either the original for json files or the new one for database. **You will need refresh* the Power BI dashboard every time to see the new results! ## SYNTAX ``` Start-DbcPowerBi [-FromDatabase] [[-Path] ] [-EnableException] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION Launches one of the included dbachecks Power BI dashboards either the original for json files or the new one for database.**You will need refresh* the Power BI dashboard every time to see the new results. ## EXAMPLES ### EXAMPLE 1 ``` Start-DbcPowerBi -FromDatabase ``` Launches the Database Power Bi dashboard template, which will prompt for the Instance and database name ### EXAMPLE 2 ``` Start-DbcPowerBi ``` Launches the Json PowerBi from "$script:ModuleRoot\bin\dbachecks.pbix" using "C:\windows\Temp\dbachecks\*.json" (generated by Update-DbcPowerBiDataSource) as the datasource. ### EXAMPLE 3 ``` Start-DbcPowerBi -Path \\nas\projects\dbachecks.pbix ``` Launches \\\\nas\projects\dbachecks.pbix using "C:\windows\Temp\dbachecks\*.json" as the datasource ## PARAMETERS ### -FromDatabase A Switch to use to open the database based PowerBi dashboard if you have stored the results in a database with Write-DbcTable. If not chosen it will use the original Power Bi file with a json data source ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -Path The location of the pbix or pbit file if you have moved it or want to use your own. "$script:ModuleRoot\bin\dbachecks.pbix" or "$script:ModuleRoot\bin\dbachecks-FromDatabase.pbit" by default. ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 1 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -WhatIf Shows what would happen if the cmdlet runs. The cmdlet is not run. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: wi Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Confirm Prompts you for confirmation before running the cmdlet. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: cf Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ## NOTES ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Start-DbcPowerBi/](https://dbachecks.readthedocs.io/en/latest/functions/Start-DbcPowerBi/) ================================================ FILE: docs/functions/Update-DbcPowerBiDataSource.md ================================================ # Update-DbcPowerBiDataSource ## SYNOPSIS Converts Pester results and exports file in required format for launching the Power BI command. **You will need refresh* the Power BI dashboard every time to see the new results. ## SYNTAX ``` Update-DbcPowerBiDataSource [-InputObject] [[-Path] ] [[-FileName] ] [[-Environment] ] [-Force] [-EnableException] [-Append] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION Converts Pester results and exports file in required format for launching the Power BI command. **You will need refresh* the Power BI dashboard every time to see the new results. Basically, it does this: $InputObject.TestResult | Select-Object -First 20 | ConvertTo-Json -Depth 3 | Out-File "$env:windir\temp\dbachecks.json" ## EXAMPLES ### EXAMPLE 1 ``` Invoke-DbcCheck -SqlInstance $Instance -Check DatabaseStatus -Show None -PassThru | Update-DbcPowerBiDataSource ``` Runs the DatabaseStatus checks against $Instance then saves to json to $env:windir\temp\dbachecks\dbachecks_1_DatabaseStatus.json ### EXAMPLE 2 ``` Invoke-DbcCheck -SqlInstance $Instance -Check DatabaseStatus -Show None -PassThru | Update-DbcPowerBiDataSource -Path C:\Temp ``` Runs the DatabaseStatus checks against $Instance then saves to json to C:\Temp\dbachecks_1_DatabaseStatus.json ### EXAMPLE 3 ``` Invoke-DbcCheck -SqlInstance $Instance -Check DatabaseStatus -Show None -PassThru | Update-DbcPowerBiDataSource -Path C:\Temp -FileName BeardyTests ``` Runs the DatabaseStatus checks against $Instance then saves to json to C:\Temp\BeardyTests.json ### EXAMPLE 4 ``` Invoke-DbcCheck -SqlInstance $Instance -Check DatabaseStatus -Show None -PassThru | Update-DbcPowerBiDataSource -Path C:\Temp -FileName BeardyTests.json ``` Runs the DatabaseStatus checks against $Instance then saves to json to C:\Temp\BeardyTests.json ### EXAMPLE 5 ``` Invoke-DbcCheck -SqlInstance $Instance -Check DatabaseStatus -Show None -PassThru | Update-DbcPowerBiDataSource -Path C:\Temp -Environment Prod_DBChecks ``` Runs the DatabaseStatus checks against $Instance then saves to json to C:\Temp\dbachecks_1_Prod_DBChecks_DatabaseStatus.json ### EXAMPLE 6 ``` Invoke-DbcCheck -SqlInstance $Instance -Check DatabaseStatus -Show None -PassThru | Update-DbcPowerBiDataSource -Environment Prod_DBChecks ``` Runs the DatabaseStatus checks against $Instance then saves to json to C:\Windows\temp\dbachecks\dbachecks_1_Prod_DBChecks_DatabaseStatus.json ### EXAMPLE 7 ``` Invoke-DbcCheck -SqlInstance sql2017 -Tag Backup -Show Summary -PassThru | Update-DbcPowerBiDataSource -Path \\nas\projects\dbachecks.json Start-DbcPowerBi -Path \\nas\projects\dbachecks.json ``` Runs tests, saves to json to \\\\nas\projects\dbachecks.json Opens the PowerBi using that file then you'll have to change your data source in Power BI because by default it points to C:\Windows\Temp (limitation of Power BI) ### EXAMPLE 8 ``` Set-DbcConfig -Name app.checkrepos -Value \\SharedPath\CustomPesterChecks Invoke-DbcCheck -SqlInstance $Instance -Check DatabaseStatus, CustomCheckTag -PassThru | Update-DbcPowerBiDataSource -Path \\SharedPath\CheckResults -Name CustomCheckResults -Append ``` Because we are using a custom check repository you MUSTR use the Append parameter for Update-DbcPowerBiDataSource otherwise the json file will be overwritten Sets the custom check repository to \\\\SharedPath\CustomPesterChecks Runs the DatabaseStatus checks and custom checks with the CustomCheckTag against $Instance then saves all the results to json to \\\\SharedPath\CheckResults.json -Name CustomCheckResults ### EXAMPLE 9 ``` Invoke-DbcCheck -SqlInstance sql2017 -Check SuspectPage -Show None -PassThru | Update-DbcPowerBiDataSource -Environment Test -Whatif ``` What if: Performing the operation "Removing .json files named *Default*" on target "C:\Windows\temp\dbachecks". What if: Performing the operation "Passing results" on target "C:\Windows\temp\dbachecks\dbachecks_1_Test__SuspectPage.json". Will not actually create or update the data sources but will output what happens with the command and what the file name will be called. ## PARAMETERS ### -InputObject Required. Resultset from Invoke-DbcCheck. If InputObject is not provided, it will be generated using a very generic resultset: ```yaml Type: PSObject Parameter Sets: (All) Aliases: Required: True Position: 1 Default value: None Accept pipeline input: True (ByValue) Accept wildcard characters: False ``` ### -Path The directory to store your JSON files. "C:\windows\temp\dbachecks\*.json" by default ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 2 Default value: "$env:windir\temp\dbachecks" Accept pipeline input: False Accept wildcard characters: False ``` ### -FileName if you want to give the file a specific name ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 3 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Environment A Name to give your suite of tests IE Prod - This will also alter the name of the file ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 4 Default value: Default Accept pipeline input: False Accept wildcard characters: False ``` ### -Force Delete all json files in the data source folder. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -Append Appends results to existing file. Use this if you have custom check repos ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -WhatIf Shows what would happen if the cmdlet runs. The cmdlet is not run. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: wi Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Confirm Prompts you for confirmation before running the cmdlet. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: cf Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ## NOTES ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Update-DbcPowerBiDataSource/](https://dbachecks.readthedocs.io/en/latest/functions/Update-DbcPowerBiDataSource/) ================================================ FILE: docs/functions/Update-DbcRequiredModules.md ================================================ # Update-DbcRequiredModules ## SYNOPSIS Updates all required modules, including dbachecks. ## SYNTAX ``` Update-DbcRequiredModules [-EnableException] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION Updates all required modules, including dbachecks. ## EXAMPLES ### EXAMPLE 1 ``` Update-DbcRequiredModules ``` Updates all required modules including dbachecks ## PARAMETERS ### -EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -WhatIf Shows what would happen if the cmdlet runs. The cmdlet is not run. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: wi Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Confirm Prompts you for confirmation before running the cmdlet. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: cf Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ## NOTES ## RELATED LINKS [https://dbachecks.readthedocs.io/en/latest/functions/Update-DbcRequiredModules/](https://dbachecks.readthedocs.io/en/latest/functions/Update-DbcRequiredModules/) ================================================ FILE: docs/functions/Write-DbcTable.md ================================================ # Write-DbcTable ## SYNOPSIS Writes the result of Invoke-DbcCheck (with -PassThru) after Convert-DbcResult to a database table ## SYNTAX ``` Write-DbcTable [-SqlInstance] [[-SqlCredential] ] [[-Database] ] [-InputObject] [[-Table] ] [[-Schema] ] [-Truncate] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION After running Invoke-DbcCheck (With PassThru) and converting it to a datatable with Convert-DbcResult, this command will write the results to a database table and will also write the current Checks to another table called dbachecksChecks ## EXAMPLES ### EXAMPLE 1 ``` Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Write-DbcTable -SqlInstance sql2017n5 -Database tempdb -Table newdbachecks ``` Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and writes it to a table newdbachecks in tempdb on SQL2017N5 (NB Don't use tempdb!!) ## PARAMETERS ### -SqlInstance The Instance for the results ```yaml Type: String Parameter Sets: (All) Aliases: Required: True Position: 1 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -SqlCredential The SQL Credential for the instance if required ```yaml Type: PSCredential Parameter Sets: (All) Aliases: Required: False Position: 2 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Database The database to write the results ```yaml Type: Object Parameter Sets: (All) Aliases: Required: False Position: 3 Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -InputObject The datatable from Convert-DbcResult ```yaml Type: Object Parameter Sets: (All) Aliases: Required: True Position: 4 Default value: None Accept pipeline input: True (ByValue) Accept wildcard characters: False ``` ### -Table The name of the table for the results - will be created if it doesn't exist. By default it will be named CheckResults ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 5 Default value: CheckResults Accept pipeline input: False Accept wildcard characters: False ``` ### -Schema The schema for the table - defaults to dbo ```yaml Type: String Parameter Sets: (All) Aliases: Required: False Position: 6 Default value: Dbo Accept pipeline input: False Accept wildcard characters: False ``` ### -Truncate Will truncate the existing table (if results go to a staging table for example) ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: Required: False Position: Named Default value: False Accept pipeline input: False Accept wildcard characters: False ``` ### -WhatIf Shows what would happen if the cmdlet runs. The cmdlet is not run. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: wi Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### -Confirm Prompts you for confirmation before running the cmdlet. ```yaml Type: SwitchParameter Parameter Sets: (All) Aliases: cf Required: False Position: Named Default value: None Accept pipeline input: False Accept wildcard characters: False ``` ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). ## INPUTS ## OUTPUTS ### System.String ## NOTES Initial - RMS 28/12/2019 ## RELATED LINKS ================================================ FILE: docs/index.md ================================================ # dbachecks dbachecks is a framework created by and for SQL Server pros who need to validate their environments. Basically, we all share similar checklists and mostly just the server names and RPO/RTO/etc change. This open source module allows us to crowdsource our checklists using [Pester](https://github.com/Pester/Pester) tests. Such checks include: * Backups are being performed * Identity columns are not about to max out * Servers have access to backup paths * Database integrity checks are being performed and corruption does not exist * Disk space is not about to run out * All enabled jobs have succeeded Have questions about development? Please visit our [Wiki](https://github.com/sqlcollaborative/dbachecks/wiki). **Anyone developing this module** should visit that Wiki page (after fully reading this readme) for a brief overview. ## Build Status
Development Branch Build - Unit testing Click Here
Main Branch Build - Module version update and Code Signing Click Here
Main Branch Release - Release to PowerShell Gallery Click Here
Want to know how our CD process works? Read this [blog post](https://sqldbawithabeard.com/2018/05/01/version-update-code-signing-and-publishing-to-the-powershell-gallery-with-vsts/) and see how the team manage it ## Prerequisites ### Client requirements * PowerShell 5 + is required. * Automatic installation of the dependent modules will only be provided via the [PowerShell Gallery](https://www.powershellgallery.com). When you install from the Gallery, it'll auto-install: * dbatools * PSFramework You will also need to manually install the Pester module at version 4.10.0, this is due to inconsistencies between dbachecks and Pester v5. If you have Pester v5 installed it is recommended to remove this and use Pester 4.10.0 or force an import of 4.10.0 when running dbachecks ```` Install-Module Pester -SkipPublisherCheck -Force -RequiredVersion 4.10.0 Import-Module Pester -Force -RequiredVersion 4.10.0 ```` When you import, it'll auto-import * dbatools * Pester * PSFramework If you have already installed the module and you update it, you may be required to update the Pester or the PSFramework modules before it will import. If you see a message like ![error](https://user-images.githubusercontent.com/6729780/35032185-dfe988a2-fb5d-11e7-83e3-6a41a9c89b81.png) Then you need to ```` Install-Module Pester -SkipPublisherCheck -Force -RequiredVersion 4.10.0 Import-Module Pester -Force -RequiredVersion 4.10.0 ```` You may need to do the same thing for the PSFramework or dbatools modules also ### SQL requirements dbachecks uses dbatools for most of it's data gathering so it supports SQL Versions from SQL 2000 to SQL vNext including SQL running on Linux. (dbachecks will not install on PowerShell Core yet so can not be run on a Linux client) Obviously some of the Services and disk space checks will not work against instances running on Linux as they are using Windows API calls. ## Getting started Checks are performed using `Invoke-DbcCheck` which is basically a wrapper for [Invoke-Pester](https://github.com/pester/Pester/wiki/Invoke-Pester). This means that supported `Invoke-Pester` parameters work against `Invoke-DbcCheck`. In this module, a "Check" is synonymous with a "Tag" in Pester. So you can **Invoke-DbcCheck** and specify a Check that you want to run. You can see a list of the available Checks with **Get-DbcCheck**. ![image](https://user-images.githubusercontent.com/8278033/34329332-57f40a1c-e8fc-11e7-8526-178c415b09bf.png) Once you've decided on the Check(s) you want to run, it's time to ensure you have a list of servers to run the checks against. ### Making server lists Similar to the [dbatools](https://dbatools.io) module, dbachecks accepts `-SqlInstance` and `-ComputerName` parameters. `Invoke-DbcCheck -SqlInstance $servers -Checks SuspectPage, LastBackup` If you have a simplified (single) environment, however, you can set a permanent list of servers. "Servers" include both SQL Server instances and Windows servers. Checks that access Windows Server (e.g. disk space checks) will utilize `-ComputerName` parameter. A pure SQL Server command(s) (such as the backup check) utilizes the `-SqlInstance` parameter. ```powershell # Set the servers you'll be working with Set-DbcConfig -Name app.sqlinstance -Value sql2016, sql2017, sql2008, sql2008\express Set-DbcConfig -Name app.computername -Value sql2016, sql2017, sql2008 # Look at the current configs Get-DbcConfig # Invoke a few tests Invoke-DbcCheck -Checks SuspectPage, LastBackup ``` #### What it looks like ![image](https://user-images.githubusercontent.com/8278033/34315954-431d0b16-e78a-11e7-8f6d-c87b40ed90b2.png) #### Other ways to execute checks against specific servers Additional `Invoke-DbcCheck` examples: ```powershell Invoke-DbcCheck -Check Backup -SqlInstance sql2016 Invoke-DbcCheck -Check RecoveryModel -SqlInstance sql2017, sqlcluster $sqlinstance = Get-DbaRegisteredServer -SqlInstance sql2017 -Group Express Invoke-DbcCheck -Check Backup -SqlInstance $sqlinstance Invoke-DbcCheck -Check Storage -ComputerName server1, server2 ``` ## Check and ExcludeCheck We tag each of our Checks using singular descriptions such as Backup, Database or Storage. You can see all the Pester related Tags using `Get-DbcTagCollection` or `Get-DbcCheck`. Each Check generally has a few Tags but at least one Tag is unique. This allows us to essentially name a Check and using these Tags, you can either include (`-Check`) or Exclude (`-ExcludeCheck`) in your results. The Exclude will always take precedence. For example, the Database Tag runs a number of Checks including Backup Checks. The command below will run all Database Checks except for the Backup Checks. ```powershell Invoke-DbcCheck -Check Database -ExcludeCheck Backup -SqlInstance sql2016 -SqlCredential (Get-Credential sqladmin) ``` All valid [Pester](https://github.com/Pester/Pester) syntax is valid for dbachecks so if you'd like to know more, you can review their documentation. ## Reporting on the data Since this is just PowerShell and Pester, results can be exported then easily converted to pretty reports. We've provided two options: Power BI and SMTP mail. ### Power BI Visualizations! We've also included a pre-built Power BI Desktop report! You can download Power BI Desktop from [here](https://powerbi.microsoft.com/en-us/downloads/) or it is now offered via the [Microsoft Store on Windows 10](https://www.microsoft.com/store/productId/9NTXR16HNW1T). Note: We strongly recommend that you keep your PowerBI Desktop updated since we can add brand-new stuff that appears on the most recent releases. To use the Power BI report, pipe the results of `Invoke-DbcCheck` to `Update-DbcPowerBiDataSource` (defaults to `C:\Windows\temp\dbachecks`), then launch the included `dbachecks.pbix` file using `Start-DbcPowerBi`. Once the Power BI report is open, just hit **refresh**. ```powershell # Run checks and export its JSON Invoke-DbcCheck -SqlInstance sql2017 -Checks SuspectPage, LastBackup -Show Summary -PassThru | Update-DbcPowerBiDataSource # Launch Power BI then hit refresh Start-DbcPowerBi ``` ![image](https://user-images.githubusercontent.com/19521315/36527050-640d6c0a-17a8-11e8-9781-0aab0a8f8d48.png) The above report uses `Update-DbcPowerBiDataSource`'s `-Environment` parameter. ```powershell # Run checks and export its JSON Invoke-DbcCheck -SqlInstance $prod -Checks LastBackup -Show Summary -PassThru | Update-DbcPowerBiDataSource -Enviornment Prod ``` 😍😍😍 ### Sending mail We even included a command to make emailing the results easier! ```powershell Invoke-DbcCheck -SqlInstance sql2017 -Checks SuspectPage, LastBackup -OutputFormat NUnitXml -PassThru | Send-DbcMailMessage -To clemaire@dbatools.io -From nobody@dbachecks.io -SmtpServer smtp.ad.local ``` ![image](https://user-images.githubusercontent.com/8278033/34316816-cc157d04-e79e-11e7-971d-1cfee90b2e11.png) If you'd like to test locally, check out [PaperCut](https://github.com/ChangemakerStudios/Papercut/releases) which is just a quick email viewer that happens to have a built-in SMTP server. It provides awesome, built-in functionality so you can send the reports! ## Advanced usage ### Skipping some internal tests The Check `LastGoodCheckDb` includes a test for data purity. You may be in an environment that can't support data purity. If this check needs to be skipped, you can do the following: ```powershell Get-DbcConfig *skip* Set-DbcConfig -Name skip.dbcc.datapuritycheck -Value $true ``` Need to skip a whole test? Just use the `-ExcludeCheck` which is auto-populated with both Check names and Pester Tags. ### Setting a global SQL Credential `Set-DbcConfig` persists the values. If you `Set-DbcConfig -Name app.sqlcredential -Value (Get-Credential sa)` it will set the `SqlCredential` for the whole module, but not your local console! So cool. You can also manually change the `SqlCredential` or `Credential` by specifying it in `Invoke-DbaCheck`: ```powershell Invoke-DbaCheck -SqlInstance sql2017 -SqlCredential (Get-Credential sqladmin) -Check MaxMemory ``` ### Manipulating the underlying commands You can also modify the parameters of the actual command that's being executed: ```powershell Set-Variable -Name PSDefaultParameterValues -Value @{ 'Get-DbaDiskSpace:ExcludeDrive' = 'C:\' } -Scope Global Invoke-DbcCheck -Check Storage ``` ## Can I run tests not included the module? If you have super specialized checks to run, you can add a new repository, update the `app.checkrepos` config and this will make all of your tests available to `Invoke-DbcCheck`. From here, you can pipe to `Send-DbcMailMessage`, `Update-DbcPowerBiDataSource` or parse however you would parse Pester results. ![image](https://user-images.githubusercontent.com/8278033/34320729-aeacb72a-e800-11e7-8278-a83de46afcc6.png) So first, add your repository ```powershell Set-DbcConfig -Name app.checkrepos -Value C:\temp\checks -Append ``` Then add additional checks. We recommend using the [development guidelines for dbachecks](https://github.com/potatoqualitee/dbachecks/wiki). ![image](https://user-images.githubusercontent.com/8278033/34320819-07fe939c-e802-11e7-8203-a82740cc8f19.png) ## I'd like to run my checks in SQL Server Agent Great idea! Remember that this module requires PowerShell version 4.0, which doesn't always mesh with SQL Server's PowerShell Job Step. To run dbachecks, **we recommend you use CmdExec**. You can read more at [dbatools.io/agent](https://dbatools.io/agent). If you do choose to use the PowerShell step, don't forget to `Set-Location` somewhere outside of SQLSERVER:, otherwise, you'll get errors similar to this ![image](https://user-images.githubusercontent.com/8771143/35379174-878505fc-01b5-11e8-8731-41be4daff815.png) ## I don't have access to the PowerShell Gallery, how can I download this? This module has a number of dependencies which makes creating a GitHub-centric installer a bit of a pain. We suggest you use a machine with [PowerShellGet](https://docs.microsoft.com/en-us/powershell/gallery/psget/get_psget_module) installed and Save all the modules you need: ```powershell Save-Module -Name dbachecks, dbatools, PSFramework, Pester -Path C:\temp ``` Then move them to somewhere in your `$env:PSModulePath`, perhaps **Documents\WindowsPowerShell\Modules** or **C:\Program Files\WindowsPowerShell\Modules**. ## Read more Read more about dbachecks from a number of our original contributors! * [Announcing dbachecks – Configurable PowerShell Validation For Your SQL Instances by Rob Sewell](https://sqldbawithabeard.com/2018/02/22/announcing-dbachecks-configurable-powershell-validation-for-your-sql-instances/) * [introducing dbachecks - a new module from the dbatools team! by Chrissy LeMaire](https://dbachecks.io/introducing) * [install dbachecks by Chrissy LeMaire](https://dbachecks.io/install) * [dbachecks commands by Chrissy LeMaire](https://dbachecks.io/commands) * [dbachecks – Using Power BI dashboards to analyse results by Cláudio Silva](http://claudioessilva.eu/2018/02/22/dbachecks-using-power-bi-dashboards-to-analyse-results/) * [My wrapper for dbachecks by Tony Wilhelm](https://v-roddba.blogspot.com/2018/02/wrapper-for-dbachecks.html) * [Checking backups with dbachecks by Jess Pomfret](http://jesspomfret.com/checking-backups-with-dbachecks/) * [dbachecks please! by Garry Bargsley](http://blog.garrybargsley.com/dbachecks-please) * [dbachecks – Configuration Deep Dive by Rob Sewell](https://sqldbawithabeard.com/2018/02/22/dbachecks-configuration-deep-dive/) * [Test Log Shipping with dbachecks by Sander Stad](https://www.sqlstad.nl/powershell/test-log-shipping-with-dbachecks/) * [Checking your backup strategy with dbachecks by Joshua Corrick](https://corrick.io/blog/checking-your-backup-strategy-with-dbachecks) * [Enterprise-level reporting with dbachecks by Jason Squires](http://www.sqlnotnull.com/2018/02/20/enterprise-level-reporting-with-dbachecks-from-the-makers-of-dbatools) * [Adding your own checks to dbachecks by Shane O'Neill](http://nocolumnname.blog/2018/02/22/adding-your-own-checks-to-dbachecks) * [dbachecks - A different approach for an in-progress and incremental validation by Cláudio Silva](http://claudioessilva.eu/2018/02/22/dbachecks-a-different-approach-for-a-in-progress-and-incremental-validation/) * [dbachecks - Improved Descriptions by Rob Sewell](https://sqldbawithabeard.com/2018/05/19/dbachecks-improved-descriptions/) * [DBACHECKS – SQL SERVER COMPLIANCE TESTING WITH SIMPLE CONFIGURATION MANAGEMENT by Stuart Moore](https://stuart-moore.com/dbachecks-sql-server-compliance-testing-simple-configuration-management/) * [dbachecks – Which Configuration Item For Which Check ? by Rob Sewell](https://sqldbawithabeard.com/2018/05/15/dbachecks-which-configuration-item-for-which-check/) *[https://sqldbawithabeard.com/2018/04/08/checking-availability-groups-with-dbachecks/ by Rob Sewell](https://sqldbawithabeard.com/2018/04/08/checking-availability-groups-with-dbachecks/) Know of any more blog posts about dbachecks? - Please add them here. ## Party Nice work! ================================================ FILE: header-mkdocs.yml ================================================ site_name: dbachecks repo_url: https://github.com/sqlcollaborative/dbachecks site_author: The Beard edit_uri: edit/main/docs/ theme: readthedocs copyright: "dbachecks is licensed under the MIT license" pages: - Home: index.md ================================================ FILE: mkdocs.yml ================================================ site_name: dbachecks repo_url: https://github.com/sqlcollaborative/dbachecks site_author: The Beard edit_uri: edit/main/docs/ theme: readthedocs copyright: "dbachecks is licensed under the MIT license" pages: - Home: index.md - Release Notes: RELEASE.md - Functions: - Clear-DbcPowerBiDataSource: functions/Clear-DbcPowerBiDataSource.md - Convert-DbcResult: functions/Convert-DbcResult.md - Export-DbcConfig: functions/Export-DbcConfig.md - Get-DbcCheck: functions/Get-DbcCheck.md - Get-DbcConfig: functions/Get-DbcConfig.md - Get-DbcConfigValue: functions/Get-DbcConfigValue.md - Get-DbcReleaseNote: functions/Get-DbcReleaseNote.md - Get-DbcTagCollection: functions/Get-DbcTagCollection.md - Import-DbcConfig: functions/Import-DbcConfig.md - Invoke-DbcCheck: functions/Invoke-DbcCheck.md - Invoke-DbcConfigFile: functions/Invoke-DbcConfigFile.md - Reset-DbcConfig: functions/Reset-DbcConfig.md - Save-DbcRequiredModules: functions/Save-DbcRequiredModules.md - Set-DbcCisConfig: functions/Set-DbcCisConfig.md - Set-DbcConfig: functions/Set-DbcConfig.md - Set-DbcFile: functions/Set-DbcFile.md - Start-DbcPowerBi: functions/Start-DbcPowerBi.md - Update-DbcPowerBiDataSource: functions/Update-DbcPowerBiDataSource.md - Update-DbcRequiredModules: functions/Update-DbcRequiredModules.md - Write-DbcTable: functions/Write-DbcTable.md ================================================ FILE: readme.md ================================================ # dbachecks [![.github/workflows/deploy-module.yml](https://github.com/dataplat/dbachecks/actions/workflows/deploy-module.yml/badge.svg?branch=main)](https://github.com/dataplat/dbachecks/actions/workflows/deploy-module.yml) [![GitHub release badge](https://badgen.net/github/release/dataplat/dbachecks/stable?label=latest_release)](https://github.com/dataplat/dbachecks/releases/latest) [![GitHub pre-release badge](https://badgen.net/github/release/dataplat/dbachecks?label=pre-release)](https://github.com/dataplat/dbachecks/releases/) [![PowerShell Gallery](https://img.shields.io/powershellgallery/v/dbachecks?label=PowerShell_Gallery)](https://www.powershellgallery.com/packages/dbachecks/) [![GitHub license badge](https://badgen.net/github/license/dataplat/dbachecks)](https://github.com/dataplat/dbachecks/blob/43423437f831e2844452d482a50864f224f12534/LICENSE) [![GitHub releases badge](https://badgen.net/github/releases/dataplat/dbachecks)](https://github.com/dataplat/dbachecks/releases) ![Ubuntu Linux](https://badgen.net/badge/icon/Ubuntu?icon=terminal&label=pwsh)[![Linux Tests](https://gist.githubusercontent.com/SQLDBAWithABeard/7a5d2837e29654202f22392187c75fec/raw/linux-badge.svg)](https://github.com/dataplat/dbachecks/actions/) ![macOS](https://badgen.net/badge/icon/macOS?icon=apple&label=pwsh)[![MacOs Tests](https://gist.githubusercontent.com/SQLDBAWithABeard/7a5d2837e29654202f22392187c75fec/raw/macos-badge.svg)](https://github.com/dataplat/dbachecks/actions/) ![Windows badge](https://badgen.net/badge/icon/windows?icon=windows&label=pwsh)[![Windows pwsh Tests](https://gist.githubusercontent.com/SQLDBAWithABeard/7a5d2837e29654202f22392187c75fec/raw/winps7-badge.svg)](https://github.com/dataplat/dbachecks/actions/) ![Windows badge](https://badgen.net/badge/icon/windows?icon=windows&label=5.1)[![Windows PowerShell 5.1 Tests](https://gist.githubusercontent.com/SQLDBAWithABeard/7a5d2837e29654202f22392187c75fec/raw/winps51-badge.svg)](https://github.com/dataplat/dbachecks/actions/) **Please note - development on v2 has stopped and all efforts are focused on the v3 improvements to use Pester v5 and improve performance.** You are welcome to help by picking something from the project https://github.com/orgs/dataplat/projects/2 or by contacting @SQLDBAWithABeard @jpomfret @ClaudioESSilva or @shaneis dbachecks is a framework created by and for SQL Server pros who need to validate their environments. Basically, we all share similar checklists and mostly just the server names and RPO/RTO/etc change. This open source module allows us to crowd-source our checklists using [Pester](https://github.com/Pester/Pester) tests. Such checks include: * Backups are being performed * Identity columns are not about to max out * Servers have access to backup paths * Database integrity checks are being performed and corruption does not exist * Disk space is not about to run out * All enabled jobs have succeeded ## Interactive dbachecks PowerShell Notebooks for Azure Data Studio You can find a set of interactive PowerShell Notebooks which will introduce you to all of the core concepts in Robs GitHub. There is a set of .NET interactive Jupyter Notebooks https://github.com/SQLDBAWithABeard/JupyterNotebooks/tree/main/notebooks/dotNETNotebooks/dbachecks and a set of Jupyter Notebooks that will run in Azure Data Studio https://github.com/SQLDBAWithABeard/JupyterNotebooks/tree/main/notebooks/NotDotNet/dbachecks Both will use a docker container to show you how dbachecks works. There is a zip file containing the Notebooks here https://github.com/SQLDBAWithABeard/Presentations/raw/main/Notebooks/dbachecks/Notebooks.zip Have questions about development? Please visit our [Wiki](https://github.com/sqlcollaborative/dbachecks/wiki). **Anyone developing this module** should visit that Wiki page (after fully reading this readme) for a brief overview. ## Build Status
Development Branch Build - Unit testing Click Here
Main Branch Build - Module version update and Code Signing Click Here
Main Branch Release - Release to PowerShell Gallery Click Here
Want to know how our CD process works? Read this [blog post](https://sqldbawithabeard.com/2018/05/01/version-update-code-signing-and-publishing-to-the-powershell-gallery-with-vsts/) and see how the team manage it ## Prerequisites ### Client requirements * PowerShell 5 + is required. * Automatic installation of the dependent modules will only be provided via the [PowerShell Gallery](https://www.powershellgallery.com). When you install from the Gallery, it'll auto-install: * dbatools * PSFramework You will also need to manually install the Pester module at version 4.10.0, this is due to inconsistencies between dbachecks and Pester v5. If you have Pester v5 installed it is recommended to remove this and use Pester 4.10.0 or force an import of 4.10.0 when running dbachecks ```` Install-Module Pester -SkipPublisherCheck -Force -RequiredVersion 4.10.0 Import-Module Pester -Force -RequiredVersion 4.10.0 ```` When you import, it'll auto-import * dbatools * Pester * PSFramework If you have already installed the module and you update it, you may be required to update the Pester or the PSFramework modules before it will import. If you see a message like ![error](https://user-images.githubusercontent.com/6729780/35032185-dfe988a2-fb5d-11e7-83e3-6a41a9c89b81.png) Then you need to ```` Install-Module Pester -SkipPublisherCheck -Force -RequiredVersion 4.10.0 Import-Module Pester -Force -RequiredVersion 4.10.0 ```` You may need to do the same thing for the PSFramework or dbatools modules also ### SQL requirements dbachecks uses dbatools for most of it's data gathering so it supports SQL Versions from SQL 2000 to SQL vNext including SQL running on Linux. (dbachecks will not install on PowerShell Core yet so can not be run on a Linux client) Obviously some of the Services and disk space checks will not work against instances running on Linux as they are using gWindows API calls. ## Getting started Checks are performed using `Invoke-DbcCheck` which is basically a wrapper for [Invoke-Pester](https://github.com/pester/Pester/wiki/Invoke-Pester). This means that supported `Invoke-Pester` parameters work against `Invoke-DbcCheck`. In this module, a "Check" is synonymous with a "Tag" in Pester. So you can **Invoke-DbcCheck** and specify a Check that you want to run. You can see a list of the available Checks with **Get-DbcCheck**. ![image](https://user-images.githubusercontent.com/8278033/34329332-57f40a1c-e8fc-11e7-8526-178c415b09bf.png) Once you've decided on the Check(s) you want to run, it's time to ensure you have a list of servers to run the checks against. ### Making server lists Similar to the [dbatools](https://dbatools.io) module, dbachecks accepts `-SqlInstance` and `-ComputerName` parameters. `Invoke-DbcCheck -SqlInstance $servers -Checks SuspectPage, LastBackup` If you have a simplified (single) environment, however, you can set a permanent list of servers. "Servers" include both SQL Server instances and Windows servers. Checks that access Windows Server (e.g. disk space checks) will utilize `-ComputerName` parameter. A pure SQL Server command(s) (such as the backup check) utilizes the `-SqlInstance` parameter. ```powershell # Set the servers you'll be working with Set-DbcConfig -Name app.sqlinstance -Value sql2016, sql2017, sql2008, sql2008\express Set-DbcConfig -Name app.computername -Value sql2016, sql2017, sql2008 # Look at the current configs Get-DbcConfig # Invoke a few tests Invoke-DbcCheck -Checks SuspectPage, LastBackup ``` #### What it looks like ![image](https://user-images.githubusercontent.com/8278033/34315954-431d0b16-e78a-11e7-8f6d-c87b40ed90b2.png) #### Other ways to execute checks against specific servers Additional `Invoke-DbcCheck` examples: ```powershell Invoke-DbcCheck -Check Backup -SqlInstance sql2016 Invoke-DbcCheck -Check RecoveryModel -SqlInstance sql2017, sqlcluster $sqlinstance = Get-DbaRegisteredServer -SqlInstance sql2017 -Group Express Invoke-DbcCheck -Check Backup -SqlInstance $sqlinstance Invoke-DbcCheck -Check Storage -ComputerName server1, server2 ``` ## Check and ExcludeCheck We tag each of our Checks using singular descriptions such as Backup, Database or Storage. You can see all the Pester related Tags using `Get-DbcTagCollection` or `Get-DbcCheck`. Each Check generally has a few Tags but at least one Tag is unique. This allows us to essentially name a Check and using these Tags, you can either include (`-Check`) or Exclude (`-ExcludeCheck`) in your results. The Exclude will always take precedence. For example, the Database Tag runs a number of Checks including Backup Checks. The command below will run all Database Checks except for the Backup Checks. ```powershell Invoke-DbcCheck -Check Database -ExcludeCheck Backup -SqlInstance sql2016 -SqlCredential (Get-Credential sqladmin) ``` All valid [Pester](https://github.com/Pester/Pester) syntax is valid for dbachecks so if you'd like to know more, you can review their documentation. ## Reporting on the data Since this is just PowerShell and Pester, results can be exported then easily converted to pretty reports. We've provided two options: Power BI and SMTP mail. ### Power BI Visualizations! We've also included a pre-built Power BI Desktop report! You can download Power BI Desktop from [here](https://powerbi.microsoft.com/en-us/downloads/) or it is now offered via the [Microsoft Store on Windows 10](https://www.microsoft.com/store/productId/9NTXR16HNW1T). Note: We strongly recommend that you keep your PowerBI Desktop updated since we can add brand-new stuff that appears on the most recent releases. To use the Power BI report, pipe the results of `Invoke-DbcCheck` to `Update-DbcPowerBiDataSource` (defaults to `C:\Windows\temp\dbachecks`), then launch the included `dbachecks.pbix` file using `Start-DbcPowerBi`. Once the Power BI report is open, just hit **refresh**. ```powershell # Run checks and export its JSON Invoke-DbcCheck -SqlInstance sql2017 -Checks SuspectPage, LastBackup -Show Summary -PassThru | Update-DbcPowerBiDataSource # Launch Power BI then hit refresh Start-DbcPowerBi ``` ![image](https://user-images.githubusercontent.com/19521315/36527050-640d6c0a-17a8-11e8-9781-0aab0a8f8d48.png) The above report uses `Update-DbcPowerBiDataSource`'s `-Environment` parameter. ```powershell # Run checks and export its JSON Invoke-DbcCheck -SqlInstance $prod -Checks LastBackup -Show Summary -PassThru | Update-DbcPowerBiDataSource -Environment Prod ``` 😍😍😍 ### Sending mail We even included a command to make emailing the results easier! ```powershell $outputDirectory = (Get-DbcConfigValue -Name app.maildirectory) $filename = $outputDirectory + '\file.xml' Invoke-Dbccheck -OutputFile $fileName -OutputFormat NunitXML $outputpath = $outputDirectory + "\index.html" $reportunit = "ModulePath\bin\ReportUnit.exe" & $reportunit $outputDirectory $htmlbody = Get-Content -Path $outputpath -ErrorAction SilentlyContinue | Out-String Send-MailMessage -To clemaire@dbatools.io -From nobody@dbachecks.io -SMTP smtp.ad.local -BodyAsHtml $htmlbody ``` ![image](https://user-images.githubusercontent.com/8278033/34316816-cc157d04-e79e-11e7-971d-1cfee90b2e11.png) If you'd like to test locally, check out [PaperCut](https://github.com/ChangemakerStudios/Papercut/releases) which is just a quick email viewer that happens to have a built-in SMTP server. It provides awesome, built-in functionality so you can send the reports! ## Advanced usage ### Skipping some internal tests The Check `LastGoodCheckDb` includes a test for data purity. You may be in an environment that can't support data purity. If this check needs to be skipped, you can do the following: ```powershell Get-DbcConfig *skip* Set-DbcConfig -Name skip.dbcc.datapuritycheck -Value $true ``` Need to skip a whole test? Just use the `-ExcludeCheck` which is auto-populated with both Check names and Pester Tags. ### Setting a global SQL Credential `Set-DbcConfig` persists the values. If you `Set-DbcConfig -Name app.sqlcredential -Value (Get-Credential sa)` it will set the `SqlCredential` for the whole module, but not your local console! So cool. You can also manually change the `SqlCredential` or `Credential` by specifying it in `Invoke-DbaCheck`: ```powershell Invoke-DbaCheck -SqlInstance sql2017 -SqlCredential (Get-Credential sqladmin) -Check MaxMemory ``` ### Manipulating the underlying commands You can also modify the parameters of the actual command that's being executed: ```powershell Set-Variable -Name PSDefaultParameterValues -Value @{ 'Get-DbaDiskSpace:ExcludeDrive' = 'C:\' } -Scope Global Invoke-DbcCheck -Check Storage ``` ## Can I run tests not included the module? If you have super specialized checks to run, you can add a new repository, update the `app.checkrepos` config and this will make all of your tests available to `Invoke-DbcCheck`. From here, you can pipe to `Send-DbcMailMessage`, `Update-DbcPowerBiDataSource` or parse however you would parse Pester results. ![image](https://user-images.githubusercontent.com/8278033/34320729-aeacb72a-e800-11e7-8278-a83de46afcc6.png) So first, add your repository ```powershell Set-DbcConfig -Name app.checkrepos -Value C:\temp\checks -Append ``` Then add additional checks. We recommend using the [development guidelines for dbachecks](https://github.com/potatoqualitee/dbachecks/wiki). ![image](https://user-images.githubusercontent.com/8278033/34320819-07fe939c-e802-11e7-8203-a82740cc8f19.png) ## I'd like to run my checks in SQL Server Agent Great idea! Remember that this module requires PowerShell version 4.0, which doesn't always mesh with SQL Server's PowerShell Job Step. To run dbachecks, **we recommend you use CmdExec**. You can read more at [dbatools.io/agent](https://dbatools.io/agent). If you do choose to use the PowerShell step, don't forget to `Set-Location` somewhere outside of SQLSERVER:, otherwise, you'll get errors similar to this ![image](https://user-images.githubusercontent.com/8771143/35379174-878505fc-01b5-11e8-8731-41be4daff815.png) ## I don't have access to the PowerShell Gallery, how can I download this? This module has a number of dependencies which makes creating a GitHub-centric installer a bit of a pain. We suggest you use a machine with [PowerShellGet](https://docs.microsoft.com/en-us/powershell/scripting/gallery/installing-psget) installed and Save all the modules you need: ```powershell Save-Module -Name dbachecks, dbatools, PSFramework, Pester -Path C:\temp ``` Then move them to somewhere in your `$env:PSModulePath`, perhaps **Documents\WindowsPowerShell\Modules** or **C:\Program Files\WindowsPowerShell\Modules**. ## Read more Read more about dbachecks from a number of our original contributors! * [Announcing dbachecks – Configurable PowerShell Validation For Your SQL Instances by Rob Sewell](https://sqldbawithabeard.com/2018/02/22/announcing-dbachecks-configurable-powershell-validation-for-your-sql-instances/) * [introducing dbachecks - a new module from the dbatools team! by Chrissy LeMaire](https://dbachecks.io/introducing) * [install dbachecks by Chrissy LeMaire](https://dbachecks.io/install) * [dbachecks commands by Chrissy LeMaire](https://dbachecks.io/commands) * [dbachecks – Using Power BI dashboards to analyse results by Cláudio Silva](http://claudioessilva.eu/2018/02/22/dbachecks-using-power-bi-dashboards-to-analyse-results/) * [My wrapper for dbachecks by Tony Wilhelm](https://v-roddba.blogspot.com/2018/02/wrapper-for-dbachecks.html) * [Checking backups with dbachecks by Jess Pomfret](http://jesspomfret.com/checking-backups-with-dbachecks/) * [dbachecks please! by Garry Bargsley](https://garrybargsley.com/2018/02/22/dbachecks-please/) * [dbachecks – Configuration Deep Dive by Rob Sewell](https://sqldbawithabeard.com/2018/02/22/dbachecks-configuration-deep-dive/) * [Test Log Shipping with dbachecks by Sander Stad](https://www.sqlstad.nl/powershell/test-log-shipping-with-dbachecks/) * [Checking your backup strategy with dbachecks by Joshua Corrick](https://corrick.io/blog/checking-your-backup-strategy-with-dbachecks) * [Enterprise-level reporting with dbachecks by Jason Squires](http://www.sqlnotnull.com/2018/02/22/enterprise-level-reporting-with-dbachecks-from-the-makers-of-dbatools/) * [Adding your own checks to dbachecks by Shane O'Neill](http://nocolumnname.blog/2018/02/22/adding-your-own-checks-to-dbachecks) * [dbachecks - A different approach for an in-progress and incremental validation by Cláudio Silva](https://claudioessilva.eu/2018/02/22/dbachecks-a-different-approach-for-an-in-progress-and-incremental-validation/) * [dbachecks - Improved Descriptions by Rob Sewell](https://sqldbawithabeard.com/2018/05/19/dbachecks-improved-descriptions/) * [DBACHECKS – SQL SERVER COMPLIANCE TESTING WITH SIMPLE CONFIGURATION MANAGEMENT by Stuart Moore](https://stuart-moore.com/dbachecks-sql-server-compliance-testing-simple-configuration-management/) * [dbachecks – Which Configuration Item For Which Check ? by Rob Sewell](https://sqldbawithabeard.com/2018/05/15/dbachecks-which-configuration-item-for-which-check/) *[https://sqldbawithabeard.com/2018/04/08/checking-availability-groups-with-dbachecks/ by Rob Sewell](https://sqldbawithabeard.com/2018/04/08/checking-availability-groups-with-dbachecks/) Know of any more blog posts about dbachecks? - Please add them here. ## Party Nice work! # How to Contribute We welcome contributions to the project. You can fork the repository, make changes and create a Pull Request. [Rob has written a guide here](https://sqldbawithabeard.com/?p=11030) ================================================ FILE: source/checks/Agent.Tests.ps1 ================================================ $filename = $MyInvocation.MyCommand.Name.Replace('.Tests.ps1', '') . $PSScriptRoot/../internal/assertions/Agent.Assertions.ps1 [string[]]$NotContactable = (Get-PSFConfig -Module dbachecks -Name global.notcontactable).Value Set-PSFConfig -Module dbachecks -Name global.notcontactable -Value $NotContactable @(Get-Instance).ForEach{ if ($NotContactable -notcontains $psitem) { $Instance = $psitem try { $InstanceSMO = Connect-DbaInstance -SqlInstance $Instance -ErrorAction SilentlyContinue -ErrorVariable errorvar } catch { $NotContactable += $Instance } if ($NotContactable -notcontains $psitem) { if ($null -eq $InstanceSMO.version) { $NotContactable += $Instance } elseif (($InstanceSMO).Edition -like 'Express Edition*') { } else { Describe "Database Mail XPs" -Tags DatabaseMailEnabled, CIS, security, $filename { $DatabaseMailEnabled = Get-DbcConfigValue policy.security.DatabaseMailEnabled if ($NotContactable -contains $psitem) { Context "Testing Database Mail XPs on $psitem" { It "Can't Connect to $Psitem" { $false | Should -BeTrue -Because 'The instance should be available to be connected to!' } } } else { Context "Testing Database Mail XPs on $psitem" { It "Testing Database Mail XPs is set to $DatabaseMailEnabled on $psitem" { Assert-DatabaseMailEnabled -SQLInstance $Psitem -DatabaseMailEnabled $DatabaseMailEnabled } } } } Describe "SQL Agent Account" -Tags AgentServiceAccount, ServiceAccount, $filename { if ($NotContactable -contains $psitem) { Context "Testing SQL Agent is running on $psitem" { It "Can't Connect to $Psitem" { $false | Should -BeTrue -Because 'The instance should be available to be connected to!' } } } else { # cant check agent on container - hmm does this actually work with instance need to check if (-not $IsLinux -and ($InstanceSMO.HostPlatform -ne 'Linux')) { Context "Testing SQL Agent is running on $psitem" { @(Get-DbaService -ComputerName $psitem -Type Agent).ForEach{ It "SQL Agent should be running for $($psitem.InstanceName) on $($psitem.ComputerName)" { $psitem.State | Should -Be 'Running' -Because 'The agent service is required to run SQL Agent jobs' } if ($InstanceSMO.IsClustered) { It "SQL Agent service should have a start mode of Manual for FailOver Clustered Instance $($psitem.InstanceName) on $($psitem.ComputerName)" { $psitem.StartMode | Should -Be 'Manual' -Because 'Clustered Instances required that the Agent service is set to manual' } } else { It "SQL Agent service should have a start mode of Automatic for standalone instance $($psitem.InstanceName) on $($psitem.ComputerName)" { $psitem.StartMode | Should -Be 'Automatic' -Because 'Otherwise the Agent Jobs wont run if the server is restarted' } } } } } else { Context "Testing SQL Agent is running on $psitem" { It "Running on Linux or connecting to container so can't check Services on $Psitem" -Skip { } } } } } Describe "DBA Operators" -Tags DbaOperator, Operator, $filename { if ($NotContactable -contains $psitem) { Context "Testing DBA Operators exists on $psitem" { It "Can't Connect to $Psitem" { $false | Should -BeTrue -Because 'The instance should be available to be connected to!' } } } else { Context "Testing DBA Operators exists on $psitem" { $operatorname = Get-DbcConfigValue agent.dbaoperatorname $operatoremail = Get-DbcConfigValue agent.dbaoperatoremail $results = Get-DbaAgentOperator -SqlInstance $psitem -Operator $operatorname @($operatorname).ForEach{ It "The Operator exists on $psitem" { $psitem | Should -BeIn $Results.Name -Because 'This Operator is expected to exist' } } @($operatoremail).ForEach{ if ($operatoremail) { It "The Operator email $operatoremail is correct on $psitem" { $psitem | Should -BeIn $results.EmailAddress -Because 'This operator email is expected to exist' } } } } } } Describe "Failsafe Operator" -Tags FailsafeOperator, Operator, $filename { if ($NotContactable -contains $psitem) { Context "Testing failsafe operator exists on $psitem" { It "Can't Connect to $Psitem" { $false | Should -BeTrue -Because 'The instance should be available to be connected to!' } } } else { Context "Testing failsafe operator exists on $psitem" { $failsafeoperator = Get-DbcConfigValue agent.failsafeoperator It "The Failsafe Operator exists on $psitem" { (Connect-DbaInstance -SqlInstance $psitem).JobServer.AlertSystem.FailSafeOperator | Should -Be $failsafeoperator -Because 'The failsafe operator will ensure that any job failures will be notified to someone if not set explicitly' } } } } Describe "Database Mail Profile" -Tags DatabaseMailProfile, $filename { if ($NotContactable -contains $psitem) { Context "Testing database mail profile is set on $psitem" { It "Can't Connect to $Psitem" { $false | Should -BeTrue -Because 'The instance should be available to be connected to!' } } } else { Context "Testing database mail profile is set on $psitem" { $databasemailprofile = Get-DbcConfigValue agent.databasemailprofile It "The Database Mail profile $databasemailprofile exists on $psitem" { ((Get-DbaDbMailProfile -SqlInstance $InstanceSMO).Name -contains $databasemailprofile) | Should -Be $true -Because 'The database mail profile is required to send emails' } } } } Describe "Agent Mail Profile" -Tags AgentMailProfile, $filename { if ($NotContactable -contains $psitem) { Context "Testing SQL Agent Alert System database mail profile is set on $psitem" { It "Can't Connect to $Psitem" { $false | Should -BeTrue -Because 'The instance should be available to be connected to!' } } } else { Context "Testing SQL Agent Alert System database mail profile is set on $psitem" { $agentmailprofile = Get-DbcConfigValue agent.databasemailprofile It "The SQL Server Agent Alert System should have an enabled database mail profile on $psitem" { (Get-DbaAgentServer -SqlInstance $InstanceSMO).DatabaseMailProfile | Should -Be $agentmailprofile -Because 'The SQL Agent Alert System needs an enabled database mail profile to send alert emails' } } } } Describe "Failed Jobs" -Tags FailedJob, $filename { if ($NotContactable -contains $psitem) { Context "Checking for failed enabled jobs on $psitem" { It "Can't Connect to $Psitem" { $false | Should -BeTrue -Because 'The instance should be available to be connected to!' } } } else { $maxdays = Get-DbcConfigValue agent.failedjob.since $startdate = (Get-Date).AddDays( - $maxdays) Context "Checking for failed enabled jobs since $startdate on $psitem" { $excludecancelled = Get-DbcConfigValue agent.failedjob.excludecancelled @(Get-DbaAgentJob -SqlInstance $psitem | Where-Object { $Psitem.IsEnabled -and ($psitem.LastRunDate -gt $startdate) }).ForEach{ if ($psitem.LastRunOutcome -eq 'Unknown') { It -Skip "We chose to skip this as $psitem's last run outcome is unknown on $($psitem.SqlInstance)" { $psitem.LastRunOutcome | Should -Be 'Succeeded' -Because 'All Agent Jobs should have succeed this one is unknown - you need to investigate the failed jobs' } } elseif (($psitem.LastRunOutcome -eq 'Cancelled') -and ($excludecancelled -eq $true)) { It -Skip "We chose to skip this as $psitem's last run outcome is cancelled on $($psitem.SqlInstance)" { $psitem.LastRunOutcome | Should -Be 'Succeeded' -Because 'All Agent Jobs should have succeed this one is unknown - you need to investigate the failed jobs' } } else { It "$psitem's last run outcome is $($psitem.LastRunOutcome) on $($psitem.SqlInstance)" { $psitem.LastRunOutcome | Should -Be 'Succeeded' -Because 'All Agent Jobs should have succeed - you need to investigate the failed jobs' } } } } } } Describe "Valid Job Owner" -Tags ValidJobOwner, $filename { [string[]]$targetowner = Get-DbcConfigValue agent.validjobowner.name if ($NotContactable -contains $psitem) { Context "Testing job owners on $psitem" { It "Can't Connect to $Psitem" { $false | Should -BeTrue -Because 'The instance should be available to be connected to!' } } } else { Context "Testing job owners on $psitem" { @(Get-DbaAgentJob -SqlInstance $psitem -EnableException:$false).ForEach{ It "Job $($psitem.Name) - owner $($psitem.OwnerLoginName) should be in this list ( $( [String]::Join(', ', $targetowner) ) ) on $($psitem.SqlInstance)" { $psitem.OwnerLoginName | Should -BeIn $TargetOwner -Because 'The account that is the job owner is not what was expected' } } } } } Describe "Invalid Job Owner" -Tags InValidJobOwner, $filename { [string[]]$targetowner = Get-DbcConfigValue agent.invalidjobowner.name if ($NotContactable -contains $psitem) { Context "Testing job owners on $psitem" { It "Can't Connect to $Psitem" { $false | Should -BeTrue -Because 'The instance should be available to be connected to!' } } } else { Context "Testing job owners on $psitem" { @(Get-DbaAgentJob -SqlInstance $psitem -EnableException:$false).ForEach{ It "Job $($psitem.Name) - owner $($psitem.OwnerLoginName) should not be in this list ( $( [String]::Join(', ', $targetowner) ) ) on $($psitem.SqlInstance)" { $psitem.OwnerLoginName | Should -Not -BeIn $TargetOwner -Because 'The account that is the job owner has been defined as not valid' } } } } } Describe "Agent Alerts" -Tags AgentAlert, $filename { $severity = Get-DbcConfigValue agent.alert.Severity $messageid = Get-DbcConfigValue agent.alert.messageid $AgentAlertJob = Get-DbcConfigValue agent.alert.Job $AgentAlertNotification = Get-DbcConfigValue agent.alert.Notification $skip = Get-DbcConfigValue skip.agent.alert if ($NotContactable -contains $psitem) { Context "Testing Agent Alerts Severity exists on $psitem" { It "Can't Connect to $Psitem" { $false | Should -BeTrue -Because 'The instance should be available to be connected to!' } } Context "Testing Agent Alerts MessageID exists on $psitem" { It "Can't Connect to $Psitem" { $false | Should -BeTrue -Because 'The instance should be available to be connected to!' } } } else { $alerts = Get-DbaAgentAlert -SqlInstance $psitem Context "Testing Agent Alerts Severity exists on $psitem" { ForEach ($sev in $severity) { It "Severity $sev Alert should exist on $psitem" -Skip:$skip { ($alerts.Where{ $psitem.Severity -eq $sev }) | Should -Be $true -Because 'Recommended Agent Alerts to exists http://blog.extreme-advice.com/2013/01/29/list-of-errors-and-severity-level-in-sql-server-with-catalog-view-sysmessages/' } It "Severity $sev Alert should be enabled on $psitem" -Skip:$skip { ($alerts.Where{ $psitem.Severity -eq $sev }).IsEnabled | Should -Be $true -Because 'Configured alerts should be enabled' } if ($AgentAlertJob) { It "A job name for Severity $sev Alert on $psitem" -Skip:$skip { ($alerts.Where{ $psitem.Severity -eq $sev }).jobname -ne $null | Should -Be $true -Because 'Should notify by SQL Agent Job' } } if ($AgentAlertNotification) { It "Severity $sev Alert should have a notification on $psitem" -Skip:$skip { ($alerts.Where{ $psitem.Severity -eq $sev }).HasNotification -in 1, 2, 3, 4, 5, 6, 7 | Should -Be $true -Because 'Should notify by Agent notifications' } } } } Context "Testing Agent Alerts MessageID exists on $psitem" { ForEach ($mid in $messageid) { It "Message_ID $mid Alert should exist on $psitem" -Skip:$skip { ($alerts.Where{ $psitem.messageid -eq $mid }) | Should -Be $true -Because 'Recommended Agent Alerts to exists http://blog.extreme-advice.com/2013/01/29/list-of-errors-and-severity-level-in-sql-server-with-catalog-view-sysmessages/' } It "Message_ID $mid Alert should be enabled on $psitem" -Skip:$skip { ($alerts.Where{ $psitem.messageid -eq $mid }) | Should -Be $true -Because 'Configured alerts should be enabled' } if ($AgentAlertJob) { It "A Job name for Message_ID $mid Alert should be on $psitem" -Skip:$skip { ($alerts.Where{ $psitem.messageid -eq $mid }).jobname -ne $null | Should -Be $true -Because 'Should notify by SQL Agent Job' } } if ($AgentAlertNotification) { It "Message_ID $mid Alert should have a notification on $psitem" -Skip:$skip { ($alerts.Where{ $psitem.messageid -eq $mid }).HasNotification -in 1, 2, 3, 4, 5, 6, 7 | Should -Be $true -Because 'Should notify by Agent notifications' } } } } } } Describe "Job History Configuration" -Tags JobHistory, $filename { if ($NotContactable -contains $psitem) { Context "Testing job history configuration on $psitem" { It "Can't Connect to $Psitem" { $false | Should -BeTrue -Because 'The instance should be available to be connected to!' } } } else { Context "Testing job history configuration on $psitem" { [int]$minimumJobHistoryRows = Get-DbcConfigValue agent.history.maximumhistoryrows [int]$minimumJobHistoryRowsPerJob = Get-DbcConfigValue agent.history.maximumjobhistoryrows $AgentServer = Get-DbaAgentServer -SqlInstance $psitem -EnableException:$false if ($minimumJobHistoryRows -eq -1) { It "The maximum job history configuration should be set to disabled on $psitem" { Assert-JobHistoryRowsDisabled -AgentServer $AgentServer -minimumJobHistoryRows $minimumJobHistoryRows } } else { It "The maximum job history number of rows configuration should be greater or equal to $minimumJobHistoryRows on $psitem" { Assert-JobHistoryRows -AgentServer $AgentServer -minimumJobHistoryRows $minimumJobHistoryRows } It "The maximum job history rows per job configuration should be greater or equal to $minimumJobHistoryRowsPerJob on $psitem" { Assert-JobHistoryRowsPerJob -AgentServer $AgentServer -minimumJobHistoryRowsPerJob $minimumJobHistoryRowsPerJob } } } } } Describe "Long Running Agent Jobs" -Tags LongRunningJob, $filename { $skip = Get-DbcConfigValue skip.agent.longrunningjobs $runningjobpercentage = Get-DbcConfigValue agent.longrunningjob.percentage if (-not $skip) { $query = "SELECT JobName, AvgSec, start_execution_date as StartDate, RunningSeconds, RunningSeconds - AvgSec AS Diff FROM ( SELECT j.name AS JobName, start_execution_date, AVG(DATEDIFF(SECOND, 0, STUFF(STUFF(RIGHT('000000' + CONVERT(VARCHAR(6),jh.run_duration),6),5,0,':'),3,0,':'))) AS AvgSec, ja.start_execution_date as startdate, DATEDIFF(second, ja.start_execution_date, GetDate()) AS RunningSeconds FROM msdb.dbo.sysjobactivity ja JOIN msdb.dbo.sysjobs j ON ja.job_id = j.job_id JOIN msdb.dbo.sysjobhistory jh ON jh.job_id = j.job_id WHERE start_execution_date is not null AND stop_execution_date is null AND run_duration < 235959 AND run_duration >= 0 AND ja.start_execution_date > DATEADD(day,-1,GETDATE()) GROUP BY j.name,j.job_id,start_execution_date,stop_execution_date,ja.job_id ) AS t ORDER BY JobName;" $runningjobs = Invoke-DbaQuery -SqlInstance $PSItem -Database msdb -Query $query } if ($NotContactable -contains $psitem) { Context "Testing long running jobs on $psitem" { It "Can't Connect to $Psitem" { $false | Should -BeTrue -Because 'The instance should be available to be connected to!' } } } else { Context "Testing long running jobs on $psitem" { if ($runningjobs) { foreach ($runningjob in $runningjobs | Where-Object { $_.AvgSec -ne 0 }) { It "Running job $($runningjob.JobName) duration should not be more than $runningjobpercentage % extra of the average run time on $psitem" -Skip:$skip { Assert-LongRunningJobs -runningjob $runningjob -runningjobpercentage $runningjobpercentage } } } else { It "There are no running jobs currently on $psitem" -Skip:$skip { $True | Should -BeTrue } } } } } Describe "Last Agent Job Run" -Tags LastJobRunTime, $filename { $skip = Get-DbcConfigValue skip.agent.lastjobruntime $runningjobpercentage = Get-DbcConfigValue agent.lastjobruntime.percentage $maxdays = Get-DbcConfigValue agent.failedjob.since if (-not $skip) { $query = "IF OBJECT_ID('tempdb..#dbachecksLastRunTime') IS NOT NULL DROP Table #dbachecksLastRunTime SELECT * INTO #dbachecksLastRunTime FROM ( SELECT j.job_id, j.name AS JobName, DATEDIFF(SECOND, 0, STUFF(STUFF(RIGHT('000000' + CONVERT(VARCHAR(6),jh.run_duration),6),5,0,':'),3,0,':')) AS Duration FROM msdb.dbo.sysjobs j INNER JOIN ( SELECT job_id, instance_id = MAX(instance_id) FROM msdb.dbo.sysjobhistory GROUP BY job_id ) AS h ON j.job_id = h.job_id INNER JOIN msdb.dbo.sysjobhistory AS jh ON jh.job_id = h.job_id AND jh.instance_id = h.instance_id WHERE msdb.dbo.agent_datetime(jh.run_date, jh.run_time) > DATEADD(DAY,- $maxdays,GETDATE()) AND jh.step_id = 0 ) AS lrt IF OBJECT_ID('tempdb..#dbachecksAverageRunTime') IS NOT NULL DROP Table #dbachecksAverageRunTime SELECT * INTO #dbachecksAverageRunTime FROM ( SELECT job_id, AVG(DATEDIFF(SECOND, 0, STUFF(STUFF(RIGHT('000000' + CONVERT(VARCHAR(6),run_duration),6),5,0,':'),3,0,':'))) AS AvgSec FROM msdb.dbo.sysjobhistory hist WHERE msdb.dbo.agent_datetime(run_date, run_time) > DATEADD(DAY,- $maxdays,GETDATE()) AND Step_id = 0 AND run_duration >= 0 GROUP BY job_id ) as art SELECT JobName, Duration, AvgSec, Duration - AvgSec AS Diff FROM #dbachecksLastRunTime lastrun JOIN #dbachecksAverageRunTime avgrun ON lastrun.job_id = avgrun.job_id DROP Table #dbachecksLastRunTime DROP Table #dbachecksAverageRunTime" $lastagentjobruns = Invoke-DbaQuery -SqlInstance $PSItem -Database msdb -Query $query Context "Testing last job run time on $psitem" { foreach ($lastagentjobrun in $lastagentjobruns | Where-Object { $_.AvgSec -ne 0 }) { It "Job $($lastagentjobrun.JobName) last run duration should be not be greater than $runningjobpercentage % extra of the average run time on $psitem" -Skip:$skip { Assert-LastJobRun -lastagentjobrun $lastagentjobrun -runningjobpercentage $runningjobpercentage } } } } else { Context "Testing last job run time on $psitem" { It "Job average run time on $psitem" -Skip { Assert-LastJobRun -lastagentjobrun $lastagentjobrun -runningjobpercentage $runningjobpercentage } } } } } } } } ================================================ FILE: source/checks/Agentv5.Tests.ps1 ================================================ # So the v5 files need to be handled differently. # We will start with a BeforeDiscovery which will gather the Instance Information up front # Gather the instances we know are not contactable BeforeDiscovery { # Gather the instances we know are not contactable [string[]]$NotContactable = (Get-PSFConfig -Module dbachecks -Name global.notcontactable).Value # Get all the tags in use in this run $Tags = Get-CheckInformation -Check $Check -Group Agent -AllChecks $AllChecks -ExcludeCheck $ChecksToExclude $InstancesToTest = @(Get-Instance).ForEach{ # just add it to the Not Contactable list if ($NotContactable -notcontains $psitem) { $Instance = $psitem try { $InstanceSMO = Connect-DbaInstance -SqlInstance $Instance -ErrorAction SilentlyContinue -ErrorVariable errorvar } catch { $NotContactable += $Instance } if ($NotContactable -notcontains $psitem) { if ($null -eq $InstanceSMO.version) { $NotContactable += $Instance } # ToDo: Give cool message about Agent not existing on Express Edition?! elseif (($InstanceSMO).Edition -like "Express Edition*") {} else { # Get the relevant information for the checks in one go to save repeated trips to the instance and set values for Not Contactable tests if required Get-AllAgentInfo -Instance $InstanceSMO -Tags $Tags } } } } #TODO : Clean this up Write-PSFMessage -Message "Instances = $($InstancesToTest.Name)" -Level Verbose Set-PSFConfig -Module dbachecks -Name global.notcontactable -Value $NotContactable # Get-DbcConfig is expensive so we call it once $__dbcconfig = Get-DbcConfig } Describe "Database Mail XPs" -Tag DatabaseMailEnabled, CIS, security, Agent -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.databasemailenabled' }).Value Context "Testing Database Mail XPs on <_.Name>" { It "Testing Database Mail XPs is set to <_.ConfigValues.DatabaseMailEnabled> on <_.Name>" -Skip:$skip { $PSItem.DatabaseMailEnabled | Should -Be $PSItem.ConfigValues.DatabaseMailEnabled -Because 'The Database Mail XPs setting should be set correctly' } } } Describe "SQL Agent Account" -Tag AgentServiceAccount, ServiceAccount, Agent -ForEach $InstancesToTest { $skipServiceState = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.servicestate' }).Value $skipServiceStartMode = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.servicestartmode' }).Value Context "Testing SQL Agent is running on <_.Name>" { It "SQL Agent should be running for <_.InstanceName> on <_.Name>" -Skip:$skipServiceState { $PSItem.Agent.State | Should -Be "Running" -Because 'The agent service is required to run SQL Agent jobs' } } if ($PSItem.IsClustered) { It "SQL Agent service should have a start mode of Manual for FailOver Clustered Instance <_.InstanceName> on <_.Name>" -Skip:$skipServiceStartMode { $PSItem.Agent.StartMode | Should -Be "Manual" -Because 'Clustered Instances required that the Agent service is set to manual' } } else { It "SQL Agent service should have a start mode of Automatic for standalone instance <_.InstanceName> on <_.Name>" -Skip:$skipServiceStartMode { $PSItem.Agent.StartMode | Should -Be "Automatic" -Because 'Otherwise the Agent Jobs wont run if the server is restarted' } } } Describe "DBA Operator" -Tag DbaOperator, Operator, Agent -ForEach $InstancesToTest { $skipOperatorName = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.dbaoperatorname' }).Value $skipOperatorEmail = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.dbaoperatoremail' }).Value Context "Testing DBA Operators exists on <_.Name>" { It "The Operator <_.ExpectedOperatorName> exists on <_.Name>" -Skip:$skipOperatorName -ForEach ($PSItem.Operator | Where-Object ExpectedOperatorName -NE 'null') { $PSItem.ExpectedOperatorName | Should -BeIn $PSItem.ActualOperatorName -Because 'This Operator is expected to exist' } It "The Operator email <_.ExpectedOperatorEmail> is correct on <_.Name>" -Skip:$skipOperatorEmail -ForEach ($PSItem.Operator | Where-Object ExpectedOperatorEmail -NE 'null') { $PSItem.ExpectedOperatorEmail | Should -BeIn $PSItem.ActualOperatorEmail -Because 'This operator email is expected to exist' } } } Describe "Failsafe operator" -Tag FailsafeOperator, Operator, Agent -ForEach $InstancesToTest { $skipFailsafeOperator = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.failsafeoperator' }).Value Context "Testing failsafe operator exists on <_.Name>" { It "The failsafe operator <_.FailSafeOperator.ExpectedFailSafeOperator> exists on <_.Name>" -Skip:$skipFailsafeOperator { $PSItem.FailSafeOperator.ActualFailSafeOperator | Should -Be $PSItem.FailSafeOperator.ExpectedFailSafeOperator -Because 'The failsafe operator will ensure that any job failures will be notified to someone if not set explicitly' } } } Describe "Database Mail Profile" -Tag DatabaseMailProfile, Agent -ForEach $InstancesToTest { $skipDatabaseMailProfile = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.databasemailprofile' }).Value Context "Testing Database Mail Profile exists on <_.Name>" { It "The Database Mail profile <_.DatabaseMailProfile.ExpectedDatabaseMailProfile> exists on <_.Name>" -Skip:$skipDatabaseMailProfile { #-ForEach ($PSItem.DatabaseMailProfile | Where-Object ExpectedDatabaseMailProfile -NE 'null') { $PSItem.DatabaseMailProfile.ActualDatabaseMailProfile | Should -BeIn $PSItem.DatabaseMailProfile.ExpectedDatabaseMailProfile -Because 'The database mail profile is required to send emails' } } } Describe "Agent Mail Profile" -Tag AgentMailProfile, Agent -ForEach $InstancesToTest { $skipAgentMailProfile = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.mailprofile' }).Value Context "Testing SQL Agent Alert System database mail profile is set on <_.Name>" { It "The SQL Server Agent Alert System has the mail profile <_.AgentMailProfile.ExpectedAgentMailProfile> enabled as profile on <_.Name>." -Skip:$skipAgentMailProfile { #-ForEach ($PSItem.DatabaseMailProfile | Where-Object ExpectedDatabaseMailProfile -NE 'null') { $PSItem.AgentMailProfile.ActualAgentMailProfile | Should -Be $PSItem.AgentMailProfile.ExpectedAgentMailProfile -Because 'The SQL Agent Alert System needs an enabled database mail profile to send alert emails' } } } Describe "Valid Job Owner" -Tag ValidJobOwner, Agent -ForEach $InstancesToTest { $skipAgentJobTargetOwner = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.jobowner' }).Value Context "Testing SQL Agent Job Owner on <_.Name>" { It "The Job <_.JobName> has the Job Owner <_.ActualJobOwnerName> that should exist in this list ($([String]::Join(', ', "<_.ExpectedJobOwnerName>"))) on <_.InstanceName>" -Skip:$skipAgentJobTargetOwner -ForEach ($PSItem.JobOwner) { $PSItem.ActualJobOwnerName | Should -BeIn $PSItem.ExpectedJobOwnerName -Because 'The account that is the job owner is not what was expected' } } } Describe "Invalid Job Owner" -Tag InvalidJobOwner, Agent -ForEach $InstancesToTest { $skipAgentJobTargetInvalidOwner = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.invalidjobowner.name' }).Value Context "Testing Invalid SQL Agent Job Owner on <_.Name>" { It "The Job <_.JobName> has the Job Owner <_.ActualJobOwnerName> that shouldn't exist in this list ($([String]::Join(', ', "<_.InvalidJobOwnerName>"))) on <_.InstanceName>" -Skip:$skipAgentJobTargetInvalidOwner -ForEach ($PSItem.InvalidJobOwner) { $PSItem.ActualJobOwnerName | Should -Not -BeIn $PSItem.InvalidJobOwnerName -Because 'The account that is the job owner has been defined as not valid' } } } Describe "Last Agent Job Run" -Tag LastJobRunTime, Agent -ForEach $InstancesToTest { $skipAgentJobLastRun = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.lastjobruntime' }).Value Context "Testing last job run time on <_.Name>" { It "Job <_.JobName> last run duration (<_.Duration> seconds) should not be greater than <_.ExpectedRunningJobPercentage>% extra of the average run time (<_.Average> seconds) on <_.InstanceName>" -Skip:$skipAgentJobLastRun -ForEach ($PSItem.LastJobRuns) { $PSItem.ActualRunningJobPercentage | Should -BeLessThan $PSItem.ExpectedRunningJobPercentage -Because "The last run of job $($PSItem.JobName) was $($PSItem.Duration) seconds. This is more than the $($PSItem.ExpectedRunningJobPercentage)% specified as the maximum variance" } } } Describe "Long Running Agent Jobs" -Tag LongRunningJob, Agent -ForEach $InstancesToTest { $skipAgentLongRunningJobs = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.longrunningjobs' }).Value Context "Testing long running jobs on <_.Name>" { It "Running job <_.JobName> duration should not be more than <_.ExpectedLongRunningJobPercentage>% extra of the average run time (<_.Average> seconds) on <_.InstanceName>" -Skip:$skipAgentLongRunningJobs -ForEach ($PSItem.LongRunningJobs) { $PSItem.ActualLongRunningJobPercentage | Should -BeLessThan $PSItem.ExpectedLongRunningJobPercentage -Because "The current running job $($PSItem.JobName) has been running for $($PSItem.Diff) seconds longer than the average run time. This is more than the $($PSItem.ExpectedLongRunningJobPercentage)% specified as the maximum" } } } Describe "SQL Agent Failed Jobs" -Tag FailedJob, Agent -ForEach $InstancesToTest { $skipAgentFailedJobs = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.failedjobs' }).Value $excludecancelled = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.failedjob.excludecancelled' }).Value Context "Checking for failed enabled jobs since on <_.Name>" { if (-not $skipAgentFailedJobs) { It "We chose to skip this as <_.JobName>'s last run outcome is unknown on <_.InstanceName>" -Skip -ForEach ($PSItem.JobsFailed | Where-Object { $_.LastRunOutcome -eq "Unknown" }) { $PSItem.LastRunOutcome | Should -Be $PSItem.ExpectedOutcome -Because 'All Agent Jobs should have succeed this one is unknown - you need to investigate the failed jobs' } It "You chose to skip this as <_.JobName>'s last run outcome is cancelled on <_.InstanceName>" -Skip -ForEach ($PSItem.JobsFailed | Where-Object { $_.LastRunOutcome -eq "Cancelled" -and ($excludecancelled -eq $true) }) { $PSItem.LastRunOutcome | Should -Be $PSItem.ExpectedOutcome -Because 'All Agent Jobs should have succeed this one is Cancelled - you need to investigate the failed jobs' } } It "Job <_.JobName> last run outcome is <_.LastRunOutcome> on <_.InstanceName>" -Skip:$skipAgentFailedJobs -ForEach ($PSItem.JobsFailed | Where-Object { $_.LastRunOutcome -notin ("Cancelled", "Unknown") }) { $PSItem.LastRunOutcome | Should -Be $PSItem.ExpectedOutcome -Because "All Agent Jobs should have succeed - you need to investigate the failed jobs" } } } Describe "Agent Alerts" -Tag AgentAlert, Agent -ForEach $InstancesToTest { $skipAgentAlerts = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.alert' }).Value $AgentAlertJob = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.alert.Job' }).Value $AgentAlertNotification = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.alert.Notification' }).Value Context "Testing Agent Alerts Severity exists on <_.Name>" { It "Severity <_.AgentAlertSeverity> Alert should exist on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.Severities) { #| Where-Object { $_.Severity -NE $null }) { $PSItem.Severity | Should -Be $PSItem.AgentAlertSeverity -Because "Recommended Agent Alerts to exists http://blog.extreme-advice.com/2013/01/29/list-of-errors-and-severity-level-in-sql-server-with-catalog-view-sysmessages/" } It "Severity <_.AgentAlertSeverity> Alert should be enabled on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.Severities) { $PSItem.IsEnabled | Should -Be $true -Because "Configured alerts should be enabled" } if ($AgentAlertJob) { It "A job name for Severity <_.AgentAlertSeverity> Alert on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.Severities) { $PSItem.JobName -ne $null | Should -Be $true -Because "Should notify by SQL Agent Job" } } if ($AgentAlertNotification) { It "Severity <_.AgentAlertSeverity> Alert should have a notification on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.Severities) { $PSItem.HasNotification -in 1, 2, 3, 4, 5, 6, 7 | Should -Be $true -Because "Should notify by Agent notifications" } } } Context "Testing Agent Alerts MessageID exists on <_.Name>" { It "MessageID <_.AgentMessageID> Alert should exist on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.MessageIDs) { $PSItem.MessageID | Should -Be $PSItem.AgentMessageID -Because "Recommended Agent Alerts to exists http://blog.extreme-advice.com/2013/01/29/list-of-errors-and-severity-level-in-sql-server-with-catalog-view-sysmessages/" } It "MessageID <_.AgentMessageID> Alert should be enabled on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.MessageIDs) { $PSItem.IsEnabled | Should -Be $true -Because "Configured alerts should be enabled" } if ($AgentAlertJob) { It "A job name for MessageID <_.AgentMessageID> on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.MessageIDs) { $PSItem.JobName -ne $null | Should -Be $true -Because "Should notify by SQL Agent Job" } } if ($AgentAlertNotification) { It "MessageID <_.AgentMessageID> Alert should have a notification on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.MessageIDs) { $PSItem.HasNotification -in 1, 2, 3, 4, 5, 6, 7 | Should -Be $true -Because "Should notify by Agent notifications" } } } } Describe "Job History Configuration" -Tag JobHistory, Agent -ForEach $InstancesToTest { $skipAgentJobHistory = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.JobHistory' }).Value [int]$minimumJobHistoryRows = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.history.maximumhistoryrows' }).Value if ($minimumJobHistoryRows -eq -1) { It "The maximum job history configuration should be set to disabled on <_.InstanceName>" -Skip:$skipAgentJobHistory -ForEach ($PSItem.JobHistory) { $PSItem.CurrentMaximumHistoryRows | Should -Be $PSItem.ExpectedMaximumHistoryRows -Because "Maximum job history configuration should be disabled" } } else { It "The maximum job history number of rows configuration should be greater or equal to <_.ExpectedMaximumHistoryRows> on <_.InstanceName>" -Skip:$skipAgentJobHistory -ForEach ($PSItem.JobHistory) { $PSItem.CurrentMaximumHistoryRows | Should -BeGreaterOrEqual $PSItem.ExpectedMaximumHistoryRows -Because "We expect the maximum job history row configuration to be greater than the configured setting <_.ExpectedMaximumHistoryRows>" } It "The maximum job history rows per job configuration should be greater or equal to <_.ExpectedMaximumJobHistoryRows> on <_.InstanceName>" -Skip:$skipAgentJobHistory -ForEach ($PSItem.JobHistory) { $PSItem.CurrentMaximumJobHistoryRows | Should -BeGreaterOrEqual $PSItem.ExpectedMaximumJobHistoryRows -Because "We expect the maximum job history row configuration per agent job to be greater than the configured setting <_.ExpectedMaximumJobHistoryRows>" } } } ================================================ FILE: source/checks/Database.Tests.ps1 ================================================ $filename = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") . $PSScriptRoot/../internal/assertions/Database.Assertions.ps1 [array]$ExcludedDatabases = Get-DbcConfigValue command.invokedbccheck.excludedatabases $ExcludedDatabases += $ExcludeDatabase [string[]]$NotContactable = (Get-PSFConfig -Module dbachecks -Name global.notcontactable).Value @(Get-Instance).ForEach{ if ($NotContactable -notcontains $psitem) { $Instance = $psitem try { $InstanceSMO = Connect-DbaInstance -SqlInstance $Instance -ErrorAction SilentlyContinue -ErrorVariable errorvar } catch { $NotContactable += $Instance } if ($NotContactable -notcontains $psitem) { if ($null -eq $InstanceSMO.version) { $NotContactable += $Instance } else { $Version = $InstanceSMO.VersionMajor } } } Set-PSFConfig -Module dbachecks -Name global.notcontactable -Value $NotContactable Describe "Database Collation" -Tags DatabaseCollation, High, $filename { $Wrongcollation = Get-DbcConfigValue policy.database.wrongcollation $exclude = "ReportingServer", "ReportingServerTempDB" $exclude += $Wrongcollation $exclude += $ExcludedDatabases if ($NotContactable -contains $psitem) { Context "Testing database collation on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing database collation on $psitem" { @(Test-DbaDbCollation -SqlInstance $psitem -Database $Database -ExcludeDatabase $exclude).ForEach{ It "Database $($psitem.Database) collation ($($psitem.DatabaseCollation)) should match server collation ($($psitem.ServerCollation)) on $($psitem.SqlInstance)" { $psitem.ServerCollation | Should -Be $psitem.DatabaseCollation -Because "You will get collation conflict errors in tempdb" } } if ($Wrongcollation) { @(Test-DbaDbCollation -SqlInstance $psitem -Database $Wrongcollation ).ForEach{ It "Database $($psitem.Database) collation ($($psitem.DatabaseCollation)) should not match server collation ($($psitem.ServerCollation)) on $($psitem.SqlInstance)" { $psitem.ServerCollation | Should -Not -Be $psitem.DatabaseCollation -Because "You have defined the database to have another collation then the server. You will get collation conflict errors in tempdb" } } } } } } Describe "Suspect Page" -Tags SuspectPage, High, $filename { if ($NotContactable -contains $psitem) { Context "Testing suspect pages on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing suspect pages on $psitem" { $InstanceSMO.Databases.Where{ if ($Database) { $_.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name } }.ForEach{ $results = Get-DbaSuspectPage -SqlInstance $psitem.Parent -Database $psitem.Name It "Database $($psitem.Name) should return 0 suspect pages on $($psitem.Parent.Name)" { @($results).Count | Should -Be 0 -Because "You do not want suspect pages" } } } } } Describe "Last Backup Restore Test" -Tags TestLastBackup, Backup, $filename { if (-not (Get-DbcConfigValue skip.backup.testing)) { $destserver = Get-DbcConfigValue policy.backup.testserver $destdata = Get-DbcConfigValue policy.backup.datadir $destlog = Get-DbcConfigValue policy.backup.logdir if ($NotContactable -contains $psitem) { Context "Testing Backup Restore & Integrity Checks on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { if (-not $destserver) { $destserver = $psitem } Context "Testing Backup Restore & Integrity Checks on $psitem" { $srv = Connect-DbaInstance -SqlInstance $psitem $dbs = ($srv.Databases.Where{ $_.CreateDate.ToUniversalTime() -lt (Get-Date).ToUniversalTime().AddHours( - $graceperiod) -and $(if ($Database) { $_.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name }) }).Name if (-not ($destdata)) { $destdata -eq $srv.DefaultFile } if (-not ($destlog)) { $destlog -eq $srv.DefaultLog } @(Test-DbaLastBackup -SqlInstance $psitem -Database $dbs -Destination $destserver -DataDirectory $destdata -LogDirectory $destlog -VerifyOnly).ForEach{ if ($psitem.DBCCResult -notmatch "skipped for restored master") { It "Database $($psitem.Database) DBCC CheckDB should be success on $($psitem.SourceServer)" { $psitem.DBCCResult | Should -Be "Success" -Because "You need to run DBCC CHECKDB to ensure your database is consistent" } It "Database $($psitem.Database) restore should be success on $($psitem.SourceServer)" { $psitem.RestoreResult | Should -Be "Success" -Because "The backup file has not successfully restored - you have no backup" } } } } } } } Describe "Last Backup VerifyOnly" -Tags TestLastBackupVerifyOnly, Backup, $filename { $graceperiod = Get-DbcConfigValue policy.backup.newdbgraceperiod if ($NotContactable -contains $psitem) { Context "VerifyOnly tests of last backups on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "VerifyOnly tests of last backups on $psitem" { $DatabasesToCheck = ($InstanceSMO.Databases.Where{ $_.IsAccessible -eq $true }.Where{ $_.CreateDate.ToUniversalTime() -lt (Get-Date).ToUniversalTime().AddHours( - $graceperiod) -and $(if ($Database) { $_.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name }) }).Name $BackUpVerify = $DatabasesToCheck.Foreach{ $BackupVerifySplat = @{ SqlInstance = $InstanceSMO Database = $psitem VerifyOnly = $true EnableException = $true } try { Test-DbaLastBackup @BackupVerifySplat } catch { [pscustomobject]@{ $psitem.RestoreResult = $_.Exception.Message $psitem.FileExists = $_.Exception.Message } } } $BackUpVerify.ForEach{ It "Database $($psitem.Database) restore for Database should be success for $($psitem.SourceServer)" { $psitem.RestoreResult | Should -Be "Success" -Because "The restore file has not successfully verified - you have no backup" } It "Database $($psitem.Database) last backup file exists for $($psitem.SourceServer)" { $psitem.FileExists | Should -BeTrue -Because "Without a backup file you have no backup" } } } } } Describe "Valid Database Owner" -Tags ValidDatabaseOwner, Medium, $filename { [string[]]$targetowner = Get-DbcConfigValue policy.validdbowner.name [string[]]$exclude = Get-DbcConfigValue policy.validdbowner.excludedb $exclude += $ExcludedDatabases if ($NotContactable -contains $psitem) { Context "Testing Database Owners on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Database Owners on $psitem" { @($InstanceSMO.Databases.Where{ if ($database) { $_.Name -in $database }else { $_.Name -notin $exclude } }).ForEach{ It "Database $($psitem.Name) - owner $($psitem.Owner) should be in this list ( $( [String]::Join(", ", $targetowner) ) ) on $($psitem.Parent.Name)" { $psitem.Owner | Should -BeIn $TargetOwner -Because "The account that is the database owner is not what was expected" } } } } } Describe "Invalid Database Owner" -Tags InvalidDatabaseOwner, Medium, $filename { [string[]]$targetowner = Get-DbcConfigValue policy.invaliddbowner.name [string[]]$exclude = Get-DbcConfigValue policy.invaliddbowner.excludedb $exclude += $ExcludedDatabases if ($NotContactable -contains $psitem) { Context "Testing Database Owners on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Database Owners on $psitem" { @($InstanceSMO.Databases.Where{ if ($database) { $_.Name -in $database }else { $_.Name -notin $exclude } }).ForEach{ It "Database $($psitem.Name) - owner $($psitem.Owner) should Not be in this list ( $( [String]::Join(", ", $targetowner) ) ) on $($psitem.Parent.Name)" { $psitem.Owner | Should -Not -BeIn $TargetOwner -Because "The database owner was one specified as incorrect" } } } } } Describe "Last Good DBCC CHECKDB" -Tags LastGoodCheckDb, Varied, $filename { $maxdays = Get-DbcConfigValue policy.dbcc.maxdays $datapurity = Get-DbcConfigValue skip.dbcc.datapuritycheck $graceperiod = Get-DbcConfigValue policy.backup.newdbgraceperiod if ($NotContactable -contains $psitem) { Context "Testing Last Good DBCC CHECKDB on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Last Good DBCC CHECKDB on $psitem" { @(Get-DbaLastGoodCheckDb -SqlInstance $psitem -Database ($InstanceSMO.Databases.Where{ $_.CreateDate.ToUniversalTime() -lt (Get-Date).ToUniversalTime().AddHours( - $graceperiod) -and ($_.IsAccessible -eq $true) -and $(if ($database) { $psitem.name -in $Database }else { $ExcludedDatabases -notcontains $_.Name }) }).Name ).ForEach{ if ($psitem.Database -ne "tempdb") { It "Database $($psitem.Database) last good integrity check should be less than $maxdays days old on $($psitem.SqlInstance)" { if ($psitem.LastGoodCheckDb) { $psitem.LastGoodCheckDb | Should -BeGreaterThan (Get-Date).ToUniversalTime().AddDays( - ($maxdays)) -Because "You should have run a DBCC CheckDB inside that time" } else { $psitem.LastGoodCheckDb | Should -BeGreaterThan (Get-Date).ToUniversalTime().AddDays( - ($maxdays)) -Because "You should have run a DBCC CheckDB inside that time" } } It -Skip:$datapurity "Database $($psitem.Database) has Data Purity Enabled on $($psitem.SqlInstance)" { $psitem.DataPurityEnabled | Should -BeTrue -Because "the DATA_PURITY option causes the CHECKDB command to look for column values that are invalid or out of range." } } } } } } Describe "Column Identity Usage" -Tags IdentityUsage, Medium, $filename { $maxpercentage = Get-DbcConfigValue policy.identity.usagepercent if ($NotContactable -contains $psitem) { Context "Testing Column Identity Usage on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Column Identity Usage on $psitem" { if ($version -lt 10) { It "Database dbachecksskipped Testing Column Identity Usage on $Instance" -Skip { Assert-DatabaseDuplicateIndex -Instance $instance -Database $psitem } } else { $exclude = $ExcludedDatabases $exclude += $InstanceSMO.Databases.Where{ $_.IsAccessible -eq $false }.Name @(Test-DbaIdentityUsage -SqlInstance $psitem -Database $Database -ExcludeDatabase $exclude).ForEach{ if ($psitem.Database -ne "tempdb") { $columnfqdn = "$($psitem.Database).$($psitem.Schema).$($psitem.Table).$($psitem.Column)" It "Database $($psitem.Database) - The usage for $columnfqdn should be less than $maxpercentage percent on $($psitem.SqlInstance)" { $psitem.PercentUsed -lt $maxpercentage | Should -BeTrue -Because "You do not want your Identity columns to hit the max value and stop inserts" } } } } } } } Describe "Recovery Model" -Tags RecoveryModel, DISA, Medium, $filename { if ($NotContactable -contains $psitem) { Context "Testing Recovery Model on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { $recoverymodel = Get-DbcConfigValue policy.recoverymodel.type Context "Testing Recovery Model on $psitem" { $exclude = Get-DbcConfigValue policy.recoverymodel.excludedb $exclude += $ExcludedDatabases @(Get-DbaDbRecoveryModel -SqlInstance $psitem -Database $Database -ExcludeDatabase $exclude).ForEach{ It "Database $($psitem.Name) should be set to $recoverymodel on $($psitem.SqlInstance)" { $psitem.RecoveryModel | Should -Be $recoverymodel -Because "You expect this recovery model" } } } } } Describe "Duplicate Index" -Tags DuplicateIndex, $filename { $Excludeddbs = Get-DbcConfigValue policy.database.duplicateindexexcludedb $Excludeddbs += $ExcludedDatabases if ($NotContactable -contains $psitem) { Context "Testing duplicate indexes on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing duplicate indexes on $psitem" { if ($version -lt 10) { It "Database dbachecksskipped should return 0 duplicate indexes on $Instance" -Skip { Assert-DatabaseDuplicateIndex -Instance $instance -Database $psitem } } else { $instance = $Psitem @(Get-Database -Instance $instance -Requiredinfo Name -Exclusions NotAccessible -Database $Database -ExcludedDbs $Excludeddbs).ForEach{ It "Database $psitem should return 0 duplicate indexes on $Instance" { Assert-DatabaseDuplicateIndex -Instance $instance -Database $psitem } } } } } } Describe "Unused Index" -Tags UnusedIndex, Medium, $filename { if ($NotContactable -contains $psitem) { Context "Testing Unused indexes on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Unused indexes on $psitem" { try { $Instance = $Psitem (Get-Database -Instance $Instance -RequiredInfo Name -Exclusions NotAccessible -Database $Database -ExcludedDbs $Excludeddbs).ForEach{ $results = Find-DbaDbUnusedIndex -SqlInstance $psitem -Database $Database -ExcludeDatabase $ExcludedDatabases -EnableException It "Database $psitem should return 0 Unused indexes on $($psitem.SQLInstance)" { @($results).Count | Should -Be 0 -Because "You should have indexes that are used" } } } catch { It -Skip "Database $psitem should return 0 Unused indexes on $($psitem.SQLInstance)" { @($results).Count | Should -Be 0 -Because "You should have indexes that are used" } } } } } Describe "Disabled Index" -Tags DisabledIndex, Medium, $filename { if ($NotContactable -contains $psitem) { Context "Testing Disabled indexes on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Disabled indexes on $psitem" { $InstanceSMO.Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name }) -and ($_.IsAccessible -eq $true) }.ForEach{ $results = Find-DbaDbDisabledIndex -SqlInstance $psitem.Parent -Database $psitem.Name It "Database $($psitem.Name) should return 0 Disabled indexes on $($psitem.Parent.Name)" { @($results).Count | Should -Be 0 -Because "Disabled indexes are wasting disk space" } } } } } Describe "Database Growth Event" -Tags DatabaseGrowthEvent, Low, $filename { $exclude = Get-DbcConfigValue policy.database.filegrowthexcludedb $daystocheck = Get-DbcConfigValue policy.database.filegrowthdaystocheck if ($null -eq $daystocheck) { $datetocheckfrom = '0001-01-01' } else { $datetocheckfrom = (Get-Date).ToUniversalTime().AddDays( - $daystocheck) } if ($NotContactable -contains $psitem) { Context "Testing database growth event on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing database growth event on $psitem" { $InstanceSMO.Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $PSItem.Name -notin $exclude -and ($ExcludedDatabases -notcontains $PsItem.Name) }) }.ForEach{ $results = @(Find-DbaDbGrowthEvent -SqlInstance $psitem.Parent -Database $psitem.Name).Where{ $_.StartTime -gt $datetocheckfrom } It "Database $($psitem.Name) should return 0 database growth events on $($psitem.Parent.Name)" { @($results).Count | Should -Be 0 -Because "You want to control how your database files are grown" } } } } } Describe "Page Verify" -Tags PageVerify, Medium, $filename { $pageverify = Get-DbcConfigValue policy.pageverify if ($NotContactable -contains $psitem) { Context "Testing page verify on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing page verify on $psitem" { switch ($version) { 8 { It "Database Page verify is not available on SQL 2000 on $psitem" { $true | Should -BeTrue } } 9 { $InstanceSMO.Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name }) }.ForEach{ if ($Psitem.Name -ne 'tempdb') { It "Database $($psitem.Name) should have page verify set to $pageverify on $($psitem.Parent.Name)" { $psitem.PageVerify | Should -Be $pageverify -Because "Page verify helps SQL Server to detect corruption" } } else { It "Database Page verify is not available on tempdb on SQL 2005 on $($psitem.Parent.Name)" { $true | Should -BeTrue } } } } Default { $InstanceSMO.Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name }) }.ForEach{ It "Database $($psitem.Name) should have page verify set to $pageverify on $($psitem.Parent.Name)" { $psitem.PageVerify | Should -Be $pageverify -Because "Page verify helps SQL Server to detect corruption" } } } } } } } Describe "Auto Close" -Tags AutoClose, High, $filename { $autoclose = Get-DbcConfigValue policy.database.autoclose if ($NotContactable -contains $psitem) { Context "Testing Auto Close on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Auto Close on $psitem" { $InstanceSMO.Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name }) }.ForEach{ It "Database $($psitem.Name) should have Auto Close set to $autoclose on $($psitem.Parent.Name)" { $psitem.AutoClose | Should -Be $autoclose -Because "Because!" } } } } } Describe "Auto Shrink" -Tags AutoShrink, High, $filename { $autoshrink = Get-DbcConfigValue policy.database.autoshrink if ($NotContactable -contains $psitem) { Context "Testing Auto Shrink on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Auto Shrink on $psitem" { $InstanceSMO.Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name }) }.ForEach{ It "Database $($psitem.Name) should have Auto Shrink set to $autoshrink on $($psitem.Parent.Name)" { $psitem.AutoShrink | Should -Be $autoshrink -Because "Shrinking databases causes fragmentation and performance issues" } } } } } Describe "Last Full Backup Times" -Tags LastFullBackup, LastBackup, Backup, DISA, Varied, $filename { $maxfull = Get-DbcConfigValue policy.backup.fullmaxdays $graceperiod = Get-DbcConfigValue policy.backup.newdbgraceperiod $skipreadonly = Get-DbcConfigValue skip.backup.readonly $skipsecondaries = Get-DbcConfigValue skip.backup.secondaries if ($NotContactable -contains $psitem) { Context "Testing last full backups on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing last full backups on $psitem" { $InstanceSMO.Databases.Where{ ($psitem.Name -ne 'tempdb') -and $Psitem.CreateDate.ToUniversalTime() -lt (Get-Date).ToUniversalTime().AddHours( - $graceperiod) -and $(if ($Database) { $PsItem.Name -in $Database } else { $ExcludedDatabases -notcontains $PsItem.Name }) }.ForEach{ if ($psitem.AvailabilityGroupName) { $agReplicaRole = $InstanceSMO.AvailabilityGroups[$psitem.AvailabilityGroupName].LocalReplicaRole } else { $agReplicaRole = $null } $skip = ($psitem.Status -match "Offline") -or ($psitem.IsAccessible -eq $false) -or ($psitem.Readonly -eq $true -and $skipreadonly -eq $true) -or ($agReplicaRole -eq 'Secondary' -and $skipsecondaries -eq $true) It -Skip:$skip "Database $($psitem.Name) should have full backups less than $maxfull days old on $($psitem.Parent.Name)" { $psitem.LastBackupDate.ToUniversalTime() | Should -BeGreaterThan (Get-Date).ToUniversalTime().AddDays( - ($maxfull)) -Because "Taking regular backups is extraordinarily important" } } } } } Describe "Last Diff Backup Times" -Tags LastDiffBackup, LastBackup, Backup, DISA, Varied, $filename { if (-not (Get-DbcConfigValue skip.diffbackuptest)) { $maxdiff = Get-DbcConfigValue policy.backup.diffmaxhours $graceperiod = Get-DbcConfigValue policy.backup.newdbgraceperiod $skipreadonly = Get-DbcConfigValue skip.backup.readonly $skipsecondaries = Get-DbcConfigValue skip.backup.secondaries if ($NotContactable -contains $psitem) { Context "Testing last diff backups on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing last diff backups on $psitem" { @($InstanceSMO.Databases.Where{ (-not $psitem.IsSystemObject) -and $Psitem.CreateDate.ToUniversalTime() -lt (Get-Date).ToUniversalTime().AddHours( - $graceperiod) -and $(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name }) }).ForEach{ if ($psitem.AvailabilityGroupName) { $agReplicaRole = $InstanceSMO.AvailabilityGroups[$psitem.AvailabilityGroupName].LocalReplicaRole } else { $agReplicaRole = $null } $skip = ($psitem.Status -match "Offline") -or ($psitem.IsAccessible -eq $false) -or ($psitem.Readonly -eq $true -and $skipreadonly -eq $true) -or ($agReplicaRole -eq 'Secondary' -and $skipsecondaries -eq $true) It -Skip:$skip "Database $($psitem.Name) diff backups should be less than $maxdiff hours old on $($psitem.Parent.Name)" { ($psitem.LastBackupDate.ToUniversalTime(), $psitem.LastDifferentialBackupDate.ToUniversalTime() | Measure-Object -Max).Maximum | Should -BeGreaterThan (Get-Date).ToUniversalTime().AddHours( - ($maxdiff)) -Because 'Taking regular backups is extraordinarily important' } } } } } } Describe "Last Log Backup Times" -Tags LastLogBackup, LastBackup, Backup, DISA, Varied, $filename { $maxlog = Get-DbcConfigValue policy.backup.logmaxminutes $graceperiod = Get-DbcConfigValue policy.backup.newdbgraceperiod $skipreadonly = Get-DbcConfigValue skip.backup.readonly $skipsecondaries = Get-DbcConfigValue skip.backup.secondaries [DateTime]$sqlinstancedatetime = $InstanceSMO.Query("SELECT getutcdate() as getutcdate").getutcdate [DateTime]$oldestbackupdateallowed = $sqlinstancedatetime.AddHours( - $graceperiod) if ($NotContactable -contains $psitem) { Context "Testing last log backups on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing last log backups on $psitem" { @($InstanceSMO.Databases.Where{ (-not $psitem.IsSystemObject) -and $Psitem.CreateDate.ToUniversalTime() -lt $oldestbackupdateallowed -and $(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name }) }).ForEach{ if ($psitem.RecoveryModel -ne "Simple") { if ($psitem.AvailabilityGroupName) { $agReplicaRole = $InstanceSMO.AvailabilityGroups[$psitem.AvailabilityGroupName].LocalReplicaRole } else { $agReplicaRole = $null } $skip = ($psitem.Status -match "Offline") -or ($psitem.IsAccessible -eq $false) -or ($psitem.Readonly -eq $true -and $skipreadonly -eq $true) -or ($agReplicaRole -eq 'Secondary' -and $skipsecondaries -eq $true) It -Skip:$skip "Database $($psitem.Name) log backups should be less than $maxlog minutes old on $($psitem.Parent.Name)" { $psitem.LastLogBackupDate.ToUniversalTime() | Should -BeGreaterThan $sqlinstancedatetime.AddMinutes( - ($maxlog) + 1) -Because "Taking regular backups is extraordinarily important" } } } } } } Describe "Log File percent used" -Tags LogfilePercentUsed, Medium, $filename { $LogFilePercentage = Get-DbcConfigValue policy.database.logfilepercentused if ($NotContactable -contains $psitem) { Context "Testing Log File percent used for $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Log File percent used for $psitem" { $InstanceSMO.Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name }) -and ($Psitem.IsAccessible -eq $true) }.ForEach{ $LogFiles = Get-DbaDbSpace -SqlInstance $psitem.Parent.Name -Database $psitem.Name | Where-Object { $_.FileType -eq "LOG" } $DatabaseName = $psitem.Name $CurrentLogFilePercentage = ($LogFiles | Measure-Object -Property PercentUsed -Maximum).Maximum It "Database $DatabaseName Should have a percentage used lower than $LogFilePercentage% on $($psitem.Parent.Name)" { $CurrentLogFilePercentage | Should -BeLessThan $LogFilePercentage -Because "Check backup strategy, open transactions, CDC, Replication and HADR solutions " } } } } } Describe "Virtual Log Files" -Tags VirtualLogFile, Medium, $filename { $vlfmax = Get-DbcConfigValue policy.database.maxvlf if ($NotContactable -contains $psitem) { Context "Testing Database VLFs on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Database VLFs on $psitem" { @(Measure-DbaDbVirtualLogFile -SqlInstance $psitem -ExcludeDatabase $ExcludedDatabases -Database $Database).ForEach{ It "Database $($psitem.Database) VLF count should be less than $vlfmax on $($psitem.SqlInstance)" { $psitem.Total | Should -BeLessThan $vlfmax -Because "Too many VLFs can impact performance and slow down backup/restore" } } } } } Describe "Log File Count Checks" -Tags LogfileCount, Medium, $filename { $LogFileCountTest = Get-DbcConfigValue skip.database.logfilecounttest $LogFileCount = Get-DbcConfigValue policy.database.logfilecount If (-not $LogFileCountTest) { if ($NotContactable -contains $psitem) { Context "Testing Log File count for $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Log File count for $psitem" { @($InstanceSMO.Databases.Where{ if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name -and ($Psitem.IsAccessible -eq $true) } }).ForEach{ $Files = Get-DbaDbFile -SqlInstance $psitem.Parent.Name -Database $psitem.Name $LogFiles = $Files | Where-Object { $_.TypeDescription -eq "LOG" } It "Database $($psitem.Name) Should have $LogFileCount or less Log files on $($psitem.Parent.Name)" { $LogFiles.Count | Should -BeLessOrEqual $LogFileCount -Because "You want the correct number of log files" } } } } } } Describe "Log File Size Checks" -Tags LogfileSize, Medium, $filename { $LogFileSizePercentage = Get-DbcConfigValue policy.database.logfilesizepercentage $LogFileSizeComparison = Get-DbcConfigValue policy.database.logfilesizecomparison if ($NotContactable -contains $psitem) { Context "Testing Log File size for $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Log File size for $psitem" { $InstanceSMO.Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name }) -and ($Psitem.IsAccessible -eq $true) }.ForEach{ $Files = Get-DbaDbFile -SqlInstance $psitem.Parent.Name -Database $psitem.Name $DatabaseName = $psitem.Name $LogFiles = $Files | Where-Object { $_.TypeDescription -eq "LOG" } $Splat = @{$LogFileSizeComparison = $true; property = "size" } $LogFileSize = ($LogFiles | Measure-Object -Property Size -Maximum).Maximum $DataFileSize = ($Files | Where-Object { $_.TypeDescription -eq "ROWS" } | Measure-Object @Splat).$LogFileSizeComparison It "Database $DatabaseName Should have no log files larger than $LogFileSizePercentage% of the $LogFileSizeComparison of DataFiles on $($psitem.Parent.Name)" { $LogFileSize | Should -BeLessThan ($DataFileSize * $LogFileSizePercentage) -Because "If your log file is this large you are not maintaining it well enough" } } } } } Describe "Future File Growth" -Tags FutureFileGrowth, Low, $filename { $threshold = Get-DbcConfigValue policy.database.filegrowthfreespacethreshold [string[]]$exclude = Get-DbcConfigValue policy.database.filegrowthexcludedb $exclude += $ExcludedDatabases if ($NotContactable -contains $psitem) { Context "Testing for files likely to grow soon on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing for files likely to grow soon on $psitem" { $InstanceSMO.Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $PsItem.Name -notin $exclude }) -and ($psitem.IsAccessible) }.ForEach{ $Files = Get-DbaDbFile -SqlInstance $psitem.Parent.Name -Database $psitem.Name $Files | Add-Member ScriptProperty -Name PercentFree -Value { 100 - [Math]::Round(([int64]$PSItem.UsedSpace.Byte / [int64]$PSItem.Size.Byte) * 100, 3) } $Files | ForEach-Object { if (-Not (($PSItem.Growth -eq 0) -and (Get-DbcConfigValue skip.database.filegrowthdisabled))) { It "Database $($PSItem.Database) file $($PSItem.LogicalName) has free space under threshold on $($PSItem.SqlInstance)" { $PSItem.PercentFree | Should -BeGreaterOrEqual $threshold -Because "free space within the file should be lower than threshold of $threshold %" } } } } } } } Describe "Correctly sized Filegroup members" -Tags FileGroupBalanced, Medium, $filename { $Tolerance = Get-DbcConfigValue policy.database.filebalancetolerance if ($NotContactable -contains $psitem) { Context "Testing for balanced FileGroups on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing for balanced FileGroups on $psitem" { @(Connect-DbaInstance -SqlInstance $_).Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name -and ($Psitem.IsAccessible -eq $true) }) }.ForEach{ $Files = Get-DbaDbFile -SqlInstance $psitem.Parent.Name -Database $psitem.Name $FileGroups = $Files | Where-Object { $_.TypeDescription -eq "ROWS" } | Group-Object -Property FileGroupName @($FileGroups).ForEach{ $Unbalanced = 0 $Average = ($psitem.Group.Size | Measure-Object -Average).Average ## files where average size is less than 95% of the average or more than 105% of the average filegroup size (using default 5% config value) $Unbalanced = $psitem | Where-Object { $psitem.group.Size -lt ((1 - ($Tolerance / 100)) * $Average) -or $psitem.group.Size -gt ((1 + ($Tolerance / 100)) * $Average) } It "Database $($psitem.Group[0].Database) File Group $($psitem.Name) should have FileGroup members with sizes within $tolerance % of the average on $($psitem.Group[0].SqlInstance)" { $Unbalanced.count | Should -Be 0 -Because "If your file groups are not balanced the files with the most free space will become allocation hotspots" } } } } } } Describe "Certificate Expiration" -Tags CertificateExpiration, High, $filename { $CertificateWarning = Get-DbcConfigValue policy.certificateexpiration.warningwindow [string[]]$exclude = Get-DbcConfigValue policy.certificateexpiration.excludedb $exclude += $ExcludedDatabases if ($NotContactable -contains $psitem) { Context "Checking that encryption certificates have not expired on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Checking that encryption certificates have not expired on $psitem" { @(Get-DbaDbEncryption -SqlInstance $psitem -IncludeSystemDBs -Database $Database -ExcludeDatabase $exclude | Where-Object { $_.Encryption -eq "Certificate" -and ($_.Database -notin $exclude) }).ForEach{ It "Database $($psitem.Database) certificate $($psitem.Name) has not expired on $($psitem.SqlInstance)" { $psitem.ExpirationDate.ToUniversalTime() | Should -BeGreaterThan (Get-Date).ToUniversalTime() -Because "this certificate should not be expired" } if ($psitem.ExpirationDate.ToUniversalTime() -lt (Get-Date).ToUniversalTime()) { $skip = $true } else { $skip = $false } It "Database $($psitem.Database) certificate $($psitem.Name) does not expire for more than $CertificateWarning months on $($psitem.SqlInstance)" -Skip:$skip { $psitem.ExpirationDate.ToUniversalTime() | Should -BeGreaterThan (Get-Date).ToUniversalTime().AddMonths($CertificateWarning) -Because "expires inside the warning window of $CertificateWarning months" } } } } } Describe "Auto Create Statistics" -Tags AutoCreateStatistics, Low, $filename { $autocreatestatistics = Get-DbcConfigValue policy.database.autocreatestatistics if ($NotContactable -contains $psitem) { Context "Testing Auto Create Statistics on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Auto Create Statistics on $psitem" { $InstanceSMO.Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name }) }.ForEach{ It "Database $($psitem.Name) should have Auto Create Statistics set to $autocreatestatistics on $($psitem.Parent.Name)" { $psitem.AutoCreateStatisticsEnabled | Should -Be $autocreatestatistics -Because "This value is expected for autocreate statistics" } } } } } Describe "Auto Update Statistics" -Tags AutoUpdateStatistics, Low, $filename { $autoupdatestatistics = Get-DbcConfigValue policy.database.autoupdatestatistics if ($NotContactable -contains $psitem) { Context "Testing Auto Update Statistics on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Auto Update Statistics on $psitem" { $InstanceSMO.Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name }) }.ForEach{ It "Database $($psitem.Name) should have Auto Update Statistics set to $autoupdatestatistics on $($psitem.Parent.Name)" { $psitem.AutoUpdateStatisticsEnabled | Should -Be $autoupdatestatistics -Because "This value is expected for autoupdate statistics" } } } } } Describe "Auto Update Statistics Asynchronously" -Tags AutoUpdateStatisticsAsynchronously, Low, $filename { $autoupdatestatisticsasynchronously = Get-DbcConfigValue policy.database.autoupdatestatisticsasynchronously if ($NotContactable -contains $psitem) { Context "Testing Auto Update Statistics Asynchronously on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Auto Update Statistics Asynchronously on $psitem" { $InstanceSMO.Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name }) }.ForEach{ It "Database $($psitem.Name) should have Auto Update Statistics Asynchronously set to $autoupdatestatisticsasynchronously on $($psitem.Parent.Name)" { $psitem.AutoUpdateStatisticsAsync | Should -Be $autoupdatestatisticsasynchronously -Because "This value is expected for autoupdate statistics asynchronously" } } } } } Describe "Datafile Auto Growth Configuration" -Tags DatafileAutoGrowthType, Low, $filename { $datafilegrowthtype = Get-DbcConfigValue policy.database.filegrowthtype $datafilegrowthvalue = Get-DbcConfigValue policy.database.filegrowthvalue $exclude = Get-DbcConfigValue policy.database.filegrowthexcludedb $exclude += $ExcludedDatabases if ($NotContactable -contains $psitem) { Context "Testing datafile growth type on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing datafile growth type on $psitem" { $InstanceSMO.Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $exclude -notcontains $PsItem.Name }) -and ($Psitem.IsAccessible -eq $true) }.ForEach{ $Files = Get-DbaDbFile -SqlInstance $InstanceSMO -Database $psitem.Name @($Files).ForEach{ if (-Not (($psitem.Growth -eq 0) -and (Get-DbcConfigValue skip.database.filegrowthdisabled))) { It "Database $($psitem.Database) datafile $($psitem.LogicalName) on filegroup $($psitem.FileGroupName) should have GrowthType set to $datafilegrowthtype on $($psitem.SqlInstance)" { $psitem.GrowthType | Should -Be $datafilegrowthtype -Because "We expect a certain file growth type" } if ($datafilegrowthtype -eq "kb") { It "Database $($psitem.Database) datafile $($psitem.LogicalName) on filegroup $($psitem.FileGroupName) should have Growth set equal or higher than $datafilegrowthvalue on $($psitem.SqlInstance)" { $psitem.Growth * 8 | Should -BeGreaterOrEqual $datafilegrowthvalue -because "We expect a certain file growth value" } } else { It "Database $($psitem.Database) datafile $($psitem.LogicalName) on filegroup $($psitem.FileGroupName) should have Growth set equal or higher than $datafilegrowthvalue on $($psitem.SqlInstance)" { $psitem.Growth | Should -BeGreaterOrEqual $datafilegrowthvalue -because "We expect a certain fFile growth value" } } } } } } } } Describe "Trustworthy Option" -Tags Trustworthy, DISA, Varied, CIS, $filename { $exclude = Get-DbcConfigValue policy.database.trustworthyexcludedb $exclude += $ExcludedDatabases if ($NotContactable -contains $psitem) { Context "Testing database trustworthy option on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing database trustworthy option on $psitem" { @($InstanceSMO.Databases.Where{ $psitem.Name -ne 'msdb' -and ($(if ($Database) { $PsItem.Name -in $Database }else { $exclude -notcontains $PsItem.Name })) }).ForEach{ It "Database $($psitem.Name) should have Trustworthy set to false on $($psitem.Parent.Name)" { $psitem.Trustworthy | Should -BeFalse -Because "Trustworthy has security implications and may expose your SQL Server to additional risk" } } } } } Describe "Database Orphaned User" -Tags OrphanedUser, CIS, Medium, $filename { if ($NotContactable -contains $psitem) { Context "Testing database orphaned user event on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing database orphaned user event on $psitem" { $instance = $psitem @($InstanceSMO.Databases.Where{ ($(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name })) }).ForEach{ It "Database $($psitem.Name) should return 0 orphaned user on $($psitem.Parent.Name)" { @(Get-DbaDbOrphanUser -SqlInstance $instance -ExcludeDatabase $ExcludedDatabases -Database $psitem.Name).Count | Should -Be 0 -Because "We dont want orphaned users" } } } } } Describe "PseudoSimple Recovery Model" -Tags PseudoSimple, Medium, $filename { if ($NotContactable -contains $psitem) { Context "Testing database is not in PseudoSimple recovery model on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing database is not in PseudoSimple recovery model on $psitem" { @($InstanceSMO.Databases.Where{ $psitem.Name -ne 'tempdb' -and $psitem.Name -ne 'model' -and $psitem.Status -ne 'Offline' -and ($(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name })) }).ForEach{ if (-not($psitem.RecoveryModel -eq "Simple")) { It "Database $($psitem.Name) has PseudoSimple recovery model equal false on $($psitem.Parent.Name)" { (Test-DbaDbRecoveryModel -SqlInstance $psitem.Parent -Database $psitem.Name).ActualRecoveryModel -eq "SIMPLE" | Should -BeFalse -Because "PseudoSimple means that a FULL backup has not been taken and the database is still effectively in SIMPLE mode" } } } } } } Describe "Compatibility Level" -Tags CompatibilityLevel, High, $filename { if ($NotContactable -contains $psitem) { Context "Testing database compatibility level matches server compatibility level on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing database compatibility level matches server compatibility level on $psitem" { if ($version -lt 10) { It "Database dbachecksskipped Testing database compatibility level matches server compatibility level on $psitem" -Skip { Assert-DatabaseDuplicateIndex -Instance $instance -Database $psitem } } else { @(Test-DbaDbCompatibility -SqlInstance $psitem -ExcludeDatabase $ExcludedDatabases -Database $Database).ForEach{ It "Database $($psitem.Database) has a database compatibility level equal to the level of $($psitem.SqlInstance)" { $psItem.DatabaseCompatibility | Should -Be $psItem.ServerLevel -Because "it means you are on the appropriate compatibility level for your SQL Server version to use all available features" } } } } } } Describe "Foreign keys and check constraints not trusted" -Tags FKCKTrusted, Low, $filename { if ($NotContactable -contains $psitem) { Context "Testing Foreign Keys and Check Constraints are not trusted $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Foreign Keys and Check Constraints are not trusted $psitem" { @(Get-DbaDbForeignKey -SqlInstance $psitem -ExcludeDatabase $ExcludedDatabases -Database $Database).Where{ $_.NotForReplication -eq $false }.ForEach{ It "Database $($psitem.Database) Foreign Key $($psitem.Name) on table $($psitem.Parent) should be trusted on $($psitem.SqlInstance)" { $psitem.IsChecked | Should -Be $true -Because "This can have a huge performance impact on queries. SQL Server won't use untrusted constraints to build better execution plans. It will also avoid data violation" } } @(Get-DbaDbCheckConstraint -SqlInstance $psitem -ExcludeDatabase $ExcludedDatabases -Database $Database).Where{ $_.NotForReplication -eq $false -and $_.IsEnabled -eq $true }.ForEach{ It "Database $($psitem.Database) Check Constraint $($psitem.Name) on table $($psitem.Parent) should be trusted on $($psitem.SqlInstance)" { $psitem.IsChecked | Should -Be $true -Because "This can have a huge performance impact on queries. SQL Server won't use untrusted constraints to build better execution plans. It will also avoid data violation" } } } } } Describe "Database MaxDop" -Tags MaxDopDatabase, MaxDop, Low, $filename { $MaxDopValue = Get-DbcConfigValue policy.database.maxdop [string[]]$exclude = Get-DbcConfigValue policy.database.maxdopexcludedb $exclude += $ExcludedDatabases if ($exclude) { Write-Warning "Excluded $exclude from testing" } if ($NotContactable -contains $psitem) { Context "Database MaxDop setting is correct on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Database MaxDop setting is correct on $psitem" { @(Test-DbaMaxDop -SqlInstance $psitem).Where{ $_.Database -ne 'N/A' -and $(if ($database) { $PsItem.Database -in $Database } else { $_.Database -notin $exclude }) }.ForEach{ It "Database $($psitem.Database) should have the correct MaxDop setting on $($psitem.SqlInstance)" { Assert-DatabaseMaxDop -MaxDop $PsItem -MaxDopValue $MaxDopValue } } } } } Describe "Database Status" -Tags DatabaseStatus, High, $filename { $ExcludeReadOnly = Get-DbcConfigValue policy.database.status.excludereadonly $ExcludeOffline = Get-DbcConfigValue policy.database.status.excludeoffline $ExcludeRestoring = Get-DbcConfigValue policy.database.status.excluderestoring if ($NotContactable -contains $psitem) { Context "Database status is correct on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Database status is correct on $psitem" { $instance = $psitem @($InstanceSMO.Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name }) }).Foreach{ It "Database $($psitem.Name) has the expected status on $instance" { Assert-DatabaseStatus -Instance $instance -Database $($psitem.Name) -ExcludeReadOnly $ExcludeReadOnly -ExcludeOffline $ExcludeOffline -ExcludeRestoring $ExcludeRestoring } } } } } Describe "Database Exists" -Tags DatabaseExists, $filename { $expected = Get-DbcConfigValue database.exists if ($Database) { $expected += $Database } $expected = $expected.where{ $psitem -notin $ExcludedDatabases } if ($NotContactable -contains $psitem) { Context "Database exists on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { $instance = $psitem Context "Database exists on $psitem" { $expected.ForEach{ It "Database $psitem should exist on $($psitem.Parent.Name)" { Assert-DatabaseExists -Instance $instance -Expecteddb $psitem } } } } } Describe "Contained Database Auto Close" -Tags ContainedDBAutoClose, CIS, $filename { $skip = Get-DbcConfigValue skip.security.containedbautoclose if ($NotContactable -contains $psitem) { Context "Testing contained database auto close option on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip{ $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing contained database auto close option on $psitem" { @($InstanceSMO.Databases.Where{ $psitem.Name -ne 'msdb' -and $psItem.ContainmentType -ne "NONE" -and $psItem.ContainmentType -ne $null -and ($(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name })) }).ForEach{ It "Database $($psitem.Name) should have auto close set to false on $($psitem.Parent.Name)" -Skip:$skip { $psitem.AutoClose | Should -BeFalse -Because "Contained Databases should have auto close set to false for CIS compliance" } } } } } Describe "CLR Assemblies SAFE_ACCESS" -Tags CLRAssembliesSafe, CIS, $filename { $skip = Get-DbcConfigValue skip.security.clrassembliessafe [string[]]$exclude = Get-DbcConfigValue policy.database.clrassembliessafeexcludedb $ExcludedDatabases += $exclude if ($NotContactable -contains $psitem) { Context "Testing that all user-defined CLR assemblies are set to SAFE_ACCESS on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing that all user-defined CLR assemblies are set to SAFE_ACCESS on $psitem" { $instance = $psitem @($InstanceSMO.Databases.Where{ ($(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name })) }).ForEach{ It "Database $($psitem.Name) user-defined CLR assemblies are set to SAFE_ACCESS on $($psitem.Parent.Name)" { Assert-CLRAssembliesSafe -Instance $instance -Database $psitem.Name } } } } } Describe "Guest User" -Tags GuestUserConnect, Security, CIS, Medium, $filename { $exclude = "master", "tempdb", "msdb" $ExcludedDatabases = $ExcludedDatabases + $exclude $skip = Get-DbcConfigValue skip.security.guestuserconnect if ($NotContactable -contains $psitem) { Context "Testing Guest user has CONNECT permission on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { $instance = $Psitem Context "Testing Guest user has CONNECT permission on $psitem" { @(Get-Database -Instance $Instance -Requiredinfo Name -Exclusions NotAccessible -Database $Database -ExcludedDbs $ExcludedDatabases).ForEach{ It "Database Guest user should return no CONNECT permissions in $psitem on $Instance" -Skip:$skip { Assert-GuestUserConnect -Instance $instance -Database $psitem } } } } } Describe "AsymmetricKeySize" -Tags AsymmetricKeySize, CIS, $filename { $skip = Get-DbcConfigValue skip.security.asymmetrickeysize $ExcludedDatabases = $ExcludedDatabases + "master", "tempdb", "msdb" if ($NotContactable -contains $psitem) { Context "Testing Asymmetric Key Size is 2048 or higher on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Asymmetric Key Size is 2048 or higher on $psitem" { @($InstanceSMO.Databases.Where{ ($(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name })) }).ForEach{ It "Database $($psitem.Name) Asymmetric Key Size should be at least 2048 on $($psitem.Parent.Name)" -Skip:$skip { Assert-AsymmetricKeySize -Instance $instance -Database $psitem } } } } } Describe "SymmetricKeyEncryptionLevel" -Tags SymmetricKeyEncryptionLevel, CIS, $filename { $skip = Get-DbcConfigValue skip.security.symmetrickeyencryptionlevel $ExcludedDatabases = $ExcludedDatabases + "master", "tempdb", "msdb" if ($NotContactable -contains $psitem) { Context "Testing Symmetric Key Encryption Level at least AES_128 or higher on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Symmetric Key Encryption Level at least AES_128 or higher on $psitem" { @($InstanceSMO.Databases.Where{ ($(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name })) }).ForEach{ It "Database $($psitem.Name) Symmetric Key Encryption Level should have AES_128 or higher on $($psitem.Parent.Name)" -Skip:$skip { Assert-SymmetricKeyEncryptionLevel -Instance $instance -Database $psitem } } } } } Describe "Contained Database SQL Authenticated Users" -Tags ContainedDBSQLAuth, CIS, $filename { $skip = Get-DbcConfigValue skip.security.ContainedDBSQLAuth if ($NotContactable -contains $psitem) { Context "Testing contained database to see if sql authenticated users exist on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing contained database to see if sql authenticated users exist on $psitem" { @($InstanceSMO.Databases.Where{ $psitem.Name -ne 'msdb' -and $psItem.ContainmentType -ne "NONE" -and ($(if ($Database) { $PsItem.Name -in $Database }else { $ExcludedDatabases -notcontains $PsItem.Name })) }).ForEach{ if ($version -lt 13 ) { $skip = $true } It "Database $($psitem.Name) should have no sql authenticated users on $($psitem.Parent.Name)" -Skip:$skip { Assert-ContainedDBSQLAuth -Instance $InstanceSMO -Database $($psitem.Name) } } } } } Describe "Query Store Enabled" -Tags QueryStoreEnabled, Medium, $filename { $QSExcludedDatabases = Get-DbcConfigValue database.querystoreenabled.excludedb $exclude = "master", "tempdb" , "model" $ExcludedDatabases += $exclude $QSExcludedDatabases += $ExcludedDatabases $Skip = Get-DbcConfigValue skip.security.querystoreenabled if (!$skip -and $InstanceSMO.Version.Major -lt 13) { $Skip = $true } if ($NotContactable -contains $psitem) { Context "Testing to see if Query Store is enabled on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { $instance = $Psitem Context "Testing to see if Query Store is enabled on $psitem" { @($InstanceSMO.Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $QSExcludedDatabases -notcontains $PsItem.Name }) }).Foreach{ It "Database $($psitem.Name) should have Query Store enabled on $Instance" -Skip:$skip { Assert-QueryStoreEnabled -Instance $InstanceSMO -Database $($psitem.Name) } } } } } Describe "Query Store Disabled" -Tags QueryStoreDisabled, Medium, $filename { $QSExcludedDatabases = Get-DbcConfigValue database.querystoredisabled.excludedb $exclude = "master", "tempdb" , "model" $ExcludedDatabases += $exclude $QSExcludedDatabases += $ExcludedDatabases $Skip = Get-DbcConfigValue skip.security.querystoredisabled if (!$skip -and $InstanceSMO.Version.Major -lt 13) { $Skip = $true } if ($NotContactable -contains $psitem) { Context "Testing to see if Query Store is disabled on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { $instance = $Psitem Context "Testing to see if Query Store is disabled on $psitem" { @($InstanceSMO.Databases.Where{ $(if ($Database) { $PsItem.Name -in $Database }else { $QSExcludedDatabases -notcontains $PsItem.Name }) }).Foreach{ It "Database $($psitem.Name) should have Query Store disabled on $Instance" -Skip:$skip { Assert-QueryStoreDisabled -Instance $InstanceSMO -Database $($psitem.Name) } } } } } } Set-PSFConfig -Module dbachecks -Name global.notcontactable -Value $NotContactable # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUtcxr55FjceUEjdUkewbSpjmy # jvGgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQnK7qKjRxJU+HyxAj3yGDpDNaE # nDANBgkqhkiG9w0BAQEFAASCAQB/bH2PVbDMyrw6q29akwgV4y2inQ3H5aEv+rbW # QNqXAAM6YQdao2jNULDso8l8SFAda7/rGwKPysHSW9T5ItOwAt3k421oegIW14lc # 1X1u2TVEm/iZ7hDxdVpwasIg4E3Dsk2GDBnBex3Kvtqa5KI6SHrkf+0hmPh6h/We # HcYi+7U3OJifW6LE6PNm2OlqV/+lf91JVMWUnnV7Lj5l3+TL4RCHLhiQeQcdYyND # Jzz3o3efcO44AHdgYr2/NUBMqKG7cNvg0kfcVEJu0P/bJXXlOFZAPjJS29QY+LjH # reo+UTxlzVPFc1/7eYaPj05afNA80nAKJ+I0fg2DXoQxj8gM # SIG # End signature block ================================================ FILE: source/checks/Databasev5.Tests.ps1 ================================================ # So the v5 files need to be handled differently. # Ww will start with a BeforeDiscovery , $Filename which for the Database Checks will need to gather the Instances up front BeforeDiscovery { # Gather the instances we know are not contactable [string[]]$NotContactable = (Get-PSFConfig -Module dbachecks -Name global.notcontactable).Value # Get all the tags in use in this run $Tags = Get-CheckInformation -Check $Check -Group Database -AllChecks $AllChecks -ExcludeCheck $ChecksToExclude $InstancesToTest = @(Get-Instance).ForEach{ # just add it to the Not Contactable list if ($NotContactable -notcontains $psitem) { $Instance = $psitem try { $InstanceSMO = Connect-DbaInstance -SqlInstance $Instance -ErrorAction SilentlyContinue -ErrorVariable errorvar } catch { $NotContactable += $Instance } if ($NotContactable -notcontains $psitem) { if ($null -eq $InstanceSMO.version) { $NotContactable += $Instance } else { # Get the relevant information for the checks in one go to save repeated trips to the instance and set values for Not Contactable tests if required Get-AllDatabaseInfo -Instance $InstanceSMO -Tags $Tags } } } } Write-PSFMessage -Message "Instances = $($InstancesToTest.Name)" -Level Verbose Set-PSFConfig -Module dbachecks -Name global.notcontactable -Value $NotContactable # Get-DbcConfig is expensive so we call it once $__dbcconfig = Get-DbcConfig } # Each Test will have a -ForEach for the Instances and the InstancesToTest object will have a # lot of information gathered up front to reduce trips and connections to the database <# - copy in test - add skip after describe $skip = Get-DbcConfigValue skip.database.databasecollation add to IT -Skip:$skip #> Describe "Suspect Page" -Tag SuspectPage, High , Database -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.database.suspectpage' }).Value Context "Testing suspect pages on <_.Name>" { It "Database <_.Name> should return 0 suspect pages on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.suspectpageexclude -notcontains $PsItem.Name } } { $psitem.SuspectPage | Should -Be 0 -Because "You do not want any suspect pages" } } } Describe "Database Collation" -Tag DatabaseCollation, High, Database -ForEach $InstancesToTest { #TODO: Should we have a skip option for each IT block? $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.database.databasecollation' }).Value Context "Testing database collation on <_.Name>" { It "Database <_.Name> collation <_.Collation> should match server collation <_.ServerCollation> on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.wrongcollation -notcontains $PsItem.Name } } { $psitem.ServerCollation | Should -Be $psitem.Collation -Because "You will get collation conflict errors in tempdb" } # wrong collation set It "Database <_.Name> collation <_.Collation> should not match server collation <_.ServerCollation> on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ $_.Name -in $psitem.ConfigValues.wrongcollation } { $psitem.ServerCollation | Should -Not -Be $psitem.Collation -Because "You have defined the database to have another collation then the server. You will get collation conflict errors in tempdb" } } } Describe "Valid Database Owner" -Tag ValidDatabaseOwner, Medium, Database -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.database.validdatabaseowner' }).Value Context "Testing Database Owners on <_.Name>" { #TODO fix the it text - needs commas --> should be in this list ( sqladmin sa ) ) It "Database <_.Name> - owner '<_.Owner>' should be in this list ( <_.ConfigValues.validdbownername> ) ) on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.validdbownerexclude -notcontains $PsItem.Name } } { $psitem.Owner | Should -BeIn $psitem.ConfigValues.validdbownername -Because "The account that is the database owner is not what was expected" } } } Describe "Invalid Database Owner" -Tag InvalidDatabaseOwner, Medium, Database -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.database.invaliddatabaseowner' }).Value Context "Testing Database Owners on <_.Name>" { It "Database <_.Name> - owner '<_.Owner>' should not be in this list ( <_.ConfigValues.invaliddbownername> ) ) on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.invaliddbownerexclude -notcontains $PsItem.Name } } { $psitem.Owner | Should -Not -BeIn $psitem.ConfigValues.invaliddbownername -Because "The database owner was one specified as incorrect" } } } Describe "AsymmetricKeySize" -Tag AsymmetricKeySize, CIS, Database -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.security.asymmetrickeysize' }).Value Context "Testing Asymmetric Key Size is 2048 or higher on <_.Name>" { It "Database <_.Name> asymmetric key size should be at least 2048 on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.asymmetrickeysizeexclude -notcontains $PsItem.Name } } { $psitem.AsymmetricKeySize | Should -Be 0 -Because "Asymmetric keys should have a key length greater than or equal to 2048" #$psitem.AsymmetricKeySize | Should -BeGreaterOrEqual 2048 -Because "Asymmetric keys should have a key length greater than or equal to 2048" } } } Describe "Auto Close" -Tag AutoClose, High, Database -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.database.autoclose' }).Value Context "Testing Auto Close on <_.Name>" { It "Database <_.Name> should have Auto Close set to <_.ConfigValues.autoclose> on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.autocloseexclude -notcontains $PsItem.Name } } { $psitem.AutoClose | Should -Be $psitem.ConfigValues.autoclose -Because "Because!" } } } Describe "Auto Shrink" -Tag AutoShrink, High, Database -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.database.autoshrink' }).Value Context "Testing Auto Shrink on <_.Name>" { It "Database <_.Name> should have Auto Shrink set to <_.ConfigValues.autoshrink> on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.autoshrinkexclude -notcontains $PsItem.Name } } { $psitem.AutoShrink | Should -Be $psitem.ConfigValues.autoshrink -Because "Shrinking databases causes fragmentation and performance issues" } } } Describe "Virtual Log Files" -Tag VirtualLogFile, Medium, Database -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.database.vlf' }).Value Context "Testing Database VLFs on <_.Name>" { It "Database <_.Name> VLF count should be less than <_.ConfigValues.maxvlf> on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.vlfexclude -notcontains $PsItem.Name } } { $psitem.VLF | Should -BeLessThan $psitem.ConfigValues.maxvlf -Because "Too many VLFs can impact performance and slow down backup/restore" } } } Describe "Log File Count Checks" -Tag LogfileCount, Medium, Database -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.database.logfilecounttest' }).Value Context "Testing Log File count for <_.Name>" { It "Database <_.Name> should have <_.ConfigValues.logfilecount> or less log files on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.logfilecountexclude -notcontains $PsItem.Name } } { $psitem.LogFileCount | Should -BeLessOrEqual $psitem.ConfigValues.logfilecount -Because "You want the correct number of log files" } } } Describe "Auto Create Statistics" -Tag AutoCreateStatistics, Low, Database -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.database.autocreatestatistics' }).Value Context "Testing Auto Create Statistics for <_.Name>" { It "Database <_.Name> should have Auto Create Statistics set to <_.ConfigValues.autocreatestats> on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.autocreatestatsexclude -notcontains $PsItem.Name } } { $psitem.AutoCreateStatistics | Should -Be $psitem.ConfigValues.autocreatestats -Because "This value is expected for autocreate statistics" } } } Describe "Auto Update Statistics" -Tag AutoUpdateStatistics, Low, Database -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.database.autoupdatestatistics' }).Value Context "Testing Auto Update Statistics on <_.Name>" { It "Database <_.Name> should have Auto Update Statistics set to <_.ConfigValues.autoupdatestats> on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.autoupdatestatsexclude -notcontains $PsItem.Name } } { $psitem.AutoUpdateStatistics | Should -Be $psitem.ConfigValues.autoupdatestats -Because "This value is expected for autoupdate statistics" } } } Describe "Auto Update Statistics Asynchronously" -Tag AutoUpdateStatisticsAsynchronously, Low, Database -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.database.autoupdatestatisticsasynchronously' }).Value Context "Testing Auto Update Statistics Asynchronously on <_.Name>" { It "Database <_.Name> should have Auto Update Statistics Asynchronously set to <_.ConfigValues.autoupdatestatsasync> on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.autoupdatestatsasyncexclude -notcontains $PsItem.Name } } { $psitem.AutoUpdateStatisticsAsync | Should -Be $psitem.ConfigValues.autoupdatestatsasync -Because "This value is expected for autoupdate statistics asynchronously" } } } Describe "Trustworthy Option" -Tag Trustworthy, DISA, Varied, CIS, Database -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.database.trustworthy' }).Value Context "Testing database trustworthy option on <_.Name>" { It "Database <_.Name> should have Trustworthy set to false on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.trustworthyexclude -notcontains $PsItem.Name } } { $psitem.Trustworthy | Should -BeFalse -Because "Trustworthy has security implications and may expose your SQL Server to additional risk" } } } Describe "Database Status" -Tag DatabaseStatus, High, Database -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.database.status' }).Value Context "Database status is correct on <_.Name>" { It "Database <_.Name> has the expected status on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.statusexclude -notcontains $PsItem.Name } } { $psitem.Where{ $_.Name -notin $psitem.ConfigValues.excludereadonly -and $psitem.IsDatabaseSnapshot -eq $false }.Readonly | Should -Not -Contain True -Because "We expect that there will be no Read-Only databases except for those specified" $psitem.Where{ $_.Name -notin $psitem.ConfigValues.excludeoffline }.Status | Should -Not -Match 'Offline' -Because "We expect that there will be no offline databases except for those specified" $psitem.Where{ $_.Name -notin $psitem.ConfigValues.excluderestoring }.Status | Should -Not -Match 'Restoring' -Because "We expect that there will be no databases in a restoring state except for those specified" $psitem.Where{ $_.Name -notin $psitem.ConfigValues.excludeoffline }.Status | Should -Not -Match 'AutoClosed' -Because "We expect that there will be no databases that have been auto closed" $psitem.Status | Should -Not -Match 'Recover' -Because "We expect that there will be no databases going through the recovery process or in a recovery pending state" $psitem.Status | Should -Not -Match 'Emergency' -Because "We expect that there will be no databases in EmergencyMode" $psitem.Status | Should -Not -Match 'Standby' -Because "We expect that there will be no databases in Standby" $psitem.Status | Should -Not -Match 'Suspect' -Because "We expect that there will be no databases in a Suspect state" } } } Describe "Query Store Enabled" -Tag QueryStoreEnabled, Medium, Database -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.security.querystoreenabled' }).Value Context "Testing to see if Query Store is enabled on <_.Name>" { It "Database <_.Name> should have Query Store enabled on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.qsenabledexclude -notcontains $PsItem.Name } } { $psitem.QueryStore | Should -Not -BeIn ('OFF', 'ERROR') -Because "We expect the Query Store to be enabled" } } } Describe "Query Store Disabled" -Tag QueryStoreDisabled, Medium, Database -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.security.querystoredisabled' }).Value Context "Testing to see if Query Store is disabled on <_.Name>" { It "Database <_.Name> should have Query Store disabled on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.qsdisabledexclude -notcontains $PsItem.Name } } { $psitem.QueryStore | Should -Not -Be 'OFF' -Because "We expect the Query Store to be disabled" } } } Describe "Compatibility Level" -Tag CompatibilityLevel, High, Database -ForEach $InstancesToTest { $Skip = ($__dbcconfig | Where-Object Name -EQ 'skip.database.compatibilitylevel').Value Context "Compatibility level matches server compatibility level on <_.Name>" { It "Database <_.Name> has the expected compatibility level on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.compatexclude -notcontains $psitem.Name } } { $psitem.CompatibilityLevel | Should -Be $psitem.ServerLevel -Because "it means you are on the appropriate compatibility level for your SQL Server version to use all available features." } } } Describe "Guest User" -Tag GuestUserConnect, Security, CIS, Medium, Database -ForEach $InstancesToTest { $Skip = ($__dbcconfig | Where-Object Name -EQ 'skip.security.guestuserconnect').Value Context "Testing Guest user has CONNECT permission on <_.Name>" { It "Database Guest user should return no CONNECT permissions in <_.Name> on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.guestuserexclude -notcontains $psitem.Name } } { $psitem.GuestUserConnect | Should -BeFalse -Because "we don't want the guest user to have connect access to our database." } } } Describe "Recovery Model" -Tag RecoveryModel, DISA, Medium, Database -ForEach $InstancesToTest { $Skip = ($__dbcconfig | Where-Object Name -EQ 'skip.database.recoverymodel').Value Context "Testing Recovery Model on <_.Name>" { It "Database <_.Name> should be set to <_.ConfigValues.recoverymodeltype> on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.recoverymodelexclude -notcontains $psitem.Name } } { $psitem.RecoveryModel | Should -Be $psitem.ConfigValues.recoverymodeltype -Because "You expect this recovery model." } } } Describe "PseudoSimple Recovery Model" -Tag PseudoSimple, Medium, Database -ForEach $InstancesToTest { $Skip = ($__dbcconfig | Where-Object Name -EQ 'skip.database.pseudosimple').Value Context "Testing database is not in PseudoSimple recovery model on <_.Name>" { It "Database <_.Name> has PseudoSimple recovery model equal false on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database -and $_.RecoveryModel -eq 'Full' } else { $psitem.ConfigValues.pseudosimpleexclude -notcontains $psitem.Name -and $_.RecoveryModel -eq 'Full' } } { $psitem.PseudoSimple | Should -BeFalse -Because "PseudoSimple means that a FULL backup has not been taken and the database is still effectively in SIMPLE mode" } } } Describe "Contained Database Auto Close" -Tag ContainedDBAutoClose, CIS, Database -ForEach $InstancesToTest { $Skip = ($__dbcconfig | Where-Object Name -EQ 'skip.security.containedbautoclose').Value Context "Testing contained database auto close option on <_.Name>" { It "Database <_.Name> should have auto close set to false on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database -and $_.ContainmentType -ne "NONE" } else { $psitem.ConfigValues.contdbautocloseexclude -notcontains $psitem.Name -and $_.ContainmentType -ne "NONE" } } { $psitem.ContainedDbAutoClose | Should -BeFalse -Because "Contained Databases should have auto close set to false for CIS compliance." } } } Describe "Contained Database SQL Authenticated Users" -Tag ContainedDBSQLAuth, CIS, Database -ForEach $InstancesToTest { $Skip = ($__dbcconfig | Where-Object Name -EQ 'skip.security.ContainedDBSQLAuth').Value #TODO: something with this? #if ($version -lt 13 ) { $skip = $true } Context "Testing contained database to see if sql authenticated users exist on <_.Name>" { It "Database <_.Name> should have no sql authenticated users on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database -and $_.ContainmentType -ne "NONE" } else { $psitem.ConfigValues.contdbsqlauthexclude -notcontains $psitem.Name -and $_.ContainmentType -ne "NONE" } } { $psitem.ContainedDbSqlAuthUsers | Should -Be 0 -Because "We expect there to be no sql authenticated users in contained database." } } } Describe "Page Verify" -Tag PageVerify, Medium, Database -ForEach $InstancesToTest { $Skip = ($__dbcconfig | Where-Object Name -EQ 'skip.database.pageverify').Value Context "Testing page verify on <_.Name>" { # handle differently depending on major version - not available at all in SQL 2000. 2005 not available on tempdb. if($psitem.MajorVersion -eq 8) { It "Database Page verify is not available on SQL 2000 on <_.SqlInstance>" { $true | Should -BeTrue } } elseif ($psitem.MajorVersion -eq 9) { It "Database <_.Name> should have page verify set to <_.ConfigValues.pageverify> on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.pageverifyexclude -notcontains $psitem.Name } } { if($psitem.Name -ne 'tempdb') { $psitem.PageVerify | Should -Be $psitem.ConfigValues.PageVerify -Because "Page verify helps SQL Server to detect corruption" } else { $true | Should -BeTrue } } } else { It "Database <_.Name> should have page verify set to <_.ConfigValues.pageverify> on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.pageverifyexclude -notcontains $psitem.Name -and $_.Name -ne 'tempdb'} } { $psitem.PageVerify | Should -Be $psitem.ConfigValues.PageVerify -Because "Page verify helps SQL Server to detect corruption." } #tempdb handled like v4 It "Database Page verify is not available on tempdb on SQL 2005 on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ $_.Name -eq 'tempdb' } { $psitem.PageVerify | Should -Be $psitem.ConfigValues.PageVerify -Because "Page verify helps SQL Server to detect corruption." } } } } Describe "Foreign keys and check constraints not trusted" -Tag FKCKTrusted, Low, Database -ForEach $InstancesToTest { $Skip = ($__dbcconfig | Where-Object Name -EQ 'skip.database.fkcktrusted').Value Context "Testing Foreign Keys and Check Constraints are not trusted <_.Name>" { It "Database <_.Database> Foreign Key <_.Name> on table <_.Parent> should be trusted on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.fkcktrustedexclude -notcontains $psitem.Name } }.ForeignKeys { $psitem.IsChecked | Should -Be $true -Because "This can have a huge performance impact on queries. SQL Server won't use untrusted constraints to build better execution plans. It will also avoid data violation" } It "Database <_.Database> Foreign Key <_.Name> on table <_.Parent> should be trusted on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.fkcktrustedexclude -notcontains $psitem.Name } }.Constraints { $psitem.IsChecked | Should -Be $true -Because "This can have a huge performance impact on queries. SQL Server won't use untrusted constraints to build better execution plans. It will also avoid data violation" } } } ================================================ FILE: source/checks/Domain.Tests.ps1 ================================================ $filename = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") Describe "Active Directory Domain Name" -Tags DomainName, $filename { $domain = Get-DbcConfigValue domain.name @(Get-ComputerName).ForEach{ Context "Testing Active Directory Domain Name on $psitem" { if ($IsLinux) { It "Running on Linux so cant check AD for now on the Domain $domain" -Skip { (Get-DbaCmObject -Class Win32_ComputerSystem -ComputerName $psitem -Credential $credential).Domain | Should -Be $domain -Because 'The machine needs to be on the domain' } } else { It "$psitem should be on the Domain $domain" { (Get-DbaCmObject -Class Win32_ComputerSystem -ComputerName $psitem -Credential $credential).Domain | Should -Be $domain -Because 'The machine needs to be on the domain' } } } } } # Skipping this for now until we get AdsiPS command equiv Describe "Active Directory OU" -Tags OrganizationalUnit, $filename { $dc = Get-DbcConfigValue domain.domaincontroller @(Get-ComputerName).ForEach{ if ($IsLinux) { Context "Testing Active Directory OU on $psitem" { It "Running on Linux so cant check AD for now on the Domain $domain" -Skip { (Get-DbaCmObject -Class Win32_ComputerSystem -ComputerName $psitem -Credential $credential).Domain | Should -Be $domain -Because 'The machine needs to be on the domain' } } } else { Context "Testing Active Directory OU on $psitem" { if (-not $value) { # Can be passed by Invoke-DbcCheck -Value $value = Get-DbcConfigValue domain.organizationalunit } It -Skip "$psitem should be in the right OU ($value on the Domain $domain" { (Get-ADComputer $psitem -Properties CanonicalName -Server $dc).CanonicalName | Should -Be $value -Because 'The SQL Server should be in the correct OU' } } } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUklzltAHEzTKwTAEUv/9O8d+T # HOOgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRx8dv3PekUmlV8Rz9sY6Ty3Q/s # UTANBgkqhkiG9w0BAQEFAASCAQBhFAAiJgB6pgO+LwQQ3O5BmJhr1n1/YSShreGY # KItAbsLUcO997zp2LFt7/sCRwH0BBv5GQ7D+tmmO/r07cWy9b0TjhXxK+I3/IJ0J # JIYeYw1ABkROGRyus0NKe6oqu25wxSxCS2z0+v2P/tQ609ZzpNsgrQmfSbrVRk0x # uIiDHOGzr4+POPOy1xMBHpX8PKMinkN+bQ3c0Gk78UaLwez8XeTWbnTxX8AYVafY # wQWwO37nKICW+Gs+PuG+MweRZDHcc0Mwc+OHCtllcQtDXtZre1bgk9egCe5WyNW4 # Ym7OEK/rO7dAkrJ4vH4XXuqN5DfMqLcJS1Q47/P8EPPXtNfJ # SIG # End signature block # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUC91oynVUf6FC/nbP2lsYpmtq # zoSgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBT0LyaihpRitMUpdyWpMdCpJPcK # 8zANBgkqhkiG9w0BAQEFAASCAQBSkt/Q2VceY4P4UfP7kx4FvqeMW6u+4oJLgyPZ # K9veRmOHtzIi/yvN/xr2qNIRmx0a5S0wYSCBZslizEt6ba+eq5/a/Cg0IMp1hdrj # rK18kvcjJGnxY1DtAsup+woi7Uw1lhA6UQ7V5T72L1fE2QkBxCgRsSfAdW02Yclf # 6YdqAt2LDuoDFFKloDo5CXZdo8Barlh/LrtklHIJtzemwvVyZi4HDT1dDxXzXHEE # ta3qAYtZy0OwS1PlC8tjvDy5KaVRID/yR1MjjVYo82W8mwn6VX69pCEdPf4o+QhE # lCwQSMdwro8Nfiar4xrhQpHQeEYDOOskVATzAL1UQ4gLuN93 # SIG # End signature block ================================================ FILE: source/checks/HADR.Tests.ps1 ================================================ $filename = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") # Get all the info in the function function Get-ClusterObject { [CmdletBinding()] param ( [string]$ClusterVM ) [PsCustomObject]$return = @{ } # Don't think you can use the cluster name here it won't run remotely try { $ErrorActionPreference = 'Stop' $return.Cluster = (Get-Cluster -Name $ClusterVM) $return.Nodes = (Get-ClusterNode -Cluster $ClusterVM) $return.Resources = (Get-ClusterResource -Cluster $ClusterVM) $return.Network = (Get-ClusterNetwork -Cluster $ClusterVM) $return.Groups = (Get-ClusterGroup -Cluster $ClusterVM) $return.AGs = $return.Resources.Where{ $psitem.ResourceType -eq 'SQL Server Availability Group' } } catch { $return.Cluster = 'FailedToConnect' $return.Nodes = 'FailedToConnect' $return.Resources = 'FailedToConnect' $return.Network = 'FailedToConnect' $return.Groups = 'FailedToConnect' $return.AGs = 'FailedToConnect' } $return.AvailabilityGroups = @{ } #Add all the AGs foreach ($AGResource in $return.AGs) { try { # Because several replicas can be on the same cluster node, # cluster node can appear several times, then we want to # avoid duplicate detection of replicas If ($PreviousClusterNode -ne $AGResource.OwnerNode.Name) { $PreviousClusterNode = $AGResource.OwnerNode.Name # We get cluster node owner first ... # We need then for each owner to find out the corresponding replicas => SQL Instance Name + Port $Replicas = Find-DbaInstance -ComputerName $AGResource.OwnerNode.Name } # Finally for each replica detected (SQL Server + Port) # We try to find the corresponding AG(s) info foreach ($replica in $Replicas){ $AGs = Get-DbaAvailabilityGroup -SqlInstance "$($replica.ComputerName),$($replica.Port)" foreach ($AG in $AGs){ If ($AG.AvailabilityGroup -eq $AGResource.Name) { $return.AvailabilityGroups[$AGResource.Name] = $AG } } } } catch { $return = $null } } Return $return } # Import module or bomb out # needs the failover cluster module if (-not (Get-Module FailoverClusters)) { try { if ($IsCoreCLR) { Stop-PSFFunction -Message "FailoverClusters module cannot be loaded in PowerShell Core unfortunately" -ErrorRecord $psitem return } else { Import-Module FailoverClusters -ErrorAction Stop } } catch { Stop-PSFFunction -Message "FailoverClusters module could not load - Please install the Failover Cluster module using Windows Features " -ErrorRecord $psitem return } } else { if ($IsCoreCLR) { Stop-PSFFunction -Message "FailoverClusters module cannot be loaded in PowerShell Core unfortunately" -ErrorRecord $psitem return } } # Grab some values $clusters = Get-DbcConfigValue app.cluster $skipClusterNetInterface = Get-DbcConfigValue skip.cluster.netclusterinterface $skipAgListenerPing = Get-DbcConfigValue skip.hadr.listener.pingcheck $skipAgListenerTcpPort = Get-DbcConfigValue skip.hadr.listener.tcpport $skipReplicaTcpPort = Get-DbcConfigValue skip.hadr.replica.tcpport $domainName = Get-DbcConfigValue domain.name $agTcpPort = Get-DbcConfigValue policy.hadr.agtcpport $sqlTcpPort = Get-DbcConfigValue policy.hadr.tcpport # hadr endpoint config parameters $hadrEndPointName = Get-DbcConfigValue policy.hadr.endpointname $hadrEndPointPort = Get-DbcConfigValue policy.hadr.endpointport $hadrSessionTimeout = Get-DbcConfigValue policy.hadr.sessiontimeout # cluster config parameters $clustAgResFailureConditionLevel = Get-DbcConfigValue policy.hadr.failureconditionlevel $clustAgResHealthCheckTimeout = Get-DbcConfigValue policy.hadr.healthchecktimeout $clustAgResLeaseTimeout = Get-DbcConfigValue policy.hadr.leasetimeout $clustPrivateNetworkProtocolsIPV4 = Get-DbcConfigValue policy.cluster.NetworkProtocolsIPV4 $clustAgReshostRecordTTL = Get-DbcConfigValue policy.cluster.hostrecordttl $clustAgResRegisterAllProvidersIP = Get-DbcConfigValue policy.cluster.registerallprovidersIP #Check for Cluster config value if ($clusters.Count -eq 0) { Write-Warning "No Clusters to look at. Please use Set-DbcConfig -Name app.cluster to add clusters for checking" break } foreach ($clustervm in $clusters) { try { # pick the name here for the output - we cant use it as we are accessing remotely $clustername = (Get-Cluster -Name $clustervm -ErrorAction Stop).Name } catch { # so that we don't get the error and Get-ClusterObject fills it as FailedtoConnect $clustername = $clustervm } Describe "Cluster $clustername Health using Node $clustervm" -Tags ClusterHealth, $filename { $return = @(Get-ClusterObject -ClusterVM $clustervm) Context "Cluster nodes for $clustername" { @($return.Nodes).ForEach{ It "This node should be available - Node $($psitem.Name)" { $psitem.State | Should -Be 'Up' -Because 'Every node in the cluster should be available' } } } Context "Cluster resources for $clustername" { # Get the resources that are no IP Addresses with an owner of Availability Group $return.Resources.Where{ ( $_.ResourceType -in ($_.ResourceType -ne 'IP Address') ) -and ($_.OwnerGroup -in $Return.Ags) }.ForEach{ It "This resource should be online - Resource $($psitem.Name)" { $psitem.State | Should -Be 'Online' -Because 'All of the cluster resources should be online' } } # Get the resources where IP Address is owned by AG and group by AG @($return.Resources.Where{ $_.ResourceType -eq 'IP Address' -and $_.OwnerGroup -in $return.AGs } | Group-Object -Property OwnerGroup).ForEach{ It "One of the IP Addresses should be online for AvailabilityGroup $($Psitem.Name)" { $psitem.Group.Where{ $_.State -eq 'Online' }.Count | Should -Be 1 -Because "There should be one IP Address online for Availability Group $($PSItem.Name)" } } $return.Resources.Where{ $_.ResourceType -eq 'Network Name' -and $_.OwnerGroup -in $return.AGs }.ForEach{ It "HostRecordTTL should be $clustAgReshostRecordTTL for Resource $($PSItem.Name)" { $hostRecordTTL = ($PSItem | Get-ClusterParameter | Where-Object { $_.Name -eq 'HostRecordTTL' }).Value $hostRecordTTL | Should -be $clustAgReshostRecordTTL -Because "$clustAgReshostRecordTTL is what we expect to be for hostRecordTTL" } It "RegisterAllProvidersIP should be $clustAgResRegisterAllProvidersIP for Resource $($PSItem.Name)" { $RegisterAllProvidersIP = ($PSItem | Get-ClusterParameter | Where-Object { $_.Name -eq 'RegisterAllProvidersIP' }).Value $RegisterAllProvidersIP | Should -be $clustAgResRegisterAllProvidersIP -Because "$clustAgResRegisterAllProvidersIP is what we expect to be for RegisterAllProvidersIP" } It "StatusNetBIOS should be $clustAgResStatusNetBIOS for Resource $($PSItem.Name)" { $StatusNetBIOS = ($PSItem | Get-ClusterParameter | Where-Object { $_.Name -eq 'StatusNetBIOS' }).Value $StatusNetBIOS | Should -be 0 -Because "NetBIOS State should be healthy" } It "StatusDNS should be $clustAgStatusDNS for Resource $($PSItem.Name)" { $StatusDNS = ($PSItem | Get-ClusterParameter | Where-Object { $_.Name -eq 'StatusDNS' }).Value $StatusDNS | Should -be 0 -Because "DNS State should be healthy" } It "StatusKerberos should be $clustAgStatusKerberos for Resource $($PSItem.Name)" { $StatusKerberos = ($PSItem | Get-ClusterParameter | Where-Object { $_.Name -eq 'StatusKerberos' }).Value $StatusKerberos | Should -be 0 -Because "Kerberos State should be healthy" } } } Context "Cluster network for $clustername" { It "At least 2 dedicated networks for the cluster should exist for cluster $clustername" -Skip:$skipClusterNetInterface { $return.Network.count | Should -BeGreaterOrEqual 2 -Because "To prevent heartbeat traffic to be overwhelmed by the public workload" } It "One Cluster Network interface should be dedicated for cluster traffic for cluster $clustername" -Skip:$skipClusterNetInterface { $return.network.Role | Should -Contain 'Cluster' -Because "Heartbeat traffic is sensitive to network latency and network interface should be dedicated for this specific usage" } It "One Cluster Network interface should be dedicated for public traffic for cluster $clustername" { $return.network.Role | Should -Contain 'ClusterAndClient' -Because "Public network is mandatory to handle public workload" } $ClusterNetwork = $return.Network | Where-Object { $_.Role -eq 'Cluster' } Foreach ($node in $return.Nodes){ $ReplicaNetInterfaces = Get-DbaWsfcNetworkInterface -ComputerName $clustervm | ` Where-Object { $_.Network -eq $ClusterNetwork.Name -And $_.Node -eq $node.Name} Foreach ($rni in $ReplicaNetInterfaces | Where-Object { $_.IPv4Addresses -ne $null }){ $netinterface = ($rni.Name.Split('-')[1]).Trim() $netbindings = Get-NetAdapter -Name $netinterface -CimSession $node.Name | ` Get-NetAdapterBinding | ` Where-Object { $_.Enabled -eq $true } It "Only required network protocols should be configured for IPV4 cluster interface on node $($node.Name)" -Skip:$skipClusterNetInterface { $netbindings.Count | Should -Be $clustPrivateNetworkProtocolsIPV4.Count -Because "Heartbeat traffic is sensitive to network latency and network protocols should be configured optimally" } $IpConfig = Get-NetIPConfiguration -CimSession $node.Name -InterfaceAlias $netinterface It "No default gateway should be configured for cluster network interface - Node $($node.Name)" -Skip:$skipClusterNetInterface { $IpConfig.IPv4DefaultGateway | Should -BeNullOrEmpty -Because "Heartbeat traffic should not be routable" } $IpDNS = Get-DnsClientServerAddress -CimSession $node.Name -InterfaceAlias $netinterface It "No DNS entries should be configured for cluster network interface - Node $($node.Name)" -Skip:$skipClusterNetInterface { $IpDNS.ServerAddresses.Count | Should -Be 0 -Because "Heartbeat traffic doesn't use DNS resolution" } $DNSRegistration = Get-NetAdapter ` -Name $netinterface ` -CimSession $node.Name | Get-DNSClient It "DNS Registration should be disabled for cluster network interface - Node $($node.Name)" -Skip:$skipClusterNetInterface { $DNSRegistration.RegisterThisConnectionsAddress | Should -Be $false -Because "Heartbeat traffic doesn't use DNS resolution" } $AdapterNetBios = Get-CimInstance ` -ClassName 'Win32_NetworkAdapterConfiguration' ` -CimSession $node.Name ` -Filter "InterfaceIndex = $((Get-NetAdapter -CimSession $node.Name -Name $netinterface).ifIndex)" It "NetBios Over TCP/IP should be disabled for cluster network interface - Node $($node.Name)" -Skip:$skipClusterNetInterface { $AdapterNetBios.TcpipNetbiosOptions | Should -Be 2 -Because "Heartbeat traffic doesn't use NetBios resolution" } } } @($return.Network).ForEach{ It "The Network should be up - Network $($psitem.Name)" { $psitem.State | Should -Be 'Up' -Because 'All of the Cluster Networks should be up' } } } $AGResources = $return.Resources | Where-Object { $_.ResourceType -eq 'SQL Server Availability Group'} Context "Cluster Availability Group Resources for $clustername" { ForEach($AGRes in $AGResources){ It "Failure Condition Level should be $clustAgResFailureConditionLevel for AG Resource $($AGRes.Name)" { $AGResourceResult = $AGRes | Get-ClusterParameter | Where-Object { $_.Name -eq 'FailureConditionLevel' } $AGResourceResult.Value | Should -Be $clustAgResFailureConditionLevel -Because "$clustAgResFailureConditionLevel is what we expect to be for Flexible automatic failover policy" } It "HealthCheck Timeout should be $clustAgResHealthCheckTimeout for AG Resource $($AGRes.Name)" { $AGResourceResult = $AGRes | Get-ClusterParameter | Where-Object { $_.Name -eq 'HealthCheckTimeout' } $AGResourceResult.Value | Should -Be $clustAgResHealthCheckTimeout -Because "$clustAgResHealthCheckTimeout is what we expect to be for health check timeout" } It "Lease Timeout should be $clustAgResLeaseTimeout for AG Resource $($AGRes.Name)" { $AGResourceResult = $AGRes | Get-ClusterParameter | Where-Object { $_.Name -eq 'LeaseTimeout' } $AGResourceResult.Value | Should -Be $clustAgResLeaseTimeout -Because "$clustAgResLeaseTimeout is what we expect to be for lease timeout" } } } $AGs = $return.AGs.Name foreach ($AGName in $AGs) { $AG = @($return.AvailabilityGroups[$AGName]) Context "HADR status for $($AG.SqlInstance) on $clustername" { It "HADR should be enabled on the replica $($AG.SqlInstance)" { try { $HADREnabled = (Get-DbaAgHadr -SqlInstance $AG.SqlInstance -WarningAction SilentlyContinue).IsHadrEnabled } catch { $HADREnabled = $false } $HADREnabled | Should -BeTrue -Because 'All of the nodes should have HADR enabled' } } Context "Cluster Connectivity for Availability Group $($AG.Name) on $clustername" { @($AG.AvailabilityGroupListeners).ForEach{ try { $results = Test-DbaConnection -SqlInstance $_.Name } Catch { $results = [PSCustomObject]@{ IsPingable = $false ConnectSuccess = $false DomainName = $false TCPPort = $false } } It "Listener should be pingable for $($results.SqlInstance)" -skip:$skipaglistenerping { $results.IsPingable | Should -BeTrue -Because 'The listeners should be pingable' } It "Listener should be connectable on $($results.SqlInstance)" { $results.ConnectSuccess | Should -BeTrue -Because 'The listener should process SQL commands successfully' } It "Listener domain name should be $domainname on $($results.SqlInstance)" { $results.DomainName | Should -Be $domainname -Because "$domainname is what we expect the domain name to be" } } @($AG.AvailabilityReplicas).ForEach{ $results = Test-DbaConnection -SqlInstance $PsItem.Name It "Replica should be Pingable for $($results.SqlInstance)" { $results.IsPingable | Should -BeTrue -Because 'Each replica should be pingable' } It "Should be able to connect with SQL on Replica $($results.SqlInstance)" { $results.ConnectSuccess | Should -BeTrue -Because 'Each replica should be able to process SQL commands' } It "Replica domain name should be $domainname on Replica $($results.SqlInstance)" { $results.DomainName | Should -Be $domainname -Because "$domainname is what we expect the domain name to be" } # Consolidated environments with multi-instances / AG replicas # In this case we cannot configure the same tcpport than those used for AG listeners # TCP port conflict # Adding exclusion for these scenarios It "HADR TCP port should be in $tcpport for replica $($results.SqlInstance)" -Skip:$skipReplicaTcpPort { $results.TCPPort | Should -BeIn $sqlTcpPort -Because "We expect the TCP Port to be in $sqlTcpPort" } $resultshadrendpoint = Get-DbaEndpoint -SqlInstance $results.SqlInstance -Endpoint $hadrEndPointName It "HADR endpoint name should be $hadrEndPointName for replica $($results.SqlInstance)" { $resultshadrendpoint.Name | Should -BeIn $hadrEndPointName -Because "$hadrEndPointName is what we expect the compliant name to be" } It "HADR TCP endpoint state should be Started for replica $($results.SqlInstance)" { $resultshadrendpoint.EndpointState | Should -BeIn "Started" -Because "We expect the HADR Endpoint to get ready for log block replication" } It "Session timeout should be $hadrSessionTimeout for replica $($results.SqlInstance)" { $replica = Get-DbaAgReplica -SqlInstance $PsItem.Name $replica.SessionTimeout | Should -BeIn $hadrSessionTimeout -Because "$hadrSessionTimeout is what we expect the session time value to be" } } } Context "Availability group status for $($AG.Name) on $clustername" { @($AG.AvailabilityReplicas).ForEach{ It "The replica should not be in unknown availability mode for $($psitem.Name)" { $psitem.AvailabilityMode | Should -Not -Be 'Unknown' -Because 'The replica should not be in unknown state' } } @($AG.AvailabilityReplicas).Where{ $psitem.AvailabilityMode -eq 'SynchronousCommit' }.ForEach{ It "The replica should be synchronised $($psitem.Name)" { $psitem.RollupSynchronizationState | Should -Be 'Synchronized' -Because 'The synchronous replica should be synchronised' } } $AG.AvailabilityReplicas.Where{ $psitem.AvailabilityMode -eq 'ASynchronousCommit' }.ForEach{ It "The replica should be synchronising $($psitem.Name)" { $psitem.RollupSynchronizationState | Should -Be 'Synchronizing' -Because 'The asynchronous replica should be synchronizing ' } } @($AG.AvailabilityReplicas).Where.ForEach{ It "The replica should be connected $($psitem.Name)" { $psitem.ConnectionState | Should -Be 'Connected' -Because 'The replica should be connected' } } } Context "Database availability group status for $($AG.Name) on $clustername" { @($ag.AvailabilityReplicas.Where{ $_.AvailabilityMode -eq 'SynchronousCommit' }).ForEach{ @(Get-DbaAgDatabase -SqlInstance $psitem.Name -AvailabilityGroup $Ag.Name).ForEach{ It "Database $($psitem.Name) should be synchronised on the replica $($psitem.sqlInstance)" { $psitem.SynchronizationState | Should -Be 'Synchronized' -Because 'The database on the synchronous replica should be synchronised' } It "Database $($psitem.Name) should be failover ready on the replica $($psitem.sqlInstance)" { $psitem.IsFailoverReady | Should -BeTrue -Because 'The database on the synchronous replica should be ready to failover' } It "Database $($psitem.Name) should be joined on the replica $($psitem.sqlInstance)" { $psitem.IsJoined | Should -BeTrue -Because 'The database on the synchronous replica should be joined to the availability group' } It "Database $($psitem.Name) should not be suspended on the replica $($psitem.sqlInstance)" { $psitem.IsSuspended | Should -Be $False -Because 'The database on the synchronous replica should not be suspended' } } } @($ag.AvailabilityReplicas.Where{ $_.AvailabilityMode -eq 'AsynchronousCommit' }).ForEach{ @(Get-DbaAgDatabase -SqlInstance $PSItem.Name -AvailabilityGroup $Ag.Name).ForEach{ It "Database $($psitem.Name) should be synchronising as it is Async on the secondary replica $($psitem.sqlInstance)" { $psitem.SynchronizationState | Should -Be 'Synchronizing' -Because 'The database on the asynchronous secondary replica should be synchronising' } It "Database $($psitem.Name) should not be failover ready on the secondary replica $($psitem.sqlInstance)" { $psitem.IsFailoverReady | Should -BeFalse -Because 'The database on the asynchronous secondary replica should be ready to failover' } It "Database $($psitem.Name) should be joined on the secondary replica $($psitem.sqlInstance)" { $psitem.IsJoined | Should -BeTrue -Because 'The database on the asynchronous secondary replica should be joined to the availability group' } It "Database $($psitem.Name) should not be suspended on the secondary replica $($psitem.sqlInstance)" { $psitem.IsSuspended | Should -Be $False -Because 'The database on the asynchronous secondary replica should not be suspended' } } } } Context "Always On extended event status for replica $($AG.SqlInstance) on $clustername" { try { $Xevents = Get-DbaXEsession -SqlInstance $AG.SqlInstance -WarningAction SilentlyContinue } catch { $Xevents = 'FailedToConnect' } It "There should be an extended event session called AlwaysOn_health on Replica $($psitem.Name)" { $Xevents.Name | Should -Contain 'AlwaysOn_health' -Because 'The extended events session should exist' } It "The Always On Health extended event session should be running on Replica $($psitem.Name)" { $Xevents.Where{ $_.Name -eq 'AlwaysOn_health' }.Status | Should -Be 'Running' -Because 'The extended event session will enable you to troubleshoot errors' } It "The Always On Health extended event session should be set to auto start on Replica $($psitem.Name)" { $Xevents.Where{ $_.Name -eq 'AlwaysOn_health' }.AutoStart | Should -BeTrue -Because 'The extended event session will enable you to troubleshoot errors' } } } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUW+i9VUpgxvFu0m8CjHR4wio2 # QYygggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBT+I7ZxtqIhmUvNKQFmlW8I9W3y # 5jANBgkqhkiG9w0BAQEFAASCAQBUHmUJqOrFJlthbAiIzL4D6LwH908qv77k84WN # J1/usSBHy1tAUX5jtMo/EJLLoXEzlL7NjhgA6zkcWX0KlSw6QoZ4qG7r61t9nm7E # RaR+kOjIYLFQB0ljSYr08YLiagcOj1NaXkiU6ohKHymcLVKjRwsY6Gwym4M9MmIS # 5Eo7pSBB1junSlXY8FuGw1F0kmZEh9vTkUOeVerFrKdY7gvZP1RiEapB6fINnPk0 # Tc8/0m+DhnjCqROPLmh3pDBZ7md+4x7fFTyU0zb7rRT8NQkgPhoUPag8wBQhba2A # vTp085O7s6kU2mq1nr1St9Od1kd2mFoLBI5Tx5VL7lL9YmrS # SIG # End signature block ================================================ FILE: source/checks/Instance.Tests.ps1 ================================================ $filename = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") . $PSScriptRoot/../internal/assertions/Instance.Assertions.ps1 # Check out the comments at the top of Instance.Assertions for guidance on adding checks # Gather the instances we know are not contactable [string[]]$NotContactable = (Get-PSFConfig -Module dbachecks -Name global.notcontactable).Value # Get all the tags in use in this run $Tags = Get-CheckInformation -Check $Check -Group Instance -AllChecks $AllChecks -ExcludeCheck $ChecksToExclude @(Get-Instance).ForEach{ # Try to make a connection to the instance and add to NotContactable if required if ($NotContactable -notcontains $psitem) { $Instance = $psitem try { $InstanceSMO = Connect-DbaInstance -SqlInstance $Instance -ErrorAction SilentlyContinue -ErrorVariable errorvar } catch { $NotContactable += $Instance $There = $false } if ($NotContactable -notcontains $psitem) { if ($null -eq $InstanceSMO.version) { $NotContactable += $Instance $There = $false } else { $There = $True } } } else { $There = $false } # Get the relevant information for the checks in one go to save repeated trips to the instance and set values for Not Contactable tests if required $AllInstanceInfo = Get-AllInstanceInfo -Instance $InstanceSMO -Tags $Tags -There $There Describe "Instance Connection" -Tags InstanceConnection, Connectivity, High, $filename { $skipremote = Get-DbcConfigValue skip.connection.remoting $skipping = Get-DbcConfigValue skip.connection.ping $skipauth = Get-DbcConfigValue skip.connection.auth $authscheme = Get-DbcConfigValue policy.connection.authscheme if ($NotContactable -contains $psitem) { Context "Testing Instance Connection on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Instance Connection on $psitem" { It "connects successfully to $psitem" { #Because Test-DbaInstance only shows connectsuccess false if the Connect-SQlInstance throws an error and we use Connect-DbaInstance $true | Should -BeTrue } #local is always NTLM except when its a container ;-) if ($InstanceSMO.NetBiosName -eq $ENV:COMPUTERNAME -and ($instance -notlike '*,*')) { It -Skip:$skipauth "auth scheme should be NTLM on the local machine on $psitem" { (Test-DbaConnectionAuthScheme -SqlInstance $Instance).authscheme | Should -Be NTLM } } else { It -Skip:$skipauth "auth scheme should be $authscheme on $psitem" { (Test-DbaConnectionAuthScheme -SqlInstance $Instance).authscheme | Should -Be $authscheme } } It -Skip:$skipping "We should be able to ping host $psitem" { $ping = New-Object System.Net.NetworkInformation.Ping $timeout = 1000 #milliseconds $reply = $ping.Send($InstanceSMO.ComputerName, $timeout) $pingable = $reply.Status -eq 'Success' $pingable | Should -BeTrue } It -Skip:$skipremote "We should be able to remote onto $psitem" { #simple remoting check try { $null = Invoke-Command -ComputerName $InstanceSMO.ComputerName -ScriptBlock { Get-ChildItem } -ErrorAction Stop $remoting = $true } catch { $remoting = $false } $remoting | Should -BeTrue } } } } Describe "SQL Engine Service" -Tags SqlEngineServiceAccount, ServiceAccount, High, $filename { $starttype = Get-DbcConfigValue policy.instance.sqlenginestart $state = Get-DbcConfigValue policy.instance.sqlenginestate if ($NotContactable -contains $psitem) { Context "Testing SQL Engine Service on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { $IsClustered = $InstanceSMO.IsClustered Context "Testing SQL Engine Service on $psitem" { if ( -not $IsLInux) { @(Get-DbaService -ComputerName $psitem -Type Engine -ErrorAction SilentlyContinue).ForEach{ It "SQL Engine service account should be $state on $($psitem.InstanceName)" { Assert-EngineState -AllInstanceInfo $AllInstanceInfo -state $state } if ($IsClustered) { It "SQL Engine service account should have a start mode of Manual on FailOver Clustered Instance $($psitem.InstanceName)" { Assert-EngineStartTypeCluster -AllInstanceInfo $AllInstanceInfo } } else { It "SQL Engine service account should have a start mode of $starttype on standalone instance $($psitem.InstanceName)" { Assert-EngineStartType -AllInstanceInfo $AllInstanceInfo -StartType $starttype } } } } else { It "Running on Linux so can't check Services on $Psitem" -Skip { } } } } } Describe "TempDB Configuration" -Tags TempDbConfiguration, Medium, $filename { if ($NotContactable -contains $psitem) { Context "Testing TempDB Configuration on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing TempDB Configuration on $psitem" { $TempDBTest = Test-DbaTempDbConfig -SqlInstance $psitem It "should have TF1118 enabled on $($TempDBTest[0].SqlInstance)" -Skip:((Get-DbcConfigValue skip.TempDb1118) -or ($InstanceSMO.VersionMajor -gt 12)) { $TempDBTest[0].CurrentSetting | Should -Be $TempDBTest[0].Recommended -Because 'TF 1118 should be enabled' } It "should have $($TempDBTest[1].Recommended) TempDB Files on $($TempDBTest[1].SqlInstance)" -Skip:(Get-DbcConfigValue skip.tempdbfileCount) { $TempDBTest[1].CurrentSetting | Should -Be $TempDBTest[1].Recommended -Because 'This is the recommended number of tempdb files for your server' } It "should not have TempDB Files autogrowth set to percent on $($TempDBTest[2].SqlInstance)" -Skip:(Get-DbcConfigValue skip.TempDbFileGrowthPercent) { $TempDBTest[2].CurrentSetting | Should -Be $TempDBTest[2].Recommended -Because 'Auto growth type should not be percent' } It "should not have TempDB Files on the C Drive on $($TempDBTest[3].SqlInstance)" -Skip:(Get-DbcConfigValue skip.TempDbFilesonC) { $TempDBTest[3].CurrentSetting | Should -Be $TempDBTest[3].Recommended -Because 'You do not want the tempdb files on the same drive as the operating system' } It "should not have TempDB Files with MaxSize Set on $($TempDBTest[4].SqlInstance)" -Skip:(Get-DbcConfigValue skip.TempDbFileSizeMax) { $TempDBTest[4].CurrentSetting | Should -Be $TempDBTest[4].Recommended -Because 'Tempdb files should be able to grow' } It "The data files should all be the same size on $($TempDBTest[0].SqlInstance)" { Assert-TempDBSize -Instance $Psitem } } } } Describe "Ad Hoc Workload Optimization" -Tags AdHocWorkload, Medium, $filename { if ($NotContactable -contains $psitem) { Context "Testing Ad Hoc Workload Optimization on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Ad Hoc Workload Optimization on $psitem" { It "Should have Optimize for Ad Hoc workloads set correctly on $psitem" -Skip:((Get-Version -SQLInstance $psitem) -lt 10) { @(Test-DbaOptimizeForAdHoc -SqlInstance $psitem).ForEach{ $psitem.CurrentOptimizeAdHoc | Should -Be $psitem.RecommendedOptimizeAdHoc -Because "optimize for ad hoc workloads is a recommended setting" } } } } } Describe "Backup Path Access" -Tags BackupPathAccess, Storage, DISA, Medium, $filename { if ($NotContactable -contains $psitem) { Context "Testing Backup Path Access on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Backup Path Access on $psitem" { $backuppath = Get-DbcConfigValue policy.storage.backuppath if (-not $backuppath) { $backuppath = (Get-DbaDefaultPath -SqlInstance $psitem).Backup } It "can access backup path ($backuppath) on $psitem" { Test-DbaPath -SqlInstance $psitem -Path $backuppath | Should -BeTrue -Because 'The SQL Service account needs to have access to the backup path to backup your databases' } } } } Describe "Default File Path" -Tags DefaultFilePath, $filename { if ($NotContactable -contains $psitem) { Context "Testing Default File Path on $psitem" { It "Can't Connect to $Psitem" { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { Context "Testing Default Data File Path on $psitem" { It "Default Data File Path on $psitem" { $diskFile = Get-DbaInstanceProperty -SqlInstance $psitem | Where-Object Name -EQ DefaultFile $diskFile.Value.substring(0, 1) | Should -Not -Be "C" -Because 'Default Data file path should not be your C:\ drive' } } Context "Testing Default Log File Path on $psitem" { It "Default Log File Path on $psitem" { $diskLog = Get-DbaInstanceProperty -SqlInstance $psitem | Where-Object Name -EQ DefaultLog $diskLog.Value.substring(0, 1) | Should -Not -Be "C" -Because 'Default Log file path should not be your C:\ drive' } } } } Describe "Dedicated Administrator Connection" -Tags DAC, CIS, Low, $filename { $dac = Get-DbcConfigValue policy.dacallowed if ($NotContactable -contains $psitem) { Context "Testing Dedicated Administrator Connection on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Dedicated Administrator Connection on $psitem" { It "DAC is set to $dac on $psitem" { (Get-DbaSpConfigure -SqlInstance $psitem -ConfigName 'RemoteDACConnectionsEnabled').ConfiguredValue -eq 1 | Should -Be $dac -Because 'This is the setting that you have chosen for DAC connections' } } } } Describe "Network Latency" -Tags NetworkLatency, Connectivity, Medium, $filename { $max = Get-DbcConfigValue policy.network.latencymaxms if ($NotContactable -contains $psitem) { Context "Testing Network Latency on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Network Latency on $psitem" { @(Test-DbaNetworkLatency -SqlInstance $psitem).ForEach{ It "network latency should be less than $max ms on $($psitem.SqlInstance)" { $psitem.Average.TotalMilliseconds | Should -BeLessThan $max -Because 'You do not want to be waiting on the network' } } } } } Describe "Linked Servers" -Tags LinkedServerConnection, Connectivity, Medium, $filename { if ($NotContactable -contains $psitem) { Context "Testing Linked Servers on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Linked Servers on $psitem" { @(Test-DbaLinkedServerConnection -SqlInstance $psitem).ForEach{ It "Linked Server $($psitem.LinkedServerName) has connectivity on $($psitem.SqlInstance)" { $psitem.Connectivity | Should -BeTrue -Because 'You need to be able to connect to your linked servers' } } } } } Describe "Max Memory" -Tags MaxMemory, High, $filename { if ($NotContactable -contains $psitem) { Context "Testing Max Memory on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Max Memory on $psitem" { if (-not $IsLInux) { It "Max Memory setting should be correct on $psitem" { @(Test-DbaMaxMemory -SqlInstance $psitem).ForEach{ $psitem.MaxValue | Should -BeLessThan ($psitem.RecommendedValue + 379) -Because 'You do not want to exhaust server memory' } } } else { It "Max Memory setting should be correct (running on Linux so only checking Max Memory is less than Total Memory) on $psitem" { # simply check that the max memory is less than total memory $MemoryValues = Get-DbaMaxMemory -SqlInstance $psitem $MemoryValues.Total | Should -BeGreaterThan $MemoryValues.MaxValue -Because 'You do not want to exhaust server memory' } } } } } Describe "Orphaned Files" -Tags OrphanedFile, Low, $filename { if ($NotContactable -contains $psitem) { Context "Checking for orphaned database files on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Checking for orphaned database files on $psitem" { It "There should be zero orphaned database files on $psitem" { @(Find-DbaOrphanedFile -SqlInstance $psitem).Count | Should -Be 0 -Because 'You dont want any orphaned files - Use Find-DbaOrphanedFile to locate them' } } } } Describe "SQL and Windows names match" -Tags ServerNameMatch, Medium, $filename { if ($NotContactable -contains $psitem) { Context "Testing instance name matches Windows name for $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing instance name matches Windows name for $psitem" { if ($InstanceSMO.NetBiosName -eq $ENV:COMPUTERNAME -and ($instance -like '*,*')) { It "We wont check this as it appears to be a local container - for $psitem" -Skip { } } else { It "Testing rename required for $psitem" { (Test-DbaInstanceName -SqlInstance $psitem).RenameRequired | Should -BeFalse -Because 'SQL and Windows should agree on the server name' } } } } } Describe "SQL Memory Dumps" -Tags MemoryDump, Medium, $filename { $maxdumps = Get-DbcConfigValue policy.dump.maxcount if ($NotContactable -contains $psitem) { Context "Checking that dumps on $psitem do not exceed $maxdumps for $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Checking that dumps on $psitem do not exceed $maxdumps for $psitem" { It "dump count of $count is less than or equal to the $maxdumps dumps on $psitem" -Skip:($InstanceSMO.Version.Major -lt 11 -and (-not ($InstanceSMO.Version.Major -eq 10 -and $InstanceSMO.Version.Minor -eq 50)) ) { Assert-MaxDump -AllInstanceInfo $AllInstanceInfo -maxdumps $maxdumps } } } } Describe "Supported Build" -Tags SupportedBuild, DISA, High, $filename { $BuildWarning = Get-DbcConfigValue policy.build.warningwindow $BuildBehind = Get-DbcConfigValue policy.build.behind $Date = Get-Date if ($NotContactable -contains $psitem) { Context "Checking that build is still supported by Microsoft for $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Checking that build is still supported by Microsoft for $psitem" { if ($BuildBehind) { It "The build is not behind the latest build by more than $BuildBehind for $psitem" { Assert-InstanceSupportedBuild -Instance $InstanceSMO -BuildBehind $BuildBehind -Date $Date } } It "The build is supported by Microsoft for $psitem" { Assert-InstanceSupportedBuild -Instance $InstanceSMO -Date $Date } It "The build is supported by Microsoft within the warning window of $BuildWarning months for $psitem" { Assert-InstanceSupportedBuild -Instance $InstanceSMO -BuildWarning $BuildWarning -Date $Date } } } } Describe "SA Login Renamed" -Tags SaRenamed, DISA, CIS, Medium, $filename { if ($NotContactable -contains $psitem) { Context "Checking that sa login has been renamed on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Checking that sa login has been renamed on $psitem" { $results = Get-DbaLogin -SqlInstance $psitem -Login sa It "sa login has been renamed on $psitem" { $results | Should -Be $null -Because 'Renaming the sa account is a requirement' } } } } Describe "SA Login Disabled" -Tags SaDisabled, DISA, CIS, Medium, $filename { if ($NotContactable -contains $psitem) { Context "Checking that sa login has been disabled on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Checking that sa login has been disabled on $psitem" { $skip = Get-DbcConfigValue skip.security.sadisabled It "sa login is disabled on $psitem" -Skip:$Skip { Assert-SaDisabled -AllInstanceInfo $AllInstanceInfo } } } } Describe "Login SA cannot exist" -Tags SaExist, CIS, Medium, $filename { if ($NotContactable -contains $psitem) { Context "Checking that a login named sa does not exist on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Checking that a login named sa does not exist on $psitem" { $skip = Get-DbcConfigValue skip.security.saexist It "sa login does not exist on $psitem" -Skip:$Skip { Assert-SaExist -AllInstanceInfo $AllInstanceInfo } } } } Describe "Default Backup Compression" -Tags DefaultBackupCompression, Low, $filename { $defaultbackupcompression = Get-DbcConfigValue policy.backup.defaultbackupcompression if ($NotContactable -contains $psitem) { Context "Testing Default Backup Compression on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Default Backup Compression on $psitem" { It "Default Backup Compression is set to $defaultbackupcompression on $psitem" -Skip:((Get-Version -SQLInstance $psitem) -lt 10) { Assert-BackupCompression -Instance $psitem -defaultbackupcompression $defaultbackupcompression } } } } Describe "XE Sessions That should be Stopped" -Tags XESessionStopped, ExtendedEvent, Medium, $filename { $xesession = Get-DbcConfigValue policy.xevent.requiredstoppedsession if ((Get-Version -SQLInstance $psitem) -gt 10) { # no point running if we dont have something to check if ($xesession) { if ($NotContactable -contains $psitem) { Context "Checking sessions on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Checking sessions on $psitem" { $runningsessions = (Get-DbaXESession -SqlInstance $psitem).Where{ $_.Status -eq 'Running' }.Name @($xesession).ForEach{ It "Session $psitem should not be running on $Instance" { $psitem | Should -Not -BeIn $runningsessions -Because "$psitem session should be stopped" } } } } } else { Write-Warning "You need to use Set-DbcConfig -Name policy.xevent.requiredstoppedsession -Value to add some Extended Events session names to run this check" } } else { Context "Checking sessions on $psitem" { It "Version does not support XE sessions on $Instance" -Skip { 1 | Should -Be 3 } } } } Describe "XE Sessions That should be Running" -Tags XESessionRunning, ExtendedEvent, Medium, $filename { $xesession = Get-DbcConfigValue policy.xevent.requiredrunningsession if ((Get-Version -SQLInstance $psitem) -gt 10) { # no point running if we dont have something to check if ($xesession) { if ($NotContactable -contains $psitem) { Context "Checking running sessions on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Checking running sessions on $psitem" { $runningsessions = (Get-DbaXESession -SqlInstance $psitem).Where{ $_.Status -eq 'Running' }.Name @($xesession).ForEach{ It "session $psitem should be running on $Instance" { $psitem | Should -BeIn $runningsessions -Because "$psitem session should be running" } } } } } else { Write-Warning "You need to use Set-DbcConfig -Name policy.xevent.requiredrunningsession -Value to add some Extended Events session names to run this check" } } else { Context "Checking running sessions on $psitem" { It "Version does not support XE sessions on $Instance" -Skip { 1 | Should -Be 3 } } } } Describe "XE Sessions That Are Allowed to Be Running" -Tags XESessionRunningAllowed, ExtendedEvent, Medium, $filename { $xesession = Get-DbcConfigValue policy.xevent.validrunningsession if ((Get-Version -SQLInstance $psitem) -gt 10) { # no point running if we dont have something to check if ($xesession) { if ($NotContactable -contains $psitem) { Context "Checking running sessions allowed on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Checking running sessions allowed on $psitem" { @(Get-DbaXESession -SqlInstance $psitem).Where{ $_.Status -eq 'Running' }.ForEach{ It "Session $($Psitem.Name) is allowed to be running on $Instance" { $psitem.name | Should -BeIn $xesession -Because "Only these sessions are allowed to be running" } } } } } else { Write-Warning "You need to use Set-DbcConfig -Name policy.xevent.validrunningsession -Value to add some Extended Events session names to run this check" } } else { Context "Checking running sessions allowed on $psitem" { It "Version does not support XE sessions on $Instance" -Skip { 1 | Should -Be 3 } } } } Describe "OLE Automation" -Tags OLEAutomation, security, CIS, Medium, $filename { $OLEAutomation = Get-DbcConfigValue policy.oleautomation if ($NotContactable -contains $psitem) { Context "Testing OLE Automation on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing OLE Automation on $psitem" { It "OLE Automation is set to $OLEAutomation on $psitem" { (Get-DbaSpConfigure -SqlInstance $psitem -ConfigName 'OleAutomationProceduresEnabled').ConfiguredValue -eq 1 | Should -Be $OLEAutomation -Because 'OLE Automation can introduce additional security risks' } } } } Describe "sp_whoisactive is Installed" -Tags WhoIsActiveInstalled, Low, $filename { $db = Get-DbcConfigValue policy.whoisactive.database if ($NotContactable -contains $psitem) { Context "Testing WhoIsActive exists on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing WhoIsActive exists on $psitem" { It "WhoIsActive should exists on $db on $psitem" { (Get-DbaModule -SqlInstance $psitem -Database $db -Type StoredProcedure | Where-Object name -EQ "sp_WhoIsActive") | Should -Not -Be $Null -Because 'The sp_WhoIsActive stored procedure should be installed' } } } } Describe "Model Database Growth" -Tags ModelDbGrowth, Low, $filename { $modeldbgrowthtest = Get-DbcConfigValue skip.instance.modeldbgrowth if (-not $modeldbgrowthtest) { if ($NotContactable -contains $psitem) { Context "Testing model database growth setting is not default on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing model database growth setting is not default on $psitem" { @(Get-DbaDbFile -SqlInstance $psitem -Database Model).ForEach{ It "Model database growth settings should not be percent for file $($psitem.LogicalName) on $($psitem.SqlInstance)" { $psitem.GrowthType | Should -Not -Be 'Percent' -Because 'New databases use the model database as a template and percent growth can cause performance problems' } It "Model database growth settings should not be 1Mb for file $($psitem.LogicalName) on $($psitem.SqlInstance)" { $psitem.Growth | Should -Not -Be 1024 -Because 'New databases use the model database as a template and growing for each Mb will have a performance impact' } } } } } } Describe "Ad Users and Groups " -Tags ADUser, Domain, High, $filename { if (-not $IsLinux) { $userexclude = Get-DbcConfigValue policy.adloginuser.excludecheck $groupexclude = Get-DbcConfigValue policy.adlogingroup.excludecheck if ($NotContactable -contains $psitem) { Context "Testing Active Directory users on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } Context "Testing Active Directory groups on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Active Directory users on $psitem" { @(Test-DbaWindowsLogin -SqlInstance $psitem -FilterBy LoginsOnly -ExcludeLogin $userexclude).ForEach{ It "Active Directory user $($psitem.login) was found in $Instance on $($psitem.domain)" { $psitem.found | Should -Be $true -Because "$($psitem.login) should be in Active Directory" } if ($psitem.found -eq $true) { It "Active Directory user $($psitem.login) should not have an expired password in $Instance on $($psitem.domain)" { $psitem.PasswordExpired | Should -Be $false -Because "$($psitem.login) password should not be expired" } It "Active Directory user $($psitem.login) should not be locked out in $Instance on $($psitem.domain)" { $psitem.lockedout | Should -Be $false -Because "$($psitem.login) should not be locked out" } It "Active Directory user $($psitem.login) should be enabled in $Instance on $($psitem.domain)" { $psitem.Enabled | Should -Be $true -Because "$($psitem.login) should be enabled" } It "Active Directory user $($psitem.login) should not be disabled in $Instance on $($psitem.Server)" { $psitem.DisabledInSQLServer | Should -Be $false -Because "$($psitem.login) should be active on the SQL server" } } } } Context "Testing Active Directory groups on $psitem" { @(Test-DbaWindowsLogin -SqlInstance $psitem -FilterBy GroupsOnly -ExcludeLogin $groupexclude).ForEach{ It "Active Directory group $($psitem.login) was found in $Instance on $($psitem.domain)" { $psitem.found | Should -Be $true -Because "$($psitem.login) should be in Active Directory" } if ($psitem.found -eq $true) { It "Active Directory group $($psitem.login) should not be disabled in $Instance on $($psitem.Server)" { $psitem.DisabledInSQLServer | Should -Be $false -Because "$($psitem.login) should be active on the SQL server" } } } } } } else { Context "Testing Active Directory users on $psitem" { It "Running on Linux so can't check AD on $Psitem" -Skip { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } Context "Testing Active Directory groups on $psitem" { It "Running on Linux so can't check AD on $Psitem" -Skip { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } } Describe "Error Log Entries" -Tags ErrorLog, Medium, $filename { $logwindow = Get-DbcConfigValue policy.errorlog.warningwindow if ($NotContactable -contains $psitem) { Context "Checking error log on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Checking error log on $psitem" { It "Error log should be free of error severities 17-24 within the window of $logwindow days on $psitem" { Assert-ErrorLogEntry -AllInstanceInfo $AllInstanceInfo } } } } Describe "Error Log Count" -Tags ErrorLogCount, CIS, Low, $filename { $errorLogCount = Get-DbcConfigValue policy.errorlog.logcount if ($NotContactable -contains $psitem) { Context "Checking error log count on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Checking error log count on $psitem" { It "Error log count should be greater or equal to $errorLogCount on $psitem" { Assert-ErrorLogCount -SqlInstance $psitem -errorLogCount $errorLogCount } } } } Describe "Instance MaxDop" -Tags MaxDopInstance, MaxDop, Medium, $filename { $UseRecommended = Get-DbcConfigValue policy.instancemaxdop.userecommended $MaxDop = Get-DbcConfigValue policy.instancemaxdop.maxdop $ExcludeInstance = Get-DbcConfigValue policy.instancemaxdop.excludeinstance if ($NotContactable -contains $psitem) { Context "Testing Instance MaxDop Value on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { if ($psitem -in $ExcludeInstance) { $Skip = $true }else { $skip = $false } Context "Testing Instance MaxDop Value on $psitem" { It "Instance Level MaxDop setting should be correct on $psitem" -Skip:$Skip { Assert-InstanceMaxDop -Instance $psitem -UseRecommended:$UseRecommended -MaxDopValue $MaxDop } } } } Describe "Two Digit Year Cutoff" -Tags TwoDigitYearCutoff, Low, $filename { $twodigityearcutoff = Get-DbcConfigValue policy.twodigityearcutoff if ($NotContactable -contains $psitem) { Context "Testing Two Digit Year Cutoff on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Two Digit Year Cutoff on $psitem" { It "Two Digit Year Cutoff is set to $twodigityearcutoff on $psitem" { Assert-TwoDigitYearCutoff -Instance $psitem -TwoDigitYearCutoff $twodigityearcutoff } } } } Describe "Trace Flags Expected" -Tags TraceFlagsExpected, TraceFlag, High, $filename { $ExpectedTraceFlags = Get-DbcConfigValue policy.traceflags.expected if ($NotContactable -contains $psitem) { Context "Testing Expected Trace Flags on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { if ($null -eq $ExpectedTraceFlags) { $ExpectedTraceFlags = 0 } $ActualTraceflags = (Get-DbaTraceFlag -SqlInstance $psitem).TraceFlag Context "Testing Expected Trace Flags on $psitem" { foreach ($ExpectedTraceFlag in $ExpectedTraceFlags) { if ($ExpectedTraceFlag -ne 0) { It "Expected Trace Flag $ExpectedTraceFlag to exist on $psitem" { Assert-TraceFlag -ActualTraceflags $ActualTraceflags -ExpectedTraceFlag $ExpectedTraceFlag } } else { It "Expected No Trace Flag to exist on $psitem" { Assert-TraceFlag -ActualTraceflags $ActualTraceflags -ExpectedTraceFlag $ExpectedTraceFlag } } } } } } Describe "Trace Flags Not Expected" -Tags TraceFlagsNotExpected, TraceFlag, Medium, $filename { $NotExpectedTraceFlags = Get-DbcConfigValue policy.traceflags.notexpected $ExpectedTraceFlags = Get-DbcConfigValue policy.traceflags.expected if ($NotContactable -contains $psitem) { Context "Testing Not Expected Trace Flags on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Not Expected Trace Flags on $psitem" { It "Expected Trace Flags $NotExpectedTraceFlags to not exist on $psitem" { Assert-NotTraceFlag -SQLInstance $psitem -NotExpectedTraceFlag $NotExpectedTraceFlags -ExpectedTraceFlag $ExpectedTraceFlags } } } } Describe "CLR Enabled" -Tags CLREnabled, security, CIS, High, $filename { $CLREnabled = Get-DbcConfigValue policy.security.clrenabled if ($NotContactable -contains $psitem) { Context "Testing CLR Enabled on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing CLR Enabled on $psitem" { It "CLR Enabled is set to $CLREnabled on $psitem" { Assert-CLREnabled -SQLInstance $psitem -CLREnabled $CLREnabled } } } } Describe "Cross Database Ownership Chaining" -Tags CrossDBOwnershipChaining, security, CIS, Medium, $filename { if ($NotContactable -contains $psitem) { Context "Testing Cross Database Ownership Chaining on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Cross Database Ownership Chaining on $psitem" { It "Cross Database Ownership Chaining should be disabled on $psitem" { Assert-CrossDBOwnershipChaining -AllInstanceInfo $AllInstanceInfo } } } } Describe "Ad Hoc Distributed Queries" -Tags AdHocDistributedQueriesEnabled, security, CIS, Medium, $filename { $AdHocDistributedQueriesEnabled = Get-DbcConfigValue policy.security.AdHocDistributedQueriesEnabled if ($NotContactable -contains $psitem) { Context "Testing Ad Hoc Distributed Queries on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing Ad Hoc Distributed Queries on $psitem" { It "Ad Hoc Distributed Queries is set to $AdHocDistributedQueriesEnabled on $psitem" { Assert-AdHocDistributedQueriesEnabled -SQLInstance $Psitem -AdHocDistributedQueriesEnabled $AdHocDistributedQueriesEnabled } } } } Describe "XP CmdShell" -Tags XpCmdShellDisabled, security, CIS, Medium, $filename { $XpCmdShellDisabled = Get-DbcConfigValue policy.security.XpCmdShellDisabled if ($NotContactable -contains $psitem) { Context "Testing XP CmdShell on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Testing XP CmdShell on $psitem" { It "XPCmdShell is set to $XpCmdShellDisabled on $psitem" { Assert-XpCmdShellDisabled -SQLInstance $Psitem -XpCmdShellDisabled $XpCmdShellDisabled } } } } Describe "Scan For Startup Procedures" -Tags ScanForStartupProceduresDisabled, Security, CIS, Medium, $filename { $skip = Get-DbcConfigValue skip.instance.scanforstartupproceduresdisabled $ScanForStartupProcsDisabled = Get-DbcConfigValue policy.security.scanforstartupproceduresdisabled if ($NotContactable -contains $psitem) { Context "Testing Scan For Startup Procedures on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { Context "Testing Scan For Startup Procedures on $psitem" { It "Scan For Startup Procedures is set to $ScanForStartupProcsDisabled on $psitem" -Skip:$skip { Assert-ScanForStartupProcedures -AllInstanceInfo $AllInstanceInfo -ScanForStartupProcsDisabled $ScanForStartupProcsDisabled } } } } Describe "Default Trace" -Tags DefaultTrace, CIS, Low, $filename { $skip = Get-DbcConfigValue skip.instance.defaulttrace if ($NotContactable -contains $psitem) { Context "Checking Default Trace on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Checking Default Trace on $psitem" { It "The Default Trace should be enabled on $psitem" -Skip:$skip { Assert-DefaultTrace -AllInstanceInfo $AllInstanceInfo } } } } Describe "OLE Automation Procedures Disabled" -Tags OLEAutomationProceduresDisabled, CIS, Low, $filename { $skip = Get-DbcConfigValue skip.instance.oleautomationproceduresdisabled if ($NotContactable -contains $psitem) { Context "Checking OLE Automation Procedures on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { Context "Checking OLE Automation Procedures on $psitem" { It "The OLE Automation Procedures should be disabled on $psitem" -Skip:$skip { Assert-OLEAutomationProcedures -AllInstanceInfo $AllInstanceInfo } } } } Describe "Remote Access Disabled" -Tags RemoteAccessDisabled, Security, CIS, Medium, $filename { $skip = Get-DbcConfigValue skip.instance.remoteaccessdisabled if ($NotContactable -contains $psitem) { Context "Testing Remote Access on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { Context "Testing Remote Access on $psitem" { It "The Remote Access should be disabled on $psitem" -Skip:$skip { Assert-RemoteAccess -AllInstanceInfo $AllInstanceInfo } } } } Describe "Latest Build" -Tags LatestBuild, Security, CIS, Medium, $filename { $skip = Get-DbcConfigValue skip.instance.latestbuild if ($NotContactable -contains $psitem) { Context "Testing Latest Build on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { Context "Testing Latest Build on $psitem" { It "The Latest Build of SQL should be installed on $psitem" -Skip:$skip { Assert-LatestBuild -AllInstanceInfo $AllInstanceInfo } } } } Describe "Login BUILTIN Administrators cannot exist" -Tags BuiltInAdmin, CIS, Medium, $filename { if ($NotContactable -contains $psitem) { Context "Checking that a login named BUILTIN\Administrators does not exist on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { Context "Checking that a login named BUILTIN\Administrators does not exist on $psitem" { $skip = Get-DbcConfigValue skip.security.builtinadmin It "BUILTIN\Administrators login does not exist on $psitem" -Skip:$skip { Assert-BuiltInAdmin -AllInstanceInfo $AllInstanceInfo } } } } Describe "Local Windows Groups Not Have SQL Logins" -Tags LocalWindowsGroup, Security, CIS, Medium, $filename { $skip = Get-DbcConfigValue skip.security.localwindowsgroup if ($NotContactable -contains $psitem) { Context "Checking that local Windows groups do not have SQL Logins on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { Context "Checking that local Windows groups do not have SQL Logins on $psitem" { It "Local Windows groups should not SQL Logins on $psitem" -Skip:$skip { Assert-LocalWindowsGroup -AllInstanceInfo $AllInstanceInfo } } } } Describe "Failed Login Auditing" -Tags LoginAuditFailed, Security, CIS, Medium, $filename { $skip = Get-DbcConfigValue skip.security.loginauditlevelfailed if ($NotContactable -contains $psitem) { Context "Testing if failed login auditing is in place on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { Context "Testing if failed login auditing is in place on $psitem" { It "The failed login auditing should be set on $psitem" -Skip:$skip { Assert-LoginAuditFailed -AllInstanceInfo $AllInstanceInfo } } } } Describe "Successful Login Auditing" -Tags LoginAuditSuccessful, Security, CIS, Medium, $filename { $skip = Get-DbcConfigValue skip.security.loginauditlevelsuccessful if ($NotContactable -contains $psitem) { Context "Testing if successful and failed login auditing is in place on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { Context "Testing if successful and failed login auditing is in place on $psitem" { It "The successful and failed auditing should be set on $psitem" -Skip:$skip { Assert-LoginAuditSuccessful -AllInstanceInfo $AllInstanceInfo } } } } Describe "SqlAgentProxiesNoPublicRole" -Tags SqlAgentProxiesNoPublicRole, Security, CIS, Medium, $filename { $skip = Get-DbcConfigValue skip.security.sqlagentproxiesnopublicrole if ($NotContactable -contains $psitem) { Context "Testing to see if the public role has access to the SQL Agent proxies on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { Context "Testing to see if the public role has access to the SQL Agent proxies on $psitem" { It "The public role should not have access to the SQL Agent Proxies on $psitem" -Skip:$skip { Assert-SqlAgentProxiesNoPublicRole -AllInstanceInfo $AllInstanceInfo } } } } Describe "Hide Instance" -Tags HideInstance, Security, CIS, Medium, $filename { $skip = Get-DbcConfigValue skip.security.hideinstance if ($NotContactable -contains $psitem) { Context "Checking the Hide an Instance of SQL Server Database Engine property on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { Context "Checking the Hide an Instance of SQL Server Database Engine property on $psitem" { It "The Hide an Instance of SQL Server Database Engine property on SQL Server instance $psitem" -Skip:$skip { Assert-HideInstance -AllInstanceInfo $AllInstanceInfo } } } } Describe "SQL Engine Service Admin" -Tags EngineServiceAdmin, Security, CIS, Medium, $filename { $skip = Get-DbcConfigValue skip.security.EngineServiceAdmin if ($NotContactable -contains $psitem) { Context "Testing whether SQL Engine account is a local administrator on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { if ($IsCoreCLR) { $Skip = $true } Context "Testing whether SQL Engine account is a local administrator on $psitem" { It "The SQL Engine service account should not be a local administrator on $psitem" -Skip:$skip { Assert-EngineServiceAdmin -AllInstanceInfo $AllInstanceInfo } } } } Describe "SQL Agent Service Admin" -Tags AgentServiceAdmin, Security, CIS, Medium, $filename { $skip = Get-DbcConfigValue skip.security.AgentServiceAdmin if ($NotContactable -contains $psitem) { Context "Testing whether SQL Agent account is a local administrator on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { if ($IsCoreCLR) { $Skip = $true } Context "Testing whether SQL Agent account is a local administrator on $psitem" { It "The SQL Agent service account should not be a local administrator on $psitem" -Skip:$skip { Assert-AgentServiceAdmin -AllInstanceInfo $AllInstanceInfo } } } } Describe "SQL Full Text Service Admin" -Tags FullTextServiceAdmin, Security, CIS, Medium, $filename { $skip = Get-DbcConfigValue skip.security.FullTextServiceAdmin if ($NotContactable -contains $psitem) { Context "Testing whether SQL Full Text account is a local administrator on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { if ($IsCoreCLR) { $Skip = $true } Context "Testing whether SQL Full Text account is a local administrator on $psitem" { It "The SQL Full Text service account should not be a local administrator on $psitem" -Skip:$skip { Assert-FullTextServiceAdmin -AllInstanceInfo $AllInstanceInfo } } } } Describe "Login Check Policy" -Tags LoginCheckPolicy, Security, CIS, Medium, $filename { $skip = Get-DbcConfigValue skip.security.LoginCheckPolicy if ($NotContactable -contains $psitem) { Context "Testing if the CHECK_POLICY is enabled on all logins on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { Context "Testing if the CHECK_POLICY is enabled on all logins on $psitem" { It "All logins should have the CHECK_POLICY option set to ON on $psitem" -Skip:$skip { Assert-LoginCheckPolicy -AllInstanceInfo $AllInstanceInfo } } } } Describe "Login Password Expiration" -Tags LoginPasswordExpiration, Security, CIS, Medium, $filename { $skip = Get-DbcConfigValue skip.security.LoginPasswordExpiration if ($NotContactable -contains $psitem) { Context "Testing if the login password expiration is enabled for sql logins in the sysadmin role $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { Context "Testing if the login password expiration is enabled for sql logins in the sysadmin role on $psitem" { It "All sql logins should have the password expiration option set to ON in the sysadmin role on $psitem" -Skip:$skip { Assert-LoginPasswordExpiration -AllInstanceInfo $AllInstanceInfo } } } } Describe "Login Must Change" -Tags LoginMustChange, Security, CIS, Medium, $filename { $skip = Get-DbcConfigValue skip.security.LoginMustChange if ($NotContactable -contains $psitem) { Context "Testing if the new SQL logins that have not logged have to change their password when they log in on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { Context "Testing if the new SQL logins that have not logged have to change their password when they log in on $psitem" { It "All new sql logins should have the have to change their password when they log in for the first time on $psitem" -Skip:$skip { Assert-LoginMustChange -AllInstanceInfo $AllInstanceInfo } } } } Describe "Suspect Page Limit Nearing" -Tags SuspectPageLimit, Medium, $filename { $skip = Get-DbcConfigValue skip.instance.suspectpagelimit $thresholdPercent = Get-DbcConfigValue policy.suspectpage.threshold if ($NotContactable -contains $psitem) { Context "Testing if the suspect_pages table is nearing the limit of 1000 rows on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { Context "Testing if the suspect_pages table is nearing the limit of 1000 rows on $psitem" { It "The suspect_pages table in msdb shouldn't be nearing the limit of 1000 rows on $psitem" -Skip:$skip { (((Get-DbaSuspectPage -SqlInstance $psitem | Measure-Object).Count) / 1000) * 100 | Should -BeLessThan $thresholdPercent } } } } Describe "SQL Mail XPs Disabled" -Tags SQLMailXPsDisabled, Security, CIS, Medium, $filename { $skip = Get-DbcConfigValue skip.security.SQLMailXPsDisabled if ($NotContactable -contains $psitem) { Context "Testing SQL Mail XPs on $psitem" { It "Can't Connect to $Psitem" -Skip:($skip -or $InstanceSMO.VersionMajor -gt 10) { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { Context "Testing SQL Mail XPs on $psitem" { It "The SQL Mail XPs should be disabled on $psitem" -Skip:($skip -or $InstanceSMO.VersionMajor -gt 10) { Assert-SQLMailXPs -AllInstanceInfo $AllInstanceInfo } } } } Describe "Public Role Permissions" -Tags PublicPermission, Security, CIS, Medium, $filename { $skip = Get-DbcConfigValue skip.security.PublicPermission if ($NotContactable -contains $psitem) { Context "Testing if the public role permissions don't have permissions on $psitem" { It "Can't Connect to $Psitem" -Skip:$skip { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { Context "Testing if the public role permissions don't have permissions on $psitem" { It "All permissions should be set to CIS standards on the public role on $psitem" -Skip:$skip { Assert-PublicPermission -AllInstanceInfo $AllInstanceInfo } } } } } Describe "SQL Browser Service" -Tags SqlBrowserServiceAccount, ServiceAccount, CIS, High, $filename { @(Get-ComputerName).ForEach{ if ($NotContactable -contains $psitem) { Context "Testing SQL Browser Service on $psitem" { It "Can't Connect to $Psitem" { $true | Should -BeFalse -Because "The instance should be available to be connected to!" } } } else { # cant check agent on container - hmm does this actually work with instance need to check if (-not $IsLinux -and ($InstanceSMO.HostPlatform -ne 'Linux')) { Context "Testing SQL Browser Service on $psitem" { if (-not $IsLinux) { $Services = Get-DbaService -ComputerName $psitem if ($Services.Where{ $_.ServiceType -eq 'Engine' }.Count -eq 1) { It "SQL Browser service should be Stopped as only one instance is installed on $psitem" { $Services.Where{ $_.ServiceType -eq 'Browser' }.State | Should -Be "Stopped" -Because 'Unless there are multiple instances you dont need the browser service' } } else { It "SQL Browser service should be Running as multiple instances are installed on $psitem" { $Services.Where{ $_.ServiceType -eq 'Browser' }.State | Should -Be "Running" -Because 'You need the browser service with multiple instances' } } if ($Services.Where{ $_.ServiceType -eq 'Engine' }.Count -eq 1) { It "SQL Browser service startmode should be Disabled as only one instance is installed on $psitem" { $Services.Where{ $_.ServiceType -eq 'Browser' }.StartMode | Should -Be "Disabled" -Because 'Unless there are multiple instances you dont need the browser service' } } else { It "SQL Browser service startmode should be Automatic as multiple instances are installed on $psitem" { $Services.Where{ $_.ServiceType -eq 'Browser' }.StartMode | Should -Be "Automatic" } } } else { It "Running on Linux so can't check Services on $Psitem" -Skip { } } } } else { Context "Testing SQL Browser Service on $psitem" { It "Running on Linux or connecting to container so can't check Services on $Psitem" -Skip { } } } } } } Set-PSFConfig -Module dbachecks -Name global.notcontactable -Value $NotContactable # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUW4dbcY1WxYJ8l/oAYpwlqWaL # aV+gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQWsI/NEEkwLkqtHxRQfgYdjkSp # BTANBgkqhkiG9w0BAQEFAASCAQCAwuSHT8zQvUzd0+krCKk8F7Cr3g2FAbQvyyNV # VVstquqAh3cPQAt2Lk90/jNnklPLKWqTr7FTOkLdwkMs6NSvwRoJu6XBNL/ginmp # R8GpzyFEp4p1Pot+dZSds/d+wx3G9C9+V8Nchj0oeQSMPjbalUTPNPfx1o7cpHEH # k8JY8K7rnCSSnCnkeZPP5KmXSrN9nSL9yX8EbQfmHSX8p/mNvPhkdWoxiTeAeEp0 # Rh6z/OF4acRn3MxwpT+8WHvAT+X9Cen5Ec5o/BCdsx6E817E8g30x4RpO6I1jVWL # tYmk20LK2bUx5An2PGWmbutWs9KOn4OiM7TG0YG6WRL0i4Ot # SIG # End signature block ================================================ FILE: source/checks/Instancev5.Tests.ps1 ================================================ # So the v5 files need to be handled differently. # Ww will start with a BeforeDiscovery which will gather the Instance Information up front # Gather the instances we know are not contactable BeforeDiscovery { # Gather the instances we know are not contactable [string[]]$NotContactable = (Get-PSFConfig -Module dbachecks -Name global.notcontactable).Value # Get all the tags in use in this run $Tags = Get-CheckInformation -Check $Check -Group Instance -AllChecks $AllChecks -ExcludeCheck $ChecksToExclude $InstancesToTest = @(Get-Instance).ForEach{ # just add it to the Not Contactable list if ($NotContactable -notcontains $psitem) { $Instance = $psitem try { $InstanceSMO = Connect-DbaInstance -SqlInstance $Instance -ErrorAction SilentlyContinue -ErrorVariable errorvar } catch { $NotContactable += $Instance } if ($NotContactable -notcontains $psitem) { if ($null -eq $InstanceSMO.version) { $NotContactable += $Instance } else { # Get the relevant information for the checks in one go to save repeated trips to the instance and set values for Not Contactable tests if required NewGet-AllInstanceInfo -Instance $InstanceSMO -Tags $Tags } } } } Write-PSFMessage -Message "Instances = $($InstancesToTest.Name)" -Level Verbose #if you ever need to see what is being tested uncomment and run in verbose but this crashed with a weird Microsoft.SqlServer.Management.Sdk.Sfc.InvalidQueryExpressionEnumeratorException: urn could not be resolved at level OleDbProviderSetting. # $InstancesToTestJson = $InstancesToTest | ConvertTo-Json -Depth 10 #Write-PSFMessage -Message "InstancesToTest = $InstancesToTestJson" -Level Verbose Set-PSFConfig -Module dbachecks -Name global.notcontactable -Value $NotContactable # Get-DbcConfig is expensive so we call it once $__dbcconfig = Get-DbcConfig $notcontactable = (Get-PSFConfig -Module dbachecks -Name global.notcontactable).Value $Checks = Get-DbcCheck $TestsNoGoBrrr = foreach ($Not in $notcontactable) { foreach ($tag in $tags) { [PSCustomObject]@{ Name = $Not Tag = $tag } } } } BeforeAll { } Describe "<_.Tag> failed on <_.Name>" -Tag FailedConnections -ForEach $TestsNoGoBrrr { Context "Checking <_.Tag> on <_.Name>" { It "The instance <_.Name> is not connectable" -Skip:$skip { $false | Should -BeTrue -Because "This instance is not connectable" } } } # Ordered alphabetically by unique tag please Describe "Ad Hoc Distributed Queries" -Tag AdHocDistributedQueriesEnabled, security, CIS, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.AdHocDistributedQueriesEnabled' }).Value Context "Checking Ad Hoc Distributed Queries on <_.Name>" { It "Ad Hoc Distributed Queries is set to <_.ConfigValues.AdHocDistributedQueriesEnabled> on <_.Name>" -Skip:$skip { $PSItem.Configuration.AdHocDistributedQueriesEnabled.ConfigValue -eq 1 | Should -Be $psitem.ConfigValues.AdHocDistributedQueriesEnabled -Because 'This is the setting you have chosen for AdHoc Distributed Queries Enabled' } } } Describe "Ad Hoc Workload Optimization" -Tag AdHocWorkload, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.AdHocWorkload' }).Value Context "Checking Ad Hoc Workload Optimization on <_.Name>" { It "Ad Hoc Workload Optimization is enabled on <_.Name>" -Skip:($skip -or $psitem.VersionMajor -lt 10) { $PSItem.Configuration.OptimizeAdhocWorkloads.ConfigValue -eq 1 | Should -Be 1 -Because "Optimize for ad hoc workloads is a recommended setting" } } } Describe "SQL Agent Service Admin" -Tags AgentServiceAdmin, Security, CIS, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.security.AgentServiceAdmin' }).Value Context "Testing whether SQL Agent account is a local administrator on <_.Name>" { It "The SQL Agent service account should not be a local administrator on <_.Name>" -Skip:$skip { # We don't make this -BeFalse because the possible results are $true/$false/'Could not connect' $psitem.AgentServiceAdminExist | Should -Be $false -Because "We expected the service account for the SQL Agent to not be a local administrator" } } } Describe "Backup Path Access" -Tag BackupPathAccess, Storage, DISA, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.BackupPathAccess' }).Value Context "Testing Backup Path Access on <_.Name>" { It "can access backup path <_.BackupPathAccess.BackupPath> on <_.Name>" { $PsItem.BackupPathAccess.Result | Should -BeTrue -Because 'The SQL Service account needs to have access to the backup path $($PsItem.BackupPathAccess.BackupPath) to backup your databases' } } } Describe "CLR Enabled" -Tag CLREnabled, security, CIS, High, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.CLREnabled' }).Value Context "Testing CLR Enabled on <_.Name>" { It "CLR Enabled is set to <_.ConfigValues.CLREnabled> on <_.Name>" -Skip:$skip { $PSItem.Configuration.IsSqlClrEnabled.ConfigValue -eq 1 | Should -Be $psitem.ConfigValues.CLREnabled -Because 'This is the setting you have chosen for CLR Enabled' } } } Describe "Cross Database Ownership Chaining" -Tag CrossDBOwnershipChaining, Security, CIS, Low, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.CrossDBOwnershipChaining' }).Value Context "Checking Cross Database Ownership Chaining on <_.Name>" { It "Cross Database Ownership Chaining should be disabled on <_.Name>" -Skip:$skip { $PSItem.Configuration.CrossDBOwnershipChaining.ConfigValue | Should -Be 0 -Because "We expected the Cross DB Ownership Chaining to be disabled" } } } Describe "Dedicated Administrator Connection" -Tag DAC, Security, CIS, Low, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.dac' }).Value Context "Checking Dedicated Administrator Connection on <_.Name>" { It "DAC is set to <_.ConfigValues.dacallowed> on <_.Name>" -Skip:$skip { $PSItem.Configuration.RemoteDACConnectionsEnabled.ConfigValue -eq 1 | Should -Be $psitem.ConfigValues.dacallowed -Because 'This is the setting that you have chosen for DAC connections' } } } Describe "Default Backup Compression" -Tag DefaultBackupCompression, Low, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.DefaultBackupCompression' }).Value Context "Checking Default Backup Compression on <_.Name>" { It "Default Backup Compression is set to <_.ConfigValues.DefaultBackupCompression> on <_.Name>" -Skip:$skip { $PSItem.Configuration.DefaultBackupCompression.ConfigValue -eq 1 | Should -Be $psitem.ConfigValues.DefaultBackupCompression -Because 'This is the setting you have chosen the default backup compression' } } } Describe "Default File Path" -Tag DefaultFilePath, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.DefaultFilePath' }).Value Context "Checking Default Data File Path on <_.Name>" { It "Default Data File Path should not be on the C Drive on <_.Name>" -Skip:$skip { $PSItem.Settings.DefaultFile.substring(0, 1) | Should -Not -Be "C" -Because 'Default Data file path should not be your C:\ drive' } It "Default Log File Path should not be on the C Drive on <_.Name>" -Skip:$skip { $PSItem.Settings.DefaultLog.substring(0, 1) | Should -Not -Be "C" -Because 'Default Log file path should not be your C:\ drive' } } } Describe "Default Trace" -Tag DefaultTrace, CIS, Low, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.defaulttrace' }).Value Context "Checking Default Trace on <_.Name>" { It "The Default Trace should be enabled on <_.Name>" -Skip:$skip { $PSItem.Configuration.DefaultTraceEnabled.ConfigValue | Should -Be 1 -Because "We expected the Default Trace to be enabled" } } } Describe "Error Log Entries" -Tag ErrorLog, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.errorlogentries' }).Value Context "Checking error log on <_.Name>" { It "Error log should be free of error severities 17-24 within the window of <_.ErrorLogEntries.logWindow> days on <_.Name>" -Skip:$Skip { $PSItem.ErrorLogEntries.Count | Should -Be 0 -Because "these severities indicate serious problems" } } } Describe "Error Log Count" -Tag ErrorLogCount, CIS, Low, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.ErrorLogCount' }).Value Context "Checking error log count on <_.Name>" { It "Error log count should be greater or equal to <_.ConfigValues.errorLogCount> on <_.Name>" -Skip:$skip { $psitem.NumberOfLogFiles | Should -BeGreaterOrEqual $psitem.ConfigValues.errorLogCount -Because "We expect to have at least $($psitem.ConfigValues.errorLogCount) number of error log files" } } } Describe "Hide Instance" -Tag HideInstance, Security, CIS, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.security.hideinstance' }).Value Context "Checking the Hide an Instance of SQL Server Database Engine property on <_.Name>" { It "The Hide an Instance of SQL Server Database Engine property on SQL Server instance <_.Name>" -Skip:$skip { # We don't make this -BeTrue because the possible results are $true/$false/'Could not connect' $psitem.HideInstance.Result | Should -Be $true -Because "We expected the hide instance property to be set to $true" } } } Describe "Instance Connection" -Tag InstanceConnection, Connectivity, High, Instance -ForEach $InstancesToTest { BeforeAll { $skipall = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.connection' }).Value $skipremote = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.connection.remoting' }).Value $skipping = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.connection.ping' }).Value $skipauth = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.connection.auth' }).Value $authscheme = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.connection.authscheme' }).Value } BeforeDiscovery { $skipall = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.connection' }).Value $skipremote = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.connection.remoting' }).Value $skipping = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.connection.ping' }).Value $skipauth = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.connection.auth' }).Value $authscheme = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.connection.authscheme' }).Value } Context "Checking Instance Connection on on <_.Name>" -Skip:$skipall { It "connects successfully to <_.Name>" -Skip:$skipall { $PsItem.InstanceConnection.Connect | Should -BeTrue -Because "We expect the instance to be connectable" } It "auth scheme should be $authscheme on <_.Name>" -Skip:$skipauth { $PsItem.InstanceConnection.AuthScheme | Should -Be $authscheme -Because "We expect the auth scheme to be $authscheme" } It "We should be able to ping host <_.Name>" -Skip:$skipping { $PsItem.InstanceConnection.Ping | Should -Be 'Success' -Because "We expect the instance to be pingable" } It "We should be able to remote onto <_.Name>" -Skip:$skipremote { $PsItem.InstanceConnection.Remote | Should -BeTrue -Because "We expect the instance to be remotely connectable" } } } Describe "Latest Build" -Tag LatestBuild, Security, CIS, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.latestbuild' }).Value Context "Testing Latest Build on <_.Name>" { It "The Latest Build of SQL should be installed on <_.Name>" -Skip:$skip { $psitem.LatestBuild.Compliant | Should -BeTrue -Because "being patched to the latest version is important" } } } Describe "Linked Servers" -Tag LinkedServerConnection, Connectivity, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.linkedserverconnection' }).Value Context "Testing Linked Server Connection on <_.Name>" { It "should be able to connect to <_.LinkedServerName> for Linked Server <_.RemoteServer> on <_.InstanceName>" -Skip:$skip -ForEach @($Psitem.LinkedServerResults) { $psitem.Connectivity | Should -BeTrue -Because "Linked server connection should be successful but the result was $($Psitem.Result)" } } } Describe "Failed Login Auditing" -Tag LoginAuditFailed, Security, CIS, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.security.loginauditlevelfailed' }).Value Context "Testing if failed login auditing is in place on <_.Name>" { It "The failed login auditing should be set on <_.Name>" -Skip:$skip { $psitem.Settings.AuditLevel | Should -BeIn @("Failure", "All") -Because "We expected the audit level to be set to capture failed logins" } } } Describe "Successful Login Auditing" -Tag LoginAuditSuccessful, Security, CIS, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.security.loginauditlevelsuccessful' }).Value Context "Testing if successful and failed login auditing is in place on <_.Name>" { It "The successful and failed auditing should be set on <_.Name>" -Skip:$skip { $psitem.Settings.AuditLevel | Should -Be "All" -Because "We expected the audit level to be set to capture all logins (successful and failed)" } } } Describe "Login Check Policy" -Tag LoginCheckPolicy, Security, CIS, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.security.LoginCheckPolicy' }).Value Context "Testing if the CHECK_POLICY is enabled on all logins on <_.Name>" { It "All logins should have the CHECK_POLICY option set to ON on <_.Name>" -Skip:$skip { ($psitem.logins | Where-Object { $_.LoginType -eq 'SqlLogin' -and $_.PasswordPolicyEnforced -eq $false -and $_.IsDisabled -eq $false }).Count | Should -Be 0 -Because "We expected the CHECK_POLICY for the all logins to be enabled" } } } Describe "Login Must Change" -Tag LoginMustChange, Security, CIS, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.security.LoginMustChange' }).Value Context "Testing if the new SQL logins that have not logged have to change their password when they log in on <_.Name>" { It "All new sql logins should have the have to change their password when they log in for the first time on <_.Name>" -Skip:$skip { $PsItem.LoginMustChangeCount | Should -Be 0 -Because "We expected the all the new sql logins to have to change the password on first login" } } } Describe "Login Password Expiration" -Tag LoginPasswordExpiration, Security, CIS, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.security.LoginPasswordExpiration' }).Value Context "Testing if the login password expiration is enabled for sql logins in the sysadmin role on <_.Name>" { It "All sql logins should have the password expiration option set to ON in the sysadmin role on <_.Name>" -Skip:$skip { $PsItem.LoginPasswordExpirationCount | Should -Be 0 -Because "We expected the password expiration policy to set on all sql logins in the sysadmin role" } } } Describe "Instance MaxDop" -Tag MaxDopInstance, MaxDop, Medium, Instance -ForEach ($InstancesToTest | Where-Object { $psitem.Name -notin $psitem.ConfigValues.ExcludeInstanceMaxDop }) { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.MaxDopInstance' }).Value Context "Testing Instance MaxDop Value on <_.Name>" { #if UseRecommended - check that the CurrentInstanceMaxDop property returned from Test-DbaMaxDop matches the the RecommendedMaxDop property It "Instance Level MaxDop setting should be correct on <_.Name>" -Skip:$Skip -ForEach ($Psitem | Where-Object { $psitem.ConfigValues.UseRecommendedMaxDop -eq $true }) { $psitem.MaxDopSettings.CurrentInstanceMaxDop | Should -Be $psitem.MaxDopSettings.RecommendedMaxDop -Because "We expect the MaxDop Setting to be the default recommended value $($psitem.MaxDopSettings.RecommendedMaxDop)" } #if not UseRecommended - check that the CurrentInstanceMaxDop property returned from Test-DbaMaxDop matches the MaxDopValue parameter It "Instance Level MaxDop setting should be correct on <_.Name>" -Skip:$Skip -ForEach($Psitem | Where-Object { $psitem.ConfigValues.UseRecommendedMaxDop -ne $true }) { $psitem.MaxDopSettings.CurrentInstanceMaxDop | Should -Be $psitem.ConfigValues.InstanceMaxDop -Because "We expect the MaxDop Setting to be the value you specified $($psitem.ConfigValues.InstanceMaxDop)" } } } Describe "Max Memory" -Tag MaxMemory, High, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.maxmemory' }).Value Context "Testing Max Memory on <_.Name>" { It "Max Memory setting should be correct on <_.Name>" -Skip:$skip { $Psitem.MaxMemory.MaxValue | Should -BeLessThan $Psitem.MaxMemory.RecommendedValue -Because 'You do not want to exhaust server memory' } } } Describe "SQL Memory Dumps" -Tag MemoryDump, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.memorydump' }).Value Context "Testing SQL Memory Dumps on <_.Name>" { It "There should be less than <_.MemoryDump.MaxDumps> since <_.MemoryDump.DumpDateCheckFrom> on <_.Name>" -Skip:$skip { $Psitem.MemoryDump.Result | Should -BeTrue -Because "We expected less than $($Psitem.MemoryDump.MaxDumps) dumps since $($PsItem.MemoryDump.DumpDateCheckFrom)but found $($Psitem.MemoryDump.DumpCount) . Memory dumps often suggest issues with the SQL Server instance" } } } Describe "Model Database Growth" -Tag ModelDbGrowth, Low, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.modeldbgrowth' }).Value Context "Testing model database growth setting is not default on <_.Name>" { It "Growth settings should not be percent for file <_.Name> on <_.Parent.Parent.Parent.Name>" -Skip:$skip -ForEach $PsItem.Databases['model'].FileGroups.Files { $psitem.GrowthType | Should -Not -Be 'Percent' -Because 'New databases use the model database as a template and percent growth can cause performance problems' } It "Growth settings should not be 1Mb for file <_.Name> on <_.Parent.Parent.Parent.Name>" -Skip:$skip -ForEach $PsItem.Databases['model'].FileGroups.Files { $psitem.Growth | Should -Not -Be 1024 -Because 'New databases use the model database as a template and growing for each Mb will have a performance impact' } It "Growth settings should not be percent for file <_.Name> on <_.Parent.Parent.Name>" -Skip:$skip -ForEach @($PsItem.Databases['model'].LogFiles) { $psitem.GrowthType | Should -Not -Be 'Percent' -Because 'New databases use the model database as a template and percent growth can cause performance problems' } It "Growth settings should not be 1Mb for file <_.Name> on <_.Parent.Parent.Name>" -Skip:$skip -ForEach @($PsItem.Databases['model'].LogFiles) { $psitem.Growth | Should -Not -Be 1024 -Because 'New databases use the model database as a template and growing for each Mb will have a performance impact' } } } Describe "Network Latency" -Tag NetworkLatency, Connectivity, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.networklatency' }).Value Context "Testing Network Latency on <_.Name>" { It "should have a network latency less than <_.NetworkLatency.Threshold> ms on <_.Name>" -Skip:$skip { $psitem.NetworkLatency.Latency | Should -BeLessThan $psitem.NetworkLatency.Threshold -Because "Network latency should be less than $($psitem.NetworkLatency.Threshold) ms" } } } Describe "OLE Automation" -Tag OLEAutomation, Security, CIS, Low, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.oleautomation' }).Value Context "Checking OLE Automation on <_.Name>" { It "OLE Automation is set to <_.ConfigValues.OLEAutomation> on <_.Name>" -Skip:$skip { $PSItem.Configuration.OleAutomationProceduresEnabled.ConfigValue -eq 1 | Should -Be $psitem.ConfigValues.OLEAutomation -Because 'OLE Automation can introduce additional security risks' } } } Describe "OLE Automation Procedures Disabled" -Tag OleAutomationProceduresDisabled, CIS, Low, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.oleautomationproceduresdisabled' }).Value Context "Checking OLE Automation Procedures on <_.Name>" { It "The OLE Automation Procedures should be disabled on <_.Name>" -Skip:$skip { $PSItem.Configuration.OleAutomationProceduresEnabled.ConfigValue | Should -Be 0 -Because "We expect the OLE Automation Procedures to be disabled" } } } Describe "Orphaned Files" -Tag OrphanedFile, Low, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.orphanedfile' }).Value Context "Testing Orphaned Files on <_.Name>" { It "should not have orphaned files on <_.Name>" -Skip:$skip { $Psitem.OrphanedFile.FileCount | Should -Be 0 -Because 'You dont want any orphaned files - Use Find-DbaOrphanedFile to locate them' } } } Describe "Remote Access Disabled" -Tag RemoteAccessDisabled, Security, CIS, Low, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.remoteaccessdisabled' }).Value Context "Checking Remote Access on <_.Name>" { It "Remote Access should be disabled on <_.Name>" -Skip:$skip { $PSItem.Configuration.RemoteAccess.ConfigValue | Should -Be 0 -Because "We expected Remote Access to be disabled" } } } Describe "SA Login Disabled" -Tag SaDisabled, DISA, CIS, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.security.sadisabled' }).Value Context "Checking that sa login has been disabled on <_.Name>" { It "sa login is disabled on <_.Name>" -Skip:$Skip { ($PsItem.Logins | Where-Object ID -EQ 1).IsDisabled | Should -Be $true -Because "We expected the original sa login to be disabled" } } } Describe "Login SA cannot exist" -Tag SaExist, CIS, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.security.saexist' }).Value Context "Checking that a login named sa does not exist on <_.Name>" { It "sa login does not exist on <_.Name>" -Skip:$Skip { $PsItem.Logins['sa'].Count | Should -Be 0 -Because "We expected no login to exist with the name sa" } } } Describe "Public Role Permissions" -Tag PublicPermission, PublicRolePermission, Security, CIS, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.security.PublicPermission' }).Value Context "Testing if the public role permissions don't have permissions on <_.Name>" { It "All permissions should be set to CIS standards on the public role on <_.Name>" -Skip:$skip { $PsItem.PublicRolePermissions | Should -Be 0 -Because "We expected the public role to have no permissions for CIS compliance." } } } Describe "SA Login Renamed" -Tag SaRenamed, DISA, CIS, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.SaRenamed' }).Value Context "Checking that sa login has been renamed on <_.Name>" { It "sa login has been renamed on <_.Name>" -Skip:$Skip { ($PsItem.Logins.Name) | Should -Not -BeIn 'sa' -Because "Renaming the sa account is a requirement" } } } Describe "Scan For Startup Procedures" -Tag ScanForStartupProceduresDisabled, Security, CIS, Low, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.scanforstartupproceduresdisabled' }).Value Context "Checking Scan For Startup Procedures on <_.Name>" { It "Scan For Startup Procedures is set to <_.ConfigValues.scanforstartupproceduresdisabled> on <_.Name>" -Skip:$skip { $PSItem.Configuration.ScanForStartupProcedures.ConfigValue -eq 0 | Should -Be $PSItem.ConfigValues.scanforstartupproceduresdisabled -Because "We expected the Cross DB Ownership Chaining to be disabled" } } } Describe "SQL and Windows names match" -Tag ServerNameMatch, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.servernamematch' }).Value Context "Testing SQL and Windows names match on <_.Name>" { It "should have matching names on <_.Name>" -Skip:$skip { $Psitem.ServerNameMatch.renamerequired | Should -BeFalse -Because "SQL and Windows names should match but configured name $($Psitem.ServerNameMatch.configuredServerName) does not match $($Psitem.ServerNameMatch.netName)" } } } Describe "SQL Engine Service" -Tag SqlEngineServiceAccount, ServiceAccount, High, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.sqlengineserviceaccount' }).Value Context "Testing SQL Engine Service on <_.Name>" -Skip:$skip { It "SQL Engine service account should be <_.State> on <_.InstanceName>" -ForEach $PsItem.SqlEngineServiceAccount { $PsItem.State | Should -Be $PsItem.ExpectedState -Because "We expected the SQL Engine service account to be $($PsItem.ExpectedState)" } It "SQL Engine service account should have a start mode of <_.ExpectedStartType> on instance <_.InstanceName>" -ForEach $PsItem.SqlEngineServiceAccount { $PsItem.StartType | Should -Be $PsItem.ExpectedStartType -Because $Psitem.because } } } Describe "SQL Mail XPs Disabled" -Tag SQLMailXPsDisabled, Security, CIS, Low, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.SQLMailXPsDisabled' }).Value Context "Checking SQL Mail XPs on <_.Name>" { It "SQL Mail XPs should be disabled on <_.Name>" -Skip:($skip -or $psitem.VersionMajor -gt 10) { $PSItem.Configuration.SqlMailXPsEnabled.ConfigValue | Should -Be 0 -Because "We expected Sql Mail XPs to be disabled" } } } Describe "Supported Build" -Tag SupportedBuild, DISA, High, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.SupportedBuild' }).Value Context "Checking that build is still supported by Microsoft for <_.Name>" -Skip:$skip { It "The build is not behind the latest build by more than <_.SupportedBuild.BuildBehind> for <_.Name>" { $psItem.SupportedBuild.Compliant | Should -BeTrue -Because "this build $($psItem.SupportedBuild.Build) should not be behind the required build" } It "The build is supported by Microsoft for <_.Name>" { $psItem.SupportedBuild.InsideMicrosoftSupport | Should -BeTrue -Because "this build $($psItem.SupportedBuild.Build) is now unsupported by Microsoft" } It "The build is supported by Microsoft within the warning window of <_.SupportedBuild.BuildWarning> months for <_.Name>" { $psItem.SupportedBuild.InsideBuildWarning | Should -BeTrue -Because "this build $($psItem.SupportedBuild.Build) will be unsupported by Microsoft on $($psItem.SupportedBuild.SupportedUntil) which is less than $($psItem.SupportedBuild.BuildWarning) months away" } } } Describe "Suspect Page Limit Nearing" -Tag SuspectPageLimit, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.suspectpagelimit' }).Value Context "Testing if the suspect_pages table is nearing the limit of 1000 rows on on <_.Name>" { It "The suspect_pages table in msdb shouldn't be nearing the limit of 1000 rows on on <_.Name>" -Skip:$skip { $PSItem.SuspectPageCountResult | Should -BeTrue -Because "The suspect_pages table in msdb shouldn't be nearing the limit of 1000 rows" } } } Describe "Trace Flags Expected" -Tag TraceFlagsExpected, TraceFlag, High, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.TraceFlagsExpected' }).Value Context "Testing Expected Trace Flags on <_.Name>" { It "Expected No Trace Flags to exist on <_.Name>" -Skip:$skip -ForEach ($Psitem | Where-Object { $null -eq $psitem.ConfigValues.TraceFlagsExpected }) { $PsItem.ExpectedTraceFlags.ActualTraceFlags.TraceFlag | Should -BeNullOrEmpty -Because "We expect that there will be no Trace Flags set on $($Psitem.Name) " } It "Expected Trace Flags <_.ExpectedTraceFlag> to exist on <_.InstanceName>" -Skip:$skip -ForEach ($PsItem.ExpectedTraceFlags | Where-Object { $psitem.ExpectedTraceFlag -ne 'null' }) { $PsItem.ActualTraceFlags.TraceFlag | Should -Contain $PsItem.ExpectedTraceFlag -Because "We expect that Trace Flag $($PsItem.ExpectedTraceFlag) will be set on $($Psitem.InstanceName) " } } } Describe "Trace Flags Not Expected" -Tag TraceFlagsNotExpected, TraceFlag, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.TraceFlagsNotExpected' }).Value Context "Testing Not Expected Trace Flags on <_.Name>" { It "Expected No Trace Flags except for <_.ConfigValues.TraceFlagsExpected> to exist on <_.Name>" -Skip:$skip -ForEach ($Psitem | Where-Object { $null -eq $psitem.ConfigValues.TraceFlagsNotExpected }) { $PsItem.NotExpectedTraceFlags.ActualTraceFlags.TraceFlag | Should -BeNullOrEmpty -Because "We expect that there will be no Trace Flags set on $($Psitem.Name) except for $($psitem.ConfigValues.ExpectedTraceFlag)" } It "Expected <_.NotExpectedTraceFlag> Trace Flag to not exist on <_.InstanceName>" -Skip:$skip -ForEach ($PsItem.NotExpectedTraceFlags | Where-Object { $psitem.NotExpectedTraceFlag -ne 'null' }) { $PsItem.ActualTraceFlags.TraceFlag | Should -Not -Contain $PsItem.NotExpectedTraceFlag -Because "We expect that Trace Flag $($PsItem.NotExpectedTraceFlag) will not be set on $($Psitem.InstanceName) except for $($psitem.ConfigValues.ExpectedTraceFlag)" } } } Describe "Two Digit Year Cutoff" -Tag TwoDigitYearCutoff, Low, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.TwoDigitYearCutoff' }).Value Context "Testing Two Digit Year Cutoff on <_.Name>" { It "Two Digit Year Cutoff is set to <_.ConfigValues.TwoDigitYearCutoff> on <_.Name>" -Skip:$skip { $PSItem.Configuration.TwoDigitYearCutoff.ConfigValue | Should -Be $psitem.ConfigValues.TwoDigitYearCutoff -Because 'This is the value that you have chosen for Two Digit Year Cutoff configuration' } } } Describe "sp_whoisactive is Installed" -Tag WhoIsActiveInstalled, Low, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.WhoIsActiveInstalled' }).Value Context "Testing WhoIsActive exists on <_.Name>" { It "WhoIsActive should exist on <_.ConfigValues.whoisactivedatabase> on <_.Name>" -Skip:$skip { $Psitem.ConfigValues.WhoIsActiveInstalled | Should -Be 1 -Because "The sp_WhoIsActive stored procedure should be installed in $($psitem.ConfigValues.whoisactivedatabase)" } } } Describe "XE Sessions that should Exist" -Tag XESessionExists, ExtendedEvent, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.XESessionExists' }).Value Context "Checking sessions on <_.Name>" { It "Session <_.SessionName> should exist on <_.Name>" -Skip:$skip -ForEach $PsItem.XeSessions.RequiredExists { $psitem.SessionName | Should -BeIn $PsItem.Sessions -Because "$($psitem.SessionName) session should exist on $($PsItem.Name)" } } } Describe "XE Sessions that should be running" -Tag XESessionRunning, ExtendedEvent, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.XESessionRunning' }).Value Context "Checking sessions on <_.Name>" { It "Session <_.SessionName> should be running on <_.Name>" -Skip:$skip -ForEach $PsItem.XeSessions.RequiredRunning { $psitem.SessionName | Should -BeIn $PsItem.Running -Because "$($psitem.SessionName) session should be running on $($PsItem.Name)" } } } Describe "XE Sessions That Are Allowed to Be Running" -Tag XESessionRunningAllowed, ExtendedEvent, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.XESessionRunningAllowed' }).Value Context "Checking running sessions allowed on <_.Name>" { It "Session <_.SessionName> is allowed to be running on <_.Name>" -Skip:$skip -ForEach $PsItem.XeSessions.RunningAllowed { $psitem.SessionName | Should -BeIn $PsItem.Allowed -Because "Only $($PsItem.Allowed) sessions are allowed to be running $($PsItem.Name)" } } } Describe "XE Sessions that should be Stopped" -Tag XESessionStopped, ExtendedEvent, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.XESessionStopped' }).Value Context "Checking sessions on <_.Name>" { It "Session <_.SessionName> should not be running on <_.Name>" -Skip:$skip -ForEach $PsItem.XeSessions.RequiredStopped { $psitem.SessionName | Should -Not -BeIn $PsItem.Running -Because "$($psitem.SessionName) session should be stopped on $($PsItem.Name)" } } } Describe "XP CmdShell" -Tag XpCmdShellDisabled, security, CIS, Medium, Instance -ForEach $InstancesToTest { $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.XpCmdShellDisabled' }).Value Context "Testing XP CmdShell on <_.Name>" { It "XpCmdShellDisabled is set to <_.ConfigValues.XpCmdShellDisabled> on <_.Name>" -Skip:$skip { $PSItem.Configuration.XpCmdShellEnabled.ConfigValue -eq 0 | Should -Be $psitem.ConfigValues.XpCmdShellDisabled -Because 'This is the value that you have chosen for XPXmdShellDisabled configuration' } } } <# Describe "TempDB Configuration" -Tags TempDbConfiguration, Medium, Instance -ForEach $InstancesToTest { Context "Testing TempDB Configuration on $psitem" -Skip:(($__dbcconfig | Where-Object { $_.Name It "should have TF1118 enabled on <_.Name>" -Skip:((($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.XESessionRunningAllowed' }).Value) -or ($InstanceSMO.VersionMajor -gt 12)) { $psitem.TempDBConfig.TF118EnabledCurrent | Should -Be $psitem.TempDBConfig.TF118EnabledRecommended -Because 'TF 1118 should be enabled' } It "should have <_.TempDBConfig.TempDBFilesRecommended> TempDB Files on <_.Name>" -Skip:(($__dbcconfig | Where-Object { $_.Name -eq 'skip.tempdbfileCount' }).Value) { $psitem.TempDBConfig.TempDBFilesCurrent | Should -Be $psitem.TempDBConfig.TempDBFilesRecommended -Because 'This is the recommended number of tempdb files for your server' } It "should not have TempDB Files autogrowth set to percent on $($TempDBTest[2].SqlInstance)" -Skip:(($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.XESessionRunningAllowed' }).Value) { $TempDBTest[2].CurrentSetting | Should -Be $TempDBTest[2].Recommended -Because 'Auto growth type should not be percent' } It "should not have TempDB Files on the C Drive on $($TempDBTest[3].SqlInstance)" -Skip:(($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.XESessionRunningAllowed' }).Value) { $TempDBTest[3].CurrentSetting | Should -Be $TempDBTest[3].Recommended -Because 'You do not want the tempdb files on the same drive as the operating system' } It "should not have TempDB Files with MaxSize Set on $($TempDBTest[4].SqlInstance)" -Skip:(($__dbcconfig | Where-Object { $_.Name -eq 'skip.instance.XESessionRunningAllowed' }).Value) { $TempDBTest[4].CurrentSetting | Should -Be $TempDBTest[4].Recommended -Because 'Tempdb files should be able to grow' } It "The data files should all be the same size on $($TempDBTest[0].SqlInstance)" { Assert-TempDBSize -Instance $Psitem } } } #> ================================================ FILE: source/checks/LogShipping.Tests.ps1 ================================================ $filename = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") Describe "Log Shipping Status Primary" -Tags LogShippingPrimary, $filename { @(Get-Instance).ForEach{ Context "Testing the primary databases on $psitem" { @(Test-DbaDbLogShipStatus -SqlInstance $psitem -Primary).ForEach{ It "Status should be OK for $($psitem.Database) on $($psitem.SqlInstance)" { $psitem.Status | Should -Be "All OK" -Because 'The Log shipping should be ok' } } } } } Describe "Log Shipping Status Secondary" -Tags LogShippingSecondary, $filename { @(Get-Instance).ForEach{ Context "Testing the secondary databases on $psitem" { @(Test-DbaDbLogShipStatus -SqlInstance $psitem -Secondary).ForEach{ It "Status should be OK for $($psitem.Database) on $($psitem.SqlInstance)" { $psitem.Status | Should -Be "All OK" -Because 'The Log shipping should be ok' } } } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU70DEQ6DkUsJwk88JvqH9bERA # Em+gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRWQsr97j61Cg5QyePfgdDuRbyT # BzANBgkqhkiG9w0BAQEFAASCAQBN2oSLUhBekR/5JOUG7Dgqz7DLelxOfxuh4ngs # pcqo8gTMYGI8U1e2LqH9JNMUUSzwz1t6+0Z9V/Dx5uu1MuN5K9bBWgEC2oeekq43 # k8AFyw7TYJNV6lrFaVC/jGFPByUko/3MIm/l9J1RZkXSbPmoTfJYoc/N0Paad/Rk # +PIjcfuDsDSVm0Cu6gzRR2dt9z/1llPEmXD8edxm4fwq8be1DpEcZKg8pKhi6opm # x6aDA9x/E3phqNK9DxYnRl+fQybRX+78QLli4544t5RC3jr1UatkKGVe7KBOU7ip # 8+mvhb4U09vnIG9m60tTLfyXwnbOKH/gBc3EbMAmgK2Wvk+x # SIG # End signature block ================================================ FILE: source/checks/MaintenanceSolution.Tests.ps1 ================================================ $filename = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") Describe "Ola maintenance solution installed" -Tags OlaInstalled, $filename { $OlaSPs = @('CommandExecute', 'DatabaseBackup', 'DatabaseIntegrityCheck', 'IndexOptimize') $oladb = Get-DbcConfigValue policy.ola.database @(Get-Instance).ForEach{ $db = Get-DbaDatabase -SqlInstance $psitem -Database $oladb Context "Checking the CommandLog table on $psitem" { It "The CommandLog table exists in $oladb on $psitem" { @($db.tables | Where-Object name -eq "CommandLog").Count | Should -Be 1 -Because 'The command log table is required' } } Context "Checking the Ola Stored Procedures on $psitem" { It "The stored procedures exists in $oladb on $psitem" { ($db.StoredProcedures | Where-Object { $psitem.schema -eq 'dbo' -and $psitem.name -in $OlaSPs } | Measure-Object).Count | Should -Be $OlaSPs.Count -Because 'The stored procedures are required for Olas jobs to run' } } } } $SysFullJobName = Get-DbcConfigValue ola.JobName.SystemFull $UserFullJobName = Get-DbcConfigValue ola.JobName.UserFull $UserDiffJobName = Get-DbcConfigValue ola.JobName.UserDiff $UserLogJobName = Get-DbcConfigValue ola.JobName.UserLog $CommandLogJobName = Get-DbcConfigValue ola.JobName.CommandLogCleanup $SysIntegrityJobName = Get-DbcConfigValue ola.JobName.SystemIntegrity $UserIntegrityJobName = Get-DbcConfigValue ola.JobName.UserIntegrity $UserIndexJobName = Get-DbcConfigValue ola.JobName.UserIndex $OutputFileJobName = Get-DbcConfigValue ola.JobName.OutputFileCleanup $DeleteBackupJobName = Get-DbcConfigValue ola.JobName.DeleteBackupHistory $PurgeBackupJobName = Get-DbcConfigValue ola.JobName.PurgeBackupHistory Describe "Ola - $SysFullJobName" -Tags SystemFull, OlaJobs, $filename { $Enabled = Get-DbcConfigValue policy.ola.SystemFullenabled $Scheduled = Get-DbcConfigValue policy.ola.SystemFullscheduled $Retention = Get-DbcConfigValue policy.ola.SystemFullretention @(Get-Instance).ForEach{ $job = Get-DbaAgentJob -SqlInstance $psitem -Job $SysFullJobName Context "Is job enabled on $psitem" { It "$SysFullJobName should be enabled - $Enabled on $psitem" { $job.IsEnabled | Should -Be $Enabled -Because "If the $SysFullJobName job is not enabled it will not run" } } Context "Is job scheduled on $psitem" { It "$SysFullJobName should be scheduled - $Scheduled on $psitem" { $job.HasSchedule | Should -Be $Scheduled -Because "If the $SysFullJobName job is not scheduled it will not run" } It "$SysFullJobName schedules should be enabled - $Scheduled on $psitem" { $results = ($job.JobSchedules | Where-Object IsEnabled | Measure-Object).Count -gt 0 $results | Should -BeGreaterThan 0 -Because "If the schedule is not enabled the $SysFullJobName jobs will not run" } } if ($Retention) { Context "Checking the backup retention on $psitem" { $jobsteps = $job.JobSteps | Where-Object { $_.SubSystem -eq "CmdExec" -or $_.SubSystem -eq "TransactSql" } if ($jobsteps) { $results = $jobsteps.Command.Split("@") | Where-Object { $_ -match "CleanupTime" } } else { $results = $null } It "Is the backup retention set to at least $Retention hours on $psitem" { if ($results) { [int]$hours = $results.split("=")[1].split(",").split(" ")[1].replace('NULL','') } $hours | Should -BeGreaterOrEqual $Retention -Because "The backup retention for $SysFullJobName needs to be correct" } } } } } Describe "Ola - $UserFullJobName" -Tags UserFull, OlaJobs, $filename { @(Get-Instance).ForEach{ $job = Get-DbaAgentJob -SqlInstance $psitem -Job $UserFullJobName $Enabled = Get-DbcConfigValue policy.ola.UserFullenabled $Scheduled = Get-DbcConfigValue policy.ola.UserFullscheduled $Retention = Get-DbcConfigValue policy.ola.UserFullretention Context "Is job enabled on $psitem" { It "$UserFullJobName should be enabled - $Enabled on $psitem" { $job.IsEnabled | Should -Be $Enabled -Because "If the $UserFullJobName job is not enabled it will not run" } } Context "Is job scheduled on $psitem" { It "$UserFullJobName should be scheduled - $Scheduled on $psitem" { $job.HasSchedule | Should -Be $Scheduled -Because "If the $UserFullJobName job is not scheduled it will not run" } It "$($UserFullJobName) schedules should be enabled - $Scheduled on $psitem" { $results = ($job.JobSchedules | Where-Object IsEnabled | Measure-Object).Count -gt 0 $results | Should -BeGreaterThan 0 -Because "If the schedule is not enabled the $UserFullJobName job will not run" } } if ($Retention) { Context "Checking the backup retention on $psitem" { $jobsteps = $job.JobSteps | Where-Object { $_.SubSystem -eq "CmdExec" -or $_.SubSystem -eq "TransactSql" } if ($jobsteps) { $results = $jobsteps.Command.Split("@") | Where-Object { $_ -match "CleanupTime" } } else { $results = $null } It "Is the backup retention set to at least $Retention hours on $psitem" { if ($results) { [int]$hours = $results.split("=")[1].split(",").split(" ")[1].replace('NULL','') } $hours | Should -BeGreaterOrEqual $Retention -Because "The backup retention for $UserFullJobName needs to be correct" } } } } } Describe "Ola - $UserDiffJobName" -Tags UserDiff, OlaJobs, $filename { @(Get-Instance).ForEach{ $job = Get-DbaAgentJob -SqlInstance $psitem -Job $UserDiffJobName $Enabled = Get-DbcConfigValue policy.ola.UserDiffenabled $Scheduled = Get-DbcConfigValue policy.ola.UserDiffscheduled $Retention = Get-DbcConfigValue policy.ola.UserDiffretention Context "Is job enabled on $psitem" { It "$UserDiffJobName should be enabled - $Enabled on $psitem" { $job.IsEnabled | Should -Be $Enabled -Because "If the $UserDiffJobName job is not enabled it will not run" } } Context "Is job scheduled on $psitem" { It "$UserDiffJobName should be scheduled - $Scheduled on $psitem" { $job.HasSchedule | Should -Be $Scheduled -Because "If the $UserDiffJobName job is not scheduled it will not run" } It "$($UserDiffJobName) schedules should be enabled - $Scheduled on $psitem" { $results = ($job.JobSchedules | Where-Object IsEnabled | Measure-Object).Count -gt 0 $results | Should -BeGreaterThan 0 -Because "If the schedule is not enabled the $UserDiffJobName job will not run" } } if ($Retention) { Context "Checking the backup retention on $psitem" { $jobsteps = $job.JobSteps | Where-Object { $_.SubSystem -eq "CmdExec" -or $_.SubSystem -eq "TransactSql" } if ($jobsteps) { $results = $jobsteps.Command.Split("@") | Where-Object { $_ -match "CleanupTime" } } else { $results = $null } It "Is the backup retention set to at least $Retention hours on $psitem" { if ($results) { [int]$hours = $results.split("=")[1].split(",").split(" ")[1].replace('NULL','') } $hours | Should -BeGreaterOrEqual $Retention -Because "The backup retention for $UserDiffJobName needs to be correct" } } } } } Describe "Ola - $UserLogJobName" -Tags UserLog, OlaJobs, $filename { @(Get-Instance).ForEach{ $job = Get-DbaAgentJob -SqlInstance $psitem -Job $UserLogJobName $Enabled = Get-DbcConfigValue policy.ola.UserLogenabled $Scheduled = Get-DbcConfigValue policy.ola.UserLogscheduled $Retention = Get-DbcConfigValue policy.ola.UserLogretention Context "Is job enabled on $psitem" { It "$UserLogJobName should be enabled - $Enabled on $psitem" { $job.IsEnabled | Should -Be $Enabled -Because "If the $UserLogJobName job is not enabled it will not run" } } Context "Is job scheduled on $psitem" { It "$UserLogJobName should be scheduled - $Scheduled on $psitem" { $job.HasSchedule | Should -Be $Scheduled -Because "If the $UserLogJobName job is not scheduled it will not run" } It "$($UserLogJobName) schedules should be enabled - $Scheduled on $psitem" { $results = ($job.JobSchedules | Where-Object IsEnabled | Measure-Object).Count -gt 0 $results | Should -BeGreaterThan 0 -Because "If the schedule is not enabled the $UserLogJobName job will not run" } } if ($Retention) { Context "Checking the backup retention on $psitem" { $jobsteps = $job.JobSteps | Where-Object { $_.SubSystem -eq "CmdExec" -or $_.SubSystem -eq "TransactSql" } if ($jobsteps) { $results = $jobsteps.Command.Split("@") | Where-Object { $_ -match "CleanupTime" } } else { $results = $null } It "Is the backup retention set to at least $Retention hours on $psitem" { if ($results) { [int]$hours = $results.split("=")[1].split(",").split(" ")[1].replace('NULL','') } $hours | Should -BeGreaterOrEqual $Retention -Because "The backup retention for $UserLogJobName needs to be correct" } } } } } Describe "Ola - $CommandLogJobName" -Tags CommandLog, OlaJobs, $filename { @(Get-Instance).ForEach{ $job = Get-DbaAgentJob -SqlInstance $psitem -Job $CommandLogJobName $Enabled = Get-DbcConfigValue policy.ola.CommandLogenabled $Scheduled = Get-DbcConfigValue policy.ola.CommandLogscheduled $CleanUp = Get-DbcConfigValue policy.ola.CommandLogCleanUp Context "Is job enabled on $psitem" { It "$CommandLogJobName should be enabled - $Enabled on $psitem" { $job.IsEnabled | Should -Be $Enabled -Because "If the $CommandLogJobName job is not enabled it will not run" } } Context "Is job scheduled on $psitem" { It "$CommandLogJobName should be scheduled - $Scheduled on $psitem" { $job.HasSchedule | Should -Be $Scheduled -Because "If the $CommandLogJobName job is not scheduled it will not run" } It "$($CommandLogJobName) schedules should be enabled - $Scheduled on $psitem" { $results = ($job.JobSchedules | Where-Object IsEnabled | Measure-Object).Count -gt 0 $results | Should -BeGreaterThan 0 -Because "If the schedule is not enabled the $CommandLogJobName job will not run" } } Context "Checking the Command Log Cleanup Time on $psitem" { $jobsteps = $job.JobSteps | Where-Object { $_.SubSystem -eq "CmdExec" -or $_.SubSystem -eq "TransactSql" } $days = [regex]::matches($jobsteps.Command, "dd,-(\d*)").groups[1].value It "Is the Clean up time set to at least $CleanUp Days on $psitem" { $days | Should -BeGreaterOrEqual $CleanUp -Because "The Clean up time for $CommandLogJobName needs to be correct" } } } } Describe "Ola - $SysIntegrityJobName" -Tags SystemIntegrityCheck, OlaJobs, $filename { @(Get-Instance).ForEach{ $job = Get-DbaAgentJob -SqlInstance $psitem -Job $SysIntegrityJobName $Enabled = Get-DbcConfigValue policy.ola.SystemIntegrityCheckenabled $Scheduled = Get-DbcConfigValue policy.ola.SystemIntegrityCheckscheduled Context "Is job enabled on $psitem" { It "$SysIntegrityJobName should be enabled - $Enabled on $psitem" { $job.IsEnabled | Should -Be $Enabled -Because "If the $SysIntegrityJobName job is not enabled it will not run" } } Context "Is job scheduled on $psitem" { It "$SysIntegrityJobName should be scheduled - $Scheduled on $psitem" { $job.HasSchedule | Should -Be $Scheduled -Because "If the $SysIntegrityJobName job is not scheduled it will not run" } It "$($SysIntegrityJobName) schedules should be enabled - $Scheduled on $psitem" { $results = ($job.JobSchedules | Where-Object IsEnabled | Measure-Object).Count -gt 0 $results | Should -BeGreaterThan 0 -Because "If the schedule is not enabled the $SysIntegrityJobName job will not run" } } } } Describe "Ola - $UserIntegrityJobName" -Tags UserIntegrityCheck, OlaJobs, $filename { @(Get-Instance).ForEach{ $job = Get-DbaAgentJob -SqlInstance $psitem -Job $UserIntegrityJobName $Enabled = Get-DbcConfigValue policy.ola.UserIntegrityCheckenabled $Scheduled = Get-DbcConfigValue policy.ola.UserIntegrityCheckscheduled Context "Is job enabled on $psitem" { It "$UserIntegrityJobName should be enabled - $Enabled on $psitem" { $job.IsEnabled | Should -Be $Enabled -Because "If the $UserIntegrityJobName job is not enabled it will not run" } } Context "Is job scheduled on $psitem" { It "$UserIntegrityJobName should be scheduled - $Scheduled on $psitem" { $job.HasSchedule | Should -Be $Scheduled -Because "If the $UserIntegrityJobName job is not scheduled it will not run" } It "$($UserIntegrityJobName) schedules should be enabled - $Scheduled on $psitem" { $results = ($job.JobSchedules | Where-Object IsEnabled | Measure-Object).Count -gt 0 $results | Should -BeGreaterThan 0 -Because "If the schedule is not enabled the $UserIntegrityJobName job will not run" } } } } Describe "Ola - $UserIndexJobName" -Tags UserIndexOptimize, OlaJobs, $filename { @(Get-Instance).ForEach{ $job = Get-DbaAgentJob -SqlInstance $psitem -Job $UserIndexJobName $Enabled = Get-DbcConfigValue policy.ola.UserIndexOptimizeenabled $Scheduled = Get-DbcConfigValue policy.ola.UserIndexOptimizescheduled Context "Is job enabled on $psitem" { It "$UserIndexJobName should be enabled - $Enabled on $psitem" { $job.IsEnabled | Should -Be $Enabled -Because "If the $UserIndexJobName job is not enabled it will not run" } } Context "Is job scheduled on $psitem" { It "$UserIndexJobName should be scheduled - $Scheduled on $psitem" { $job.HasSchedule | Should -Be $Scheduled -Because "If the $UserIndexJobName job is not scheduled it will not run" } It "$($UserIndexJobName) schedules should be enabled - $Scheduled on $psitem" { $results = ($job.JobSchedules | Where-Object IsEnabled | Measure-Object).Count -gt 0 $results | Should -BeGreaterThan 0 -Because "If the schedule is not enabled the $UserIndexJobName job will not run" } } } } Describe "Ola - $OutputFileJobName" -Tags OutputFileCleanup, OlaJobs, $filename { @(Get-Instance).ForEach{ $job = Get-DbaAgentJob -SqlInstance $psitem -Job $OutputFileJobName $Enabled = Get-DbcConfigValue policy.ola.OutputFileCleanupenabled $Scheduled = Get-DbcConfigValue policy.ola.OutputFileCleanupscheduled $CleanUp = Get-DbcConfigValue policy.ola.OutputFileCleanUp Context "Is job enabled on $psitem" { It "$OutputFileJobName should be enabled - $Enabled on $psitem" { $job.IsEnabled | Should -Be $Enabled -Because "If the $OutputFileJobName job is not enabled it will not run" } } Context "Is job scheduled on $psitem" { It "$OutputFileJobName should be scheduled - $Scheduled on $psitem" { $job.HasSchedule | Should -Be $Scheduled -Because "If the $OutputFileJobName job is not scheduled it will not run" } It "$($OutputFileJobName) schedules should be enabled - $Scheduled on $psitem" { $results = ($job.JobSchedules | Where-Object IsEnabled | Measure-Object).Count -gt 0 $results | Should -BeGreaterThan 0 -Because "If the schedule is not enabled the $OutputFileJobName job will not run" } } Context "Checking the Output File Job Cleanup Time on $psitem" { $jobsteps = $job.JobSteps | Where-Object { $_.SubSystem -eq "CmdExec" -or $_.SubSystem -eq "TransactSql" } $jobsteps.Command -match "\/d\s-(\d\d)" If($Matches.Count -gt 0){ $days = $Matches[1] } else{ $days = 0 } It "Is the Clean up time set to at least $CleanUp Days on $psitem" { $days | Should -BeGreaterOrEqual $CleanUp -Because "The Clean up time for $OutputFileJobName needs to be correct" } } } } Describe "Ola - $DeleteBackupJobName" -Tags DeleteBackupHistory, OlaJobs, $filename { @(Get-Instance).ForEach{ $job = Get-DbaAgentJob -SqlInstance $psitem -Job $DeleteBackupJobName $Enabled = Get-DbcConfigValue policy.ola.DeleteBackupHistoryenabled $Scheduled = Get-DbcConfigValue policy.ola.DeleteBackupHistoryscheduled $CleanUp = Get-DbcConfigValue policy.ola.DeleteBackupHistoryCleanUp Context "Is job enabled on $psitem" { It "$DeleteBackupJobName should be enabled - $Enabled on $psitem" { $job.IsEnabled | Should -Be $Enabled -Because "If the $DeleteBackupJobName job is not enabled it will not run" } } Context "Is job scheduled on $psitem" { It "$DeleteBackupJobName should be scheduled - $Scheduled on $psitem" { $job.HasSchedule | Should -Be $Scheduled -Because "If the $DeleteBackupJobName job is not scheduled it will not run" } It "$($DeleteBackupJobName) schedules should be enabled - $Scheduled on $psitem" { $results = ($job.JobSchedules | Where-Object IsEnabled | Measure-Object).Count -gt 0 $results | Should -BeGreaterThan 0 -Because "If the schedule is not enabled the $DeleteBackupJobName job will not run" } } Context "Checking the Delete Backup History Cleanup Time on $psitem" { $jobsteps = $job.JobSteps | Where-Object { $_.SubSystem -eq "CmdExec" -or $_.SubSystem -eq "TransactSql" } $days = [regex]::matches($jobsteps.Command, "dd,-(\d*)").groups[1].value It "Is the Clean up time set to at least $CleanUp Days on $psitem" { $days | Should -BeGreaterOrEqual $CleanUp -Because "The Clean up time for $DeleteBackupJobName needs to be correct" } } } } Describe "Ola - $PurgeBackupJobName" -Tags PurgeJobHistory, OlaJobs, $filename { @(Get-Instance).ForEach{ $job = Get-DbaAgentJob -SqlInstance $psitem -Job $PurgeBackupJobName $Enabled = Get-DbcConfigValue policy.ola.PurgeJobHistoryenabled $Scheduled = Get-DbcConfigValue policy.ola.PurgeJobHistoryscheduled $CleanUp = Get-DbcConfigValue policy.ola.PurgeJobHistoryCleanUp Context "Is job enabled on $psitem" { It "$PurgeBackupJobName should be enabled - $Enabled on $psitem" { $job.IsEnabled | Should -Be $Enabled -Because "If the $PurgeBackupJobName job is not enabled it will not run" } } Context "Is job scheduled on $psitem" { It "$PurgeBackupJobName should be scheduled - $Scheduled on $psitem" { $job.HasSchedule | Should -Be $Scheduled -Because "If the $PurgeBackupJobName job is not scheduled it will not run" } It "$($PurgeBackupJobName) schedules should be enabled - $Scheduled on $psitem" { $results = ($job.JobSchedules | Where-Object IsEnabled | Measure-Object).Count -gt 0 $results | Should -BeGreaterThan 0 -Because "If the schedule is not enabled the $PurgeBackupJobName job will not run" } } Context "Checking the Purge Backup History Cleanup Time on $psitem" { $jobsteps = $job.JobSteps | Where-Object { $_.SubSystem -eq "CmdExec" -or $_.SubSystem -eq "TransactSql" } $days = [regex]::matches($jobsteps.Command, "dd,-(\d*)").groups[1].value It "Is the Clean up time set to at least $CleanUp Days on $psitem" { $days | Should -BeGreaterOrEqual $CleanUp -Because "The Clean up time for $PurgeBackupJobName needs to be correct" } } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUS1JQPHv5yCEsWxq/oekgpzof # efigggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQrwbrUliQ9N0KAabkjhkVyFJXK # gDANBgkqhkiG9w0BAQEFAASCAQAV13wSIR24gk+gKS/qcNNSK+ugz0pzotNya4sj # KFZ6T6AzliNxFJD7EVIBNtsjlMNBWVDIrALhZxOR6VGPxlvFhCXJTY2kuE4zfBTW # epbVpbBK8d2Z8NqhSM5Cnh8pwgABYygRIVYGby06XIXDf36Jd0wTk74uOqajOA/S # 5XkwxNaeoeV58gEHOquTOpXWsf1JFZBnKI8pn4imT1i/meGdvo5wnaI+uIY8N2m6 # ZgDjrO0SN5cIMQE8jIaih/LjqplJkL/YB3h9dxLuDm37rSeSv/UX5ltM1cXmxIXk # mqUCh2+zTsZ8gOk5bkbuihdKpERqfF/5E8ZMw5mFMynDO+Yz # SIG # End signature block ================================================ FILE: source/checks/Server.Tests.ps1 ================================================ $filename = $MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") . $PSScriptRoot/../internal/assertions/Server.Assertions.ps1 # follow the guidance in Instance.Assertions to add new checks $Tags = Get-CheckInformation -Check $Check -Group Server -AllChecks $AllChecks -ExcludeCheck $ChecksToExclude if($IsLinux){ Write-PSFMessage "We cannot run any of the Server tests from linux at the moment" -Level Warning Return } @(Get-ComputerName).ForEach{ $AllServerInfo = Get-AllServerInfo -ComputerName $Psitem -Tags $Tags Describe "Server Power Plan Configuration" -Tags PowerPlan, Medium, $filename { Context "Testing Server Power Plan Configuration on $psitem" { It "PowerPlan is High Performance on $psitem" { Assert-PowerPlan -AllServerInfo $AllServerInfo } } } Describe "SPNs" -Tags SPN, $filename { Context "Testing SPNs on $psitem" { $computername = $psitem @($AllServerInfo.SPNs).ForEach{ It "There should be an SPN $($psitem.RequiredSPN) for $($psitem.InstanceServiceAccount) on $computername" { Assert-SPN -SPN $psitem } } } } Describe "Disk Space" -Tags DiskCapacity, Storage, DISA, Varied, $filename { $free = Get-DbcConfigValue policy.diskspace.percentfree Context "Testing Disk Space on $psitem" { @($AllServerInfo.DiskSpace).ForEach{ It "$($psitem.Name) with $($psitem.PercentFree)% free should be at least $free% free on $($psitem.ComputerName)" { Assert-DiskSpace -Disk $psitem } } } } Describe "Ping Computer" -Tags PingComputer, Varied, $filename { $pingmsmax = Get-DbcConfigValue policy.connection.pingmaxms $pingcount = Get-DbcConfigValue policy.connection.pingcount $skipping = Get-DbcConfigValue skip.connection.ping Context "Testing Ping to $psitem" { It -skip:$skipping "Should have pinged $pingcount times for $psitem" { Assert-Ping -AllServerInfo $AllServerInfo -Type Ping } It -skip:$skipping "Average response time (ms) should Be less than $pingmsmax (ms) for $psitem" { Assert-Ping -AllServerInfo $AllServerInfo -Type Average } } } Describe "CPUPrioritisation" -Tags CPUPrioritisation, Medium, $filename { $exclude = Get-DbcConfigValue policy.server.cpuprioritisation Context "Testing CPU Prioritisation on $psitem" { It "Should have the registry key set correctly for background CPU Prioritisation on $psitem" -Skip:$exclude { Assert-CPUPrioritisation -ComputerName $psitem } } } Describe "Disk Allocation Unit" -Tags DiskAllocationUnit, Medium, $filename { if($IsCoreCLR){ Context "Testing disk allocation unit on $psitem" { It "Can't run this check on Core on $psitem" -Skip { $true | Should -BeTrue } } } else { Context "Testing disk allocation unit on $psitem" { $computerName = $psitem $excludedisks = Get-DbcConfigValue policy.server.excludeDiskAllocationUnit @($AllServerInfo.DiskAllocation).Where{$psitem.IsSqlDisk -eq $true}.ForEach{ if($Psitem.Name -in $excludedisks){ $exclude = $true } else { $exclude = $false } It "$($Psitem.Name) Should be set to 64kb on $computerName" -Skip:$exclude { Assert-DiskAllocationUnit -DiskAllocationObject $Psitem } } } } } Describe "Non Standard Port" -Tags NonStandardPort, Medium, CIS, $filename { $skip = Get-DbcConfigValue skip.security.nonstandardport Context "Checking SQL Server ports on $psitem" { It "No SQL Server Instances should be configured with port 1433 on $psitem" -skip:$skip { Assert-NonStandardPort -AllServerInfo $AllServerInfo } } } Describe "Server Protocols" -Tags ServerProtocol, Medium, CIS, $filename { $skip = Get-DbcConfigValue skip.security.serverprotocol Context "Checking SQL Server protocols on $psitem" { It "All SQL Server Instances should be configured to run only TCP/IP protocol on $psitem" -skip:$skip { Assert-ServerProtocol -AllServerInfo $AllServerInfo } } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU4VzG8Um6bNQuBBJDVJTixLoH # c6GgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQLrVHq2xWVeT/Yis0CW7DFOnrz # 3TANBgkqhkiG9w0BAQEFAASCAQBa4ar9/SNGWCbUjfixhB09tP8BgiYT+cVmfouo # VqnGmvLgY4FyzP9fDdu8lAFqGDXWEvX1WLHQ8Er0YQwAnqLzAkZ574G/JLkm3AYe # Kzmz45DiYWkXDwAUIc9blMY1f3y99sRYbY2ZCAyDnIdzb5hS2iL0jwLO/tI/3exn # sDGLRhdApejAphzoLOLiG4lgCLXQgXcebiQ9riqgpna/i4YhR5eeNhHirWRkY0WJ # baiw/YXViFXMC7YpNQrZsPntebw929RtRmwkCGmdwggDgSsBUDYUHuZbrpn5Vs4r # ifMN8tXG6d2PoD2g0ApF4YHEZGS/nGGolgBzEE/GkPW4z+RQ # SIG # End signature block ================================================ FILE: source/dbachecks.psm1 ================================================ $script:ModuleRoot = $PSScriptRoot $VerbosePreference = "SilentlyContinue" function Import-ModuleFile { [CmdletBinding()] Param ( [string] $Path ) if ($doDotSource) { . $Path } else { try { $ExecutionContext.InvokeCommand.InvokeScript($false, ([scriptblock]::Create([io.file]::ReadAllText($Path))), $null, $null) } catch { Write-Warning "Failed to import $Path" } } } # Detect whether at some level dotsourcing was enforced $script:doDotSource = $false if ($dbachecks_dotsourcemodule) { $script:doDotSource = $true } if ((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\WindowsPowerShell\dbachecks\System" -Name "DoDotSource" -ErrorAction Ignore).DoDotSource) { $script:doDotSource = $true } if ((Get-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\WindowsPowerShell\dbachecks\System" -Name "DoDotSource" -ErrorAction Ignore).DoDotSource) { $script:doDotSource = $true } # Execute Preimport actions if($IsLinux){ Write-Verbose "Loading preimport in linux" . Import-ModuleFile -Path "$ModuleRoot/internal/scripts/preimport.ps1" }else{ . Import-ModuleFile -Path "$ModuleRoot\internal\scripts\preimport.ps1" } # Import all internal functions foreach ($function in (Get-ChildItem "$ModuleRoot\internal\functions\*.ps1")) { . Import-ModuleFile -Path $function.FullName } # Import all public functions foreach ($function in (Get-ChildItem "$ModuleRoot\functions\*.ps1")) { . Import-ModuleFile -Path $function.FullName } # Execute Postimport actions if($IsLinux){ Write-Verbose "Loading postimport in linux" . Import-ModuleFile -Path "$ModuleRoot/internal/scripts/postimport.ps1" }else{ . Import-ModuleFile -Path "$ModuleRoot\internal\scripts\postimport.ps1" } if (-not (Test-Path Alias:Update-Dbachecks)) { Set-Alias -Scope Global -Name 'Update-Dbachecks' -Value 'Update-DbcRequiredModules' } $VerbosePreference = "SilentlyContinue" ================================================ FILE: source/functions/Clear-DbcPowerBiDataSource.ps1 ================================================ <# .SYNOPSIS Clears the data source directory created by Update-DbcPowerBiDataSource .DESCRIPTION Clears the data source directory created by Update-DbcPowerBiDataSource ("C:\windows\temp\dbachecks\*.json" by default). This command makes it easier to clean up data used by PowerBI via Start-DbcPowerBi. .PARAMETER Path The directory to your JSON files, which will be removed. "C:\windows\temp\dbachecks\*.json" by default .PARAMETER Environment Removes the JSON files for a specific environment .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .EXAMPLE Clear-DbcPowerBiDataSource Removes "$env:windir\temp\dbachecks\*.json" .EXAMPLE Clear-DbcPowerBiDataSource -Environment Production Removes "$env:windir\temp\dbachecks\*Production*.json" .LINK https://dbachecks.readthedocs.io/en/latest/functions/Clear-DbcPowerBiDataSource/ #> function Clear-DbcPowerBiDataSource { [CmdletBinding()] param ( [string]$Path = "$env:windir\temp\dbachecks", [string]$Environment, [switch]$EnableException ) if($IsLinux){ Write-PSFMessage "We cannot run this command from linux at the moment" -Level Warning Return } $null = Remove-Item "$Path\*$Environment*.json" -ErrorAction SilentlyContinue } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUA00kTu85Ivjt7LC5otovqiJK # 1emgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBS6xAwZ6on2dM+sbzpK2hGvwd5f # 9jANBgkqhkiG9w0BAQEFAASCAQAOVXnyzzJViidCg4J6HneRqOvHanT5cfRCBgYW # 4je8YQjwp21Z5nNnzLDjYfkGvO42JNbiLEoUioeWXmKUpRX9tI6q6xpE6oZYX4ws # IixgpBQMTH6dyjYZOvD1z0dnOfr6PiX6Zu1LHMD6iV8rFkVEq1Dcc5Z7g9mOxmY0 # eWY87eeuE+JANHGeGB7DSizDK5+nVQboSrSq8I1TfQIEy+1+DqSzD4Kj0DZJ0tk/ # HUomLslBpqQgohNMG8OxlfPKhe+/fXIG58IRIQ8l28hdIj8ZM3MlXPRW+yI9wvgM # SgHLi+IvYbJW3rCfq9n5wbkMg9f4rjEjPGmv+aoY8mkjBvDe # SIG # End signature block ================================================ FILE: source/functions/Convert-DbcResult.ps1 ================================================ <# .SYNOPSIS Takes the results of Invoke-DbcCheck, parses it and converts it to a datatable object .DESCRIPTION You need to run Invoke-DbcCheck with the PassThru parameter and this command will take the results and parse them creating a datatable object with column headings Date Label Describe Context Name Database ComputerName Instance Result FailureMessage so that it can be written to a database with Write-DbcTable (or Write-DbaDataTable) or to a file with Set-DbcFile .PARAMETER TestResults The output of Invoke-DbcCheck (WITH -PassThru) .PARAMETER Label An optional label to add to the set of results to identify them - Think Morning-Checks or New-instance .EXAMPLE Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check .EXAMPLE Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Write-DbcTable -SqlInstance sql2017n5 -Database tempdb -Table newdbachecks Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and writes it to a table newdbachecks in tempdb on SQL2017N5 (NB Don't use tempdb!!) .EXAMPLE Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Set-DbcFile -FilePath C:\temp\dbachecks\ -FileName Auto-close.json -FileType Json Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and outputs to JSON and saves in C:\temp\dbachecks\Auto-close.json .NOTES Initial - RMS 28/12/2019 #> function Convert-DbcResult { [OutputType([System.Data.DataTable])] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'Because I dont know why it doesnt know about Label')] Param( # The pester results object [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [Alias('TestsResults')] [PSCustomObject]$Results, [Parameter(Mandatory = $false)] # the label for the Tests [string]$Label = 'NoLabel' ) begin { Write-PSFMessage "Creating a datatable" -Level Verbose # Create DataTable Object $table = New-Object system.Data.DataTable Results # Create Columns $col1 = New-Object system.Data.DataColumn Date, ([datetime]) $col2 = New-Object system.Data.DataColumn Label, ([string]) $col3 = New-Object system.Data.DataColumn Describe, ([string]) $col4 = New-Object system.Data.DataColumn Context, ([string]) $col5 = New-Object system.Data.DataColumn Name, ([string]) $col6 = New-Object system.Data.DataColumn Database, ([string]) $col7 = New-Object system.Data.DataColumn ComputerName, ([string]) $col8 = New-Object system.Data.DataColumn Instance, ([string]) $col9 = New-Object system.Data.DataColumn Result, ([string]) $col10 = New-Object system.Data.DataColumn FailureMessage, ([string]) #Add the Columns to the table $table.columns.add($col1) $table.columns.add($col2) $table.columns.add($col3) $table.columns.add($col4) $table.columns.add($col5) $table.columns.add($col6) $table.columns.add($col7) $table.columns.add($col8) $table.columns.add($col9) $table.columns.add($col10) } process { Write-PSFMessage "Testing we have a Test Results object" -Level Verbose if ( $Results.TestResult) { Write-PSFMessage "Processing the v4 test results" -Level Verbose $Results.TestResult.ForEach{ $ContextSplit = ($PSitem.Context -split ' ') $ComputerName = ($ContextSplit[-1] -split '\\')[0] $NameSplit = ($PSitem.Name -split ' ') if ($PSitem.Name -match '^Database\s(.*?)\s') { $Database = $Matches[1] } else { $Database = $null } $Date = Get-Date # Create a new Row $row = $table.NewRow() # Add values to new row $Row.Date = [datetime]$Date $Row.Label = $Label $Row.Describe = $PSitem.Describe $Row.Context = $ContextSplit[0..($ContextSplit.Count - 3)] -join ' ' $Row.Name = $NameSplit[0..($NameSplit.Count - 3)] -join ' ' $Row.Database = $Database $Row.ComputerName = $ComputerName $Row.Instance = $ContextSplit[-1] $Row.Result = $PSitem.Result $Row.FailureMessage = $PSitem.FailureMessage #Add new row to table $table.Rows.Add($row) } } else { Write-PSFMessage "Processing the v5 test results" -Level Verbose $Results.Tests.Where{ $Psitem.Result -ne 'NotRun' }.ForEach{ $TestResult = $Psitem switch ($TestResult.Result) { 'skipped' { $PathSplit = $TestResult.ExpandedPath.split('.') $Describe = $PathSplit[0] $Context = $PathSplit[1] $ContextSplit = ($Context -split ' ') $Instance = $ContextSplit[-1] $CheckName = $TestResult.ExpandedName -replace '<_.Name>', 'CheckSkipped' -replace '<_.SqlInstance>', $Instance if ($TestResult.ExpandedName -match '<_\.Name>') { $Database = 'CheckSkipped' } else { $Database = $null } } Default { $PathSplit = $TestResult.ExpandedPath.split('.') $Describe = $PathSplit[0] $Context = $PathSplit[1] $ContextSplit = ($Context -split ' ') $Instance = $ContextSplit[-1] $CheckName = $TestResult.ExpandedName if ($TestResult.ExpandedName -match '^Database\s(.*?)\s') { $Database = $Matches[1] } else { $Database = $null } } } $ComputerName = ($ContextSplit[-1] -split '\\')[0] $Date = Get-Date # Create a new Row $row = $table.NewRow() # Add values to new row $Row.Date = [datetime]$Date $Row.Label = $Label $Row.Describe = $Describe $Row.Context = $Context $Row.Name = $CheckName $Row.Database = $Database $Row.ComputerName = $ComputerName $Row.Instance = $Instance $Row.Result = $TestResult.Result $Row.FailureMessage = $TestResult.ErrorRecord.Exception.Message #Add new row to table $table.Rows.Add($row) } } } end { Write-Output -NoEnumerate -InputObject $table } } ================================================ FILE: source/functions/Export-DbcConfig.ps1 ================================================ <# .SYNOPSIS Exports dbachecks configs to a json file to make it easier to modify or be used for specific configurations. .DESCRIPTION Exports dbachecks configs to a json file to make it easier to modify or be used for specific configurations. .PARAMETER Path The path to export to, by default is "$script:localapp\config.json" .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .PARAMETER Force Overwrite Existing file .EXAMPLE Export-DbcConfig Exports config to "$script:localapp\config.json" .EXAMPLE Export-DbcConfig -Path \\nfs\projects\config.json Exports config to \\nfs\projects\config.json .EXAMPLE $config = Export-DbcConfig | Invoke-Item Exports config to "$script:localapp\config.json" as and opens it in a default application. .LINK https://dbachecks.readthedocs.io/en/latest/functions/Export-DbcConfig/ #> function Export-DbcConfig { [CmdletBinding()] [OutputType('System.String')] param ( [string]$Path = "$script:localapp\config.json", [switch]$Force ) Write-PSFMessage "Testing if $Path exists" -Level Verbose if (Test-Path -Path $Path) { if (-not $Force) { Write-PSFMessage "Uh-Oh - File $Path exists - use the Force parameter to overwrite (even if your name is not Luke!)" -Level Significant Return '' } else { Write-PSFMessage "File $Path exists and will be overwritten " -Level Verbose } } try { Get-DbcConfig | Select-Object * | ConvertTo-Json -Depth 10 | Out-File -FilePath $Path -Force -ErrorAction Stop # support for Invoke-Item Get-Item -Path $Path Write-PSFMessage -Message "Wrote file to $Path" -Level Verbose } catch { Stop-PSFFunction -Message $_ -Target $Path } } ================================================ FILE: source/functions/Get-DbcCheck.ps1 ================================================ <# .SYNOPSIS Lists all checks, tags and unique identifiers .DESCRIPTION Lists all checks, tags and unique identifiers .PARAMETER Tag The tag to return information about .PARAMETER Pattern May be any string, supports wildcards. .PARAMETER Group To be able to filter by group .EXAMPLE Get-DbcCheck Retrieves all of the available checks .EXAMPLE Get-DbcCheck backups Retrieves all of the available tags that match backups .LINK https://dbachecks.readthedocs.io/en/latest/functions/Get-DbcCheck/ #> function Get-DbcCheck { [CmdletBinding()] param ( [string]$Tag, [string]$Pattern, [string]$Group ) process { $script:localapp = Get-DbcConfigValue -Name app.localapp # so that it works cross platform $checksfile = Join-Path -Path $script:localapp -ChildPath 'checks.json' if ($Pattern) { if ($Pattern -notmatch '\*') { $output = @([System.IO.File]::ReadAllText($checksfile) | ConvertFrom-Json).ForEach{ $psitem | Where-Object { $_.Group, $_.Description , $_.UniqueTag , $_.AllTags, $_.Type -match $Pattern } } } else { $output = @([System.IO.File]::ReadAllText($checksfile) | ConvertFrom-Json).ForEach{ $psitem | Where-Object { $_.Group, $_.Description , $_.UniqueTag , $_.AllTags, $_.Type -like $Pattern } } } } else { $output = [System.IO.File]::ReadAllText($checksfile) | ConvertFrom-Json } if ($Group) { $output = @($output).ForEach{ $psitem | Where-Object { $_.Group -eq $Group } } } if ($Tag) { $output = @($output).ForEach{ $psitem | Where-Object { $_.AllTags -match $Tag } } } @($output).ForEach{ Select-DefaultView -InputObject $psitem -TypeName Check -Property 'Group', 'Type', 'UniqueTag', 'AllTags', 'Config', 'Description' } } } ================================================ FILE: source/functions/Get-DbcConfig.ps1 ================================================ <# .SYNOPSIS Retrieves configuration elements by name. .DESCRIPTION Retrieves configuration elements by name. Can be used to search the existing configuration list. .PARAMETER Name Default: "*" The name of the configuration element(s) to retrieve. May be any string, supports wildcards. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .EXAMPLE Get-DbcConfig Gets all of the dbachecks configurations for the current session. .EXAMPLE Get-DbcConfig app.sqlinstance Retrieves the configuration element for the configuration app.sqlinstance .LINK https://dbachecks.readthedocs.io/en/latest/functions/Get-DbcConfig/ #> function Get-DbcConfig { [CmdletBinding()] param ( [string[]]$Name = '*', [switch]$EnableException ) begin { $Module = 'dbachecks' } process { foreach ($configName in $Name) { $configName = $configName.ToLower() $results = [PSFramework.Configuration.ConfigurationHost]::Configurations.Values | Where-Object { ($_.Name -like $configName) -and ($_.Module -like $Module) -and ((-not $_.Hidden) -or ($Force)) } | Sort-Object Module, Name $results | Select-Object Name, Value, Description } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUp++lzWH925cphTu1sPIOsDer # vOmgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBSLOffvddixct6nJ9okJTRzAQuq # qTANBgkqhkiG9w0BAQEFAASCAQCKUShGyPbM7X9iwJhehd8C59noyPTJ6TwWHA1M # IJTqh1Ao1+aRIpUxw4HEZj/tF66iVQ6l4rjR7UKESyCUugs1TA+GbRJJ4ZySFhBq # 4UhG666U5+1uiBwnMeFNZRc+zv4K9DgzYeIvtPKbxZfm5v0vJ9fpk3hhcbeBe8UV # 3Zt6CeJR8MKHr1w/NjUSXujMeRqiRtx7Dr7eur75WNFwyT+acTK7URzQXzdUkjEU # 7lTRy2oUWxjdiQk7bWMwdy8Eox7u1PpmrQ5NdWfFRo4ezsz9q7Gk2360QZLmsevb # F8irwSmcSyIDubZ6p9LxG/fFUXSlhGQMncrfozRLxcrXLHk3 # SIG # End signature block ================================================ FILE: source/functions/Get-DbcConfigValue.ps1 ================================================ <# .SYNOPSIS Retrieves raw configuration values by name. .DESCRIPTION Retrieves raw configuration values by name. Can be used to search the existing configuration list. .PARAMETER Name Default: "*" The name of the configuration element(s) to retrieve. May be any string, supports wildcards. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .EXAMPLE Get-DbcConfigValue app.sqlinstance Retrieves the raw value for the key "app.sqlinstance" .EXAMPLE Get-DbcConfigValue app.computername Retrieves the raw value for the key "app.computername" .LINK https://dbachecks.readthedocs.io/en/latest/functions/Get-DbcConfig/ #> function Get-DbcConfigValue { [CmdletBinding()] param ( [string]$Name = '*', [switch]$EnableException ) begin { # $Module = "dbachecks" } process { $Name = $Name.ToLower() Get-DbcConfig -Name $name | Select-Object -ExpandProperty Value } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU4P3RdY4dWlK/kA9jRpcIQAZF # yMqgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTKpPwIWx/YjqN1/9bAaFeecyLF # 2TANBgkqhkiG9w0BAQEFAASCAQBAAzm5rJJtiV/ZtGDlRmw1sY321FBpgDX6vUWi # NMh7GLPkTRKN78Z69mCzd8tI+G2LOVe4UyJftqWodS+ZXxQGjxWs9/EqVFjqhIgo # 7QF+w5szvjskt4Gj1BFXz2jkbWiqzUNMddZF0GLnQYjhZybtunqwfrM6bXJj9SIP # 2m7ASAowVcqr0tZn/ENtqL37Kd0VZWVq/KhM/FFG+OPj4M+74aEs5suej7fvzV2x # IXUazrkgeazTc4yS/9UhB3FKEqqIpdgaaXwlnc0CPVbpqI8h/KY7kJTLQ4ydbHFq # VmOWKCXRoYStjv5qrgxuITV6hiaArar6Xnreq0VLFcuqNf2S # SIG # End signature block ================================================ FILE: source/functions/Get-DbcReleaseNote.ps1 ================================================ <# .SYNOPSIS Returns the release notes for the module - organised by date .DESCRIPTION Grabs the release notes for the dbachecks module and returns either the latest or all of them .PARAMETER Latest A Switch to return the latest release notes only .EXAMPLE Get-DbcReleaseNote Returns the release notes for the dbachecks module .EXAMPLE Get-DbcReleaseNote -Latest Returns just the latest release notes for the dbachecks module .LINK https://dbachecks.readthedocs.io/en/latest/functions/Get-DbcReleaseNote/ .NOTES 30/05/2012 - RMS #> function Get-DbcReleaseNote { Param ( [switch]$Latest ) $releasenotesfile = Join-Path -Path $PSScriptRoot -ChildPath 'RELEASE.md' $releasenotes = [System.IO.File]::ReadAllText($releasenotesfile) if ($Latest) { ($releasenotes -Split "##Latest")[0] } else { $releasenotes } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUX1m+5h9AKDQyxy0HJtaG/rr5 # PKegggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBR+kO8+/t4N/1AUHnycw22KYl72 # VDANBgkqhkiG9w0BAQEFAASCAQAUEjMBkN6h/919Kp4RG4Cp7kUyYbz77icSAWJq # HYuIafBkquZRhF0KJ+6Q5kCzqwwFt4HFZKrmUu7DRXi6ZjS92tEt+N3rbCcqWf23 # MSeKNULZ7EIok6BKjJzsA1x5pfBdZXmIz6YXnHRn4wdo4yo5GpmtWJ/oL8Zm200+ # WBCgcfSId0PDOrmVpfN1cmIpPCDZ+svfzo9f/P5cH+q9bY/hYbUKMOTQCr5/1tJe # wJ+/vGeqdEp0IxbU7B5MA2Nm9iY3HFh57iDOMS+gEQybj+8JmEQw+Zyvh4YZ+d2a # y9hCaxWuk44+GCaXmaFo2KkGC+CUOTpGOljIeWssQdutlFS2 # SIG # End signature block ================================================ FILE: source/functions/Get-DbcTagCollection.ps1 ================================================ <# .SYNOPSIS Retrieves a list of all available tags. Simplistic, similar to Get-Verb. .DESCRIPTION Retrieves a list of all available tags. Simplistic, similar to Get-Verb. .PARAMETER Name Default: "*" The name of the tag to retrieve. May be any string, supports wildcards. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .EXAMPLE Get-DbcTag Retrieves all of the available tags for -Tag and -ExcludeTag .EXAMPLE Get-DbcTag backups Retrieves all of the available tags for -Tag and -ExcludeTag that are -like backups .LINK https://dbachecks.readthedocs.io/en/latest/functions/Get-DbcTagCollection/ #> function Get-DbcTagCollection { [CmdletBinding()] param ( [string]$Name = "*", [switch]$EnableException ) process { $script:localapp = Get-DbcConfigValue -Name app.localapp # so that it works cross platform $checksfile = Join-Path -Path $script:localapp -ChildPath 'checks.json' $alltags = ([System.IO.File]::ReadAllText($checksfile) | ConvertFrom-Json) | Select-Object -ExpandProperty AllTags ($alltags -split ",").Trim() | Where-Object { $_ -like $name } | Sort-Object | Select-Object -Unique } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUjVxf87ljPm2jHdPbI+pfbR2q # tK2gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRNBjIYXnlxLI1MtDtAAqXjSlPs # zTANBgkqhkiG9w0BAQEFAASCAQBdjaKdD8oVpoI/3gIlTU2smc/09Hv3kq05WPpn # kAv4t6E2l+St85RgZwojT1zgmgXIYdr+wv0z2Qejk6y06Hzgb/yCkQ1VGBHrcmOO # c/aXhU8QRkjfBtm5vRjzKpb31ayLvn8KNM4qT+ViSZJi79JbUW0FeNkPau8pQ7s+ # t/HWxC2q9M4Gn2fravi8FPcV6GQAzkGsd+Y5gEC3kWF7o25VSZUZ4PxUC4XIkz0r # VQVFbS4davU9uWNzkxfOv4Jro0PhM56fN9ExHUFi+Wwa4xptL9BTIFNp1Uczvw8U # YtZWcUazKI9O3XKynRYrSTRUzhJ4O6ntZ3Fko1yf7QHncU1z # SIG # End signature block ================================================ FILE: source/functions/Import-DbcConfig.ps1 ================================================ <# .SYNOPSIS Imports dbachecks configs from a json file .DESCRIPTION Imports dbachecks configs from a json file .PARAMETER Path The path to import from, by default is "$script:localapp\config.json" .PARAMETER Temporary The settings are not persisted outside the current session. By default, settings will be remembered across all PowerShell sessions. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .EXAMPLE Import-DbcConfig Imports config from "$script:localapp\config.json" .EXAMPLE Import-DbcConfig -Path \\nas\projects\config.json Imports config from \\nas\projects\config.json .LINK https://dbachecks.readthedocs.io/en/latest/functions/Import-DbcConfig/ #> function Import-DbcConfig { [CmdletBinding()] param ( [string]$Path = (Join-Path -Path $script:localapp -ChildPath config.json) , [switch]$Temporary ) process { if (-not (Test-Path -Path $Path)) { Stop-PSFFunction -Message "$Path does not exist. Run Export-DbcConfig to create." return } try { $results = [System.IO.File]::ReadAllText($Path) | ConvertFrom-Json } catch { Stop-PSFFunction -Message "Failure" -ErrorRecord $_ return } foreach ($result in $results) { Set-DbcConfig -Name $result.Name -Value $result.Value -Temporary:$Temporary } } } ================================================ FILE: source/functions/Invoke-DbcCheck.ps1 ================================================  <# .SYNOPSIS Invoke-DbcCheck is a SQL-centric Invoke-Pester wrapper .DESCRIPTION The Invoke-DbcCheck function runs Pester tests, including *.Tests.ps1 files and Pester tests in PowerShell scripts. Extended description about Pester: Get-Help -Name Invoke-Pester .PARAMETER Check Runs only tests in Describe blocks with the specified Tag parameter values. Wildcard characters and Tag values that include spaces or whitespace characters are not supported. When you specify multiple Tag values, Invoke-DbcCheck runs tests that have any of the listed tags (it ORs the tags). However, when you specify TestName and Tag values, Invoke-DbcCheck runs only describe blocks that have one of the specified TestName values and one of the specified Tag values. If you use both Tag and ExcludeTag, ExcludeTag takes precedence. .PARAMETER ExcludeCheck Omits tests in Describe blocks with the specified Tag parameter values. Wildcard characters and Tag values that include spaces or whitespace characters are not supported. When you specify multiple ExcludeTag values, Invoke-DbcCheck omits tests that have any of the listed tags (it ORs the tags). However, when you specify TestName and ExcludeTag values, Invoke-DbcCheck omits only describe blocks that have one of the specified TestName values and one of the specified Tag values. If you use both Tag and ExcludeTag, ExcludeTag takes precedence .PARAMETER SqlInstance A list of SQL Servers to run the tests against. If this is not provided, it will be gathered from: Get-DbatoolsConfig -Name app.sqlinstance .PARAMETER ComputerName A list of computers to run the tests against. If this is not provided, it will be gathered from: Get-DbatoolsConfig -Name app.computername .PARAMETER SqlCredential Alternate SQL Server-based credential. .PARAMETER Credential Alternate Windows credential. .PARAMETER Database A list of databases to include if your check is database centric. .PARAMETER ExcludeDatabase A list of databases to exclude if your check is database centric. .PARAMETER PassThru Returns a custom object (PSCustomObject) that contains the test results. By default, Invoke-DbcCheck writes to the host program, not to the output stream (stdout). If you try to save the result in a variable, the variable is empty unless you use the PassThru parameter. To suppress the host output, use the Quiet parameter. .PARAMETER ConfigFile The path to the exported dbachecks config file. .PARAMETER OutputFormat The format of output. Currently, only NUnitXML is supported. .PARAMETER Strict Makes Pending and Skipped tests to Failed tests. Useful for continuous integration where you need to make sure all tests passed. .PARAMETER AllChecks In the unlikely event that you'd like to run all checks, specify -AllChecks. These checks still confirm to the skip settings in Get-DbcConfig. .PARAMETER Quiet The parameter Quiet is deprecated since Pester v. 4.0 and will be deleted in the next major version of Pester. Please use the parameter Show with value 'None' instead. .PARAMETER Show Customizes the output Pester writes to the screen. Available options are None Default Passed Failed Pending Skipped Inconclusive Describe Context Summary Header All Fails The options can be combined to define presets. Common use cases are: None - to write no output to the screen. All - to write all available information (this is default option). Fails - to write everything except Passed (but including Describes etc.). A common setting is also Failed, Summary, to write only failed tests and test summary. This parameter does not affect the PassThru custom object or the XML output that is written when you use the Output parameters. .PARAMETER Value A value.. it's hard to explain .PARAMETER Script Get-Help -Name Invoke-Pester -Parameter Script .PARAMETER TestName Get-Help -Name Invoke-Pester -Parameter TestName .PARAMETER EnableExit Get-Help -Name Invoke-Pester -Parameter EnableExit .PARAMETER OutputFile Get-Help -Name Invoke-Pester -Parameter OutputFile .PARAMETER CodeCoverage Get-Help -Name Invoke-Pester -Parameter CodeCoverage .PARAMETER PesterOption Get-Help -Name Invoke-Pester -Parameter PesterOption .PARAMETER CodeCoverageOutputFile Get-Help -Name Invoke-Pester -Parameter CodeCoverageOutputFile .PARAMETER CodeCoverageOutputFileFormat Get-Help -Name Invoke-Pester -Parameter CodeCoverageOutputFileFormat .LINK https://dbachecks.readthedocs.io/en/latest/functions/Invoke-DbcCheck/ .EXAMPLE Invoke-DbcCheck -Tag Backup -SqlInstance sql2016 Runs all of the checks tagged Backup against the sql2016 instance .EXAMPLE Invoke-DbcCheck -Tag RecoveryModel -SqlInstance sql2017, sqlcluster -SqlCredential (Get-Credential sqladmin) Runs the Recovery model check against the SQL instances sql2017, sqlcluster using the sqladmin SQL login with the password provided interactively .EXAMPLE Invoke-DbcCheck -Check Database -ExcludeCheck AutoShrink -ConfigFile \\share\repo\prod.json Runs all of the checks tagged Database except for the AutoShrink check against the SQL Instances set in the config under app.sqlinstance Imports configuration file, \\share\repo\prod.json, prior to executing checks. .EXAMPLE # Set the servers you'll be working with Set-DbcConfig -Name app.sqlinstance -Value sql2016, sql2017, sql2008, sql2008\express Set-DbcConfig -Name app.computername -Value sql2016, sql2017, sql2008 # Look at the current configs Get-DbcConfig # Invoke a few tests Invoke-DbcCheck -Tags SuspectPage, LastBackup Runs the Suspect Pages and Last Backup checks against the SQL Instances sql2016, sql2017, sql2008, sql2008\express after setting them in the configuration .EXAMPLE Invoke-DbcCheck -SqlInstance sql2017 -Tags SuspectPage, LastBackup -Show Summary -PassThru | Update-DbcPowerBiDataSource Start-DbcPowerBi Runs the Suspect Page and Last Backup checks against the SQL Instances set in the config under app.sqlinstance only showing the summary of the results of the checks. It then updates the source json for the XML which is stored at C:\Windows\temp\dbachecks\ and then opens the PowerBi report in PowerBi Desktop .EXAMPLE Get-Help -Name Invoke-Pester -Examples Want to get super deep? You can look at Invoke-Pester's example's and run them against Invoke-DbcCheck since it's a wrapper. https://github.com/pester/Pester/wiki/Invoke-Pester Describe about_Pester #> #TODO the help is probably not correct function Invoke-DbcCheck { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '', Justification = 'Because scoping is hard')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Because its set to the global var')] [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Alias('Path', 'relative_path')] [object[]]$Script, [Alias('Name')] [string[]]$TestName, [switch]$EnableExit, [Parameter(Position = 0)] [Alias('Tags', 'Tag', 'Checks')] [string[]]$Check, [AllowEmptyCollection()] [Alias('ExcludeTags', 'ExcludeTag', 'ExcludeChecks')] [string[]]$ExcludeCheck = (Get-PSFConfigValue -FullName 'dbachecks.command.invokedbccheck.excludecheck' -Fallback @()), [switch]$PassThru, [DbaInstance[]]$SqlInstance, [DbaInstance[]]$ComputerName, [PSCredential]$SqlCredential, [PSCredential]$Credential, [object[]]$Database, [object[]]$ExcludeDatabase = (Get-PSFConfigValue -FullName 'dbachecks.command.invokedbccheck.excludedatabase' -Fallback @()), [string[]]$Value, [string]$ConfigFile, [object[]]$CodeCoverage = @(), [string]$CodeCoverageOutputFile, [ValidateSet('JaCoCo')] [string]$CodeCoverageOutputFileFormat = 'JaCoCo', [switch]$Strict, [Parameter(Mandatory = $true, ParameterSetName = 'NewOutputSet')] [string]$OutputFile, [ValidateSet('NUnitXml')] [string]$OutputFormat, [switch]$AllChecks, [switch]$Quiet, [ValidateSet('None', 'Minimal', 'Detailed', 'Default', 'Passed', 'Failed', 'Pending', 'Skipped', 'Inconclusive', 'Describe', 'Context', 'Summary', 'Header', 'Fails', 'All', 'Diagnostic')] #None, Default,Passed, Failed, Pending, Skipped, Inconclusive, Describe, Context, Summary, Header, All, Fails. [string]$Show = 'All', [bool]$legacy = $true ) dynamicparam { $config = Get-PSFConfig -Module dbachecks $RuntimeParamDic = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary foreach ($setting in $config) { $name = $setting.Name $name = 'Config' + (($name.Split('.') | ForEach-Object { $_.SubString(0, 1).ToUpper() + $_.SubString(1) }) -join '') $ParamAttrib = New-Object System.Management.Automation.ParameterAttribute $ParamAttrib.ParameterSetName = '__AllParameterSets' $AttribColl = New-Object System.Collections.ObjectModel.Collection[System.Attribute] $AttribColl.Add($ParamAttrib) $RuntimeParam = New-Object System.Management.Automation.RuntimeDefinedParameter($name, [object], $AttribColl) $RuntimeParamDic.Add($name, $RuntimeParam) } return $RuntimeParamDic } begin { if (Test-PSFParameterBinding -ParameterName ConfigFile) { if (-not (Test-Path -Path $ConfigFile)) { Stop-PSFFunction -Message "$ConfigFile does not exist" return } $null = Import-DbcConfig -Path $ConfigFile -WarningAction SilentlyContinue -Temporary } $config = Get-PSFConfig -Module dbachecks foreach ($key in $PSBoundParameters.Keys | Where-Object { $_ -like 'Config*' }) { if ($item = $config | Where-Object { "Config$($_.Name.Replace('.', ''))" -eq $key }) { Set-PSFConfig -Module dbachecks -Name $item.Name -Value $PSBoundParameters.$key } } if ($SqlCredential) { if ($PSDefaultParameterValues) { $PSDefaultParameterValues.Remove('*:SqlCredential') $newvalue = $PSDefaultParameterValues += @{ '*:SqlCredential' = $SqlCredential } Set-Variable -Scope 0 -Name PSDefaultParameterValues -Value $newvalue } else { Set-Variable -Scope 0 -Name PSDefaultParameterValues -Value @{ '*:SqlCredential' = $SqlCredential } } } else { if ($PSDefaultParameterValues) { $PSDefaultParameterValues.Remove('*:SqlCredential') } } if ($Credential) { if ($PSDefaultParameterValues) { $PSDefaultParameterValues.Remove('*Dba*:Credential') $newvalue = $PSDefaultParameterValues += @{ '*Dba*:Credential' = $Credential } Set-Variable -Scope 0 -Name PSDefaultParameterValues -Value $newvalue } else { Set-Variable -Scope 0 -Name PSDefaultParameterValues -Value @{ '*Dba*:Credential' = $Credential } } } else { if ($PSDefaultParameterValues) { $PSDefaultParameterValues.Remove('*Dba*:Credential') } } } process { if ($legacy) { try { Write-PSFMessage 'Running in legacy mode, we need Version 4' if (Get-Module Pester | Where-Object { $_.Version -gt '5.0.0' }) { Write-PSFMessage 'Remove Version 5' -Level Verbose Remove-Module Pester -ErrorAction SilentlyContinue } Write-PSFMessage 'import Version 4' -Level Verbose Import-Module Pester -RequiredVersion 4.10.1 -Global } catch { Write-PSFMessage -Message 'Something Went wrong' -Level Warning -ErrorRecord $_ Return } $null = $PSBoundParameters.Remove('legacy') Invoke-DbcCheckv4 @PSBoundParameters } else { try { if (Get-Module Pester | Where-Object { $_.Version -lt '5.0.0' }) { Remove-Module Pester -ErrorAction SilentlyContinue Write-PSFMessage 'Running in fancy new mode, we need to import Version 5' -Level Verbose Import-Module Pester -MinimumVersion 5.0.0 -Global } else { Write-PSFMessage 'Running in fancy new mode but not imported' -Level Verbose } # We should be able to move the creation of the container and the configuration to here switch ($Show) { 'None' { $NewShow = 'None' } 'Default' { $NewShow = 'Detailed' } 'Passed' { $NewShow = 'Normal' } 'Failed' { $NewShow = 'Normal' } 'Pending' { $NewShow = 'Normal' } 'Skipped' { $NewShow = 'Normal' } 'Inconclusive' { $NewShow = 'Normal' } 'Describe' { $NewShow = 'Normal' } 'Context' { $NewShow = 'Normal' } 'Summary' { $NewShow = 'Normal' } 'Header' { $NewShow = 'Normal' } 'Fails' { $NewShow = 'Normal' } 'All' { $NewShow = 'Detailed' } 'Diagnostic' { $NewShow = 'Diagnostic' } 'Minimal' { $NewShow = 'Minimal' } Default { $NewShow = 'Detailed' } } # cast from empty hashtable to get default $configuration = New-PesterConfiguration $configuration.Output.Verbosity = $NewShow $configuration.Filter.Tag = $check + 'FailedConnections' # Exclude the excluded checks and the not converted checks $notv5 = (Get-PSFConfigValue -FullName 'dbachecks.checks.notv5ready') $configuration.Filter.ExcludeTag = $ExcludeCheck + $notv5 if ($PassThru) { $configuration.Run.PassThru = $true } # So that if all of the checks passed in are not yet converted so that we stop # Compare the two arrays $comparisonResult = Compare-Object -ReferenceObject $check -DifferenceObject $notv5 # If all elements of $check are in $notv5, then $comparisonResult will be either $null or only contain differences where SideIndicator is '=>' if (($comparisonResult | Where-Object SideIndicator -EQ '<=').Count -eq 0) { $Message = "The checks that you are running are yet to be converted to v5 unfortunately. We cannot continue. Please use the legacy switch" Write-PSFMessage -Message $Message -Level Warning Return } foreach ($c in $Check) { # So that if the only check passed in is not yet converted if ($c -in $notv5) { $Message = "You are running a check {0} that is not yet converted to v5." -f $c Write-PSFMessage -Message $Message -Level Warning } } } catch { Write-PSFMessage -Message 'Something Went wrong' -Level Warning -ErrorRecord $_ Return } $null = $PSBoundParameters.Remove('legacy') $null = $PSBoundParameters.Remove('Show') $null = $PSBoundParameters.Remove('PassThru') Write-PSFMessage -Message ($PSBoundParameters | Out-String) -Level Verbose Invoke-DbcCheckv5 @PSBoundParameters -configuration $configuration } } end { foreach ($c in $Check) { # So that if the only check passed in is not yet converted if ($c -in $notv5) { $Message = "You are running a check {0} that is not yet converted to v5." -f $c Write-PSFMessage -Message $Message -Level Warning } } } } ================================================ FILE: source/functions/Invoke-DbcConfigFile.ps1 ================================================ <# .SYNOPSIS Opens the default location of the json config file for easy edits. .DESCRIPTION Opens the default location of the json config file for easy edits. Follow with Import-DbcConfig to import changes. .PARAMETER Path The path to open, by default is "$script:localapp\config.json" .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .EXAMPLE Invoke-DbcConfigFile Opens "$script:localapp\config.json" for editing. .EXAMPLE Invoke-DbcConfigFile -Path C:\temp\config.json Opens "C:\temp\config.json" for editing. .LINK https://dbachecks.readthedocs.io/en/latest/functions/Invoke-DbcConfigFile/ #> function Invoke-DbcConfigFile { [CmdletBinding()] param ( [string]$Path = "$script:localapp\config.json", [switch]$EnableException ) process { if (-not (Test-Path -Path $Path)) { Stop-PSFFunction -Message "$Path does not exist. Run Export-DbcConfig to create a file." return } try { Invoke-Item -Path $Path Write-PSFMessage -Level Output -Message "Remember to run Import-DbcConfig when you've finished your edits" } catch { Stop-PSFFunction -Message 'Failure' -ErrorRecord $_ return } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUhQLRhUDOEe2I8CmDdGnBrRYH # Ee+gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQxinshpufcrAFD4+lsl7TQL3lR # dTANBgkqhkiG9w0BAQEFAASCAQB8Cf7BgEbjFk9gvbjrOkQeTEY4N4khNOuv0b6y # EDOh+yazZiAFKDcF7p2mKyKzIkBm3gpv8S2iNhlV6nkqb8N23qvJ7ljgosVtXTId # 0rwhCAL0OheOcQPgdNCH8C3FvVznouf9UzRZFLDUp0aeThRE5Y+abT9HsrAn9EsF # K9cZk06BQXAv2iFZG3RCWnhFZgbeDwGq+7EgjKA871M/58zM/V6FPwmVz35mKCwr # xIe3OuMbZdvek8UafD+qpPMZ/NBSOe/nywfQBDGhbBPCxr53QzuY3GyopoxXsffU # TSjlcftuoLS1Am+d7JSU41yPg9PFr4L7ljrkoBmaOwWowOjA # SIG # End signature block ================================================ FILE: source/functions/Reset-DbcConfig.ps1 ================================================ . $script:ModuleRoot/internal/functions/Invoke-ConfigurationScript.ps1 <# .SYNOPSIS Resets configuration entries to their default values. .DESCRIPTION This function unregisters configuration values and then registers them back with the default values and type. This can be used to get the dbachecks back to default state of configuration, or to resolve problems with a specific setting. .PARAMETER Name Name of the configuration key. .EXAMPLE Reset-DbcConfig Resets all the configuration values for dbachecks. .EXAMPLE Reset-DbcConfig -Name policy.recoverymodel.type Resets the policy.recoverymodel.type to the default value and type. .LINK https://dbachecks.readthedocs.io/en/latest/functions/Reset-DbcConfig/ #> function Reset-DbcConfig { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding(DefaultParameterSetName = "FullName")] param ( [Parameter(Mandatory = $false)] [string[]]$Name ) process { if (!$Name) { # no name provided, get all known dbachecks settings $resolvedName = (Get-DbcConfig).Name } elseif ($Name -match '\*') { # wildcard is used, get only the matching settings $resolvedName = (Get-DbcConfig).Name | Where-Object { $psitem -like $Name } } else { $resolvedName = $Name } @($resolvedName).ForEach{ $localName = $psitem.ToLower() if (-not (Get-DbcConfig -Name $localName)) { Stop-PSFFunction -FunctionName Reset-DbcConfig -Message "Setting named $localName does not exist. Use Get-DbcCheck to get the list of supported settings." } else { Write-PSFMessage -FunctionName Reset-DbcConfig -Message "resetting $localName" Unregister-PSFConfig -Module dbachecks -Name $localName [PSFramework.Configuration.ConfigurationHost]::Configurations.Remove("dbachecks.$localName") | Out-Null } } # set up everything that is now missing back to the default values Invoke-ConfigurationScript # display the new values @($resolvedName).ForEach{ Get-DbcConfig -Name $psitem } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUNUBbq4EpBfs1joEMYSLCoPkb # zGGgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBR3l3SiI0NPBR4CWmM9fmSkSKLy # GDANBgkqhkiG9w0BAQEFAASCAQAr7bYA6OAueFQ2dn1dUwQGhbFE0juwzfe4oO24 # fZo+mG/t/FO/3CAK0HLcDXRlZ6DatOFBiAXg1TVQVB65Sj8kTaYK6c3RJvOh01O7 # eARSCKMI3fpNVFJ3So1GmueVwI5h63b6uwUJcWc3aWEY0rBmS3qkZBuLQh/dU+OU # eTkBCLpMYrwz9O5xDsxbF6ff9RmF54vEAI056l8RkEVw/zqvRg5NmhFeMmHhA4lW # zzdfwmL+cwj5wkPOtWPDYOV6/iE3+cUN7WvIvL8pJ83Uw+FWDNS0/fO37L7fqNGu # j66L2DwWGyn/BoQ2KjG6HcRgNVe4VzCoZGdauvRrCEXRoJdj # SIG # End signature block ================================================ FILE: source/functions/Save-DbcRequiredModules.ps1 ================================================ <# .SYNOPSIS Saves all required modules, including dbachecks, dbatools, Pester and PSFramework to a directory. Ideal for offline installs. .DESCRIPTION Saves all required modules, including dbachecks, dbatools, Pester and PSFramework to a directory. Ideal for offline installs. .PARAMETER Path The directory where the modules will be saved. Directory will be created if it does not exist. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .EXAMPLE Save-DbcRequiredModules -Path C:\temp\downlaods Saves all required modules and dbachecks to C:\temp\downloads .EXAMPLE Save-DbcRequiredModules -Path C:\temp\downlaods -Verbose Saves all required modules and dbachecks to C:\temp\downloads and shows verbose output .LINK https://dbachecks.readthedocs.io/en/latest/functions/Save-DbcRequiredModules/ #> function Save-DbcRequiredModules { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param ( [Parameter (Mandatory)] [string]$Path, [switch]$EnableException ) if (-not (Test-Path $Path)) { try { $null = New-Item -ItemType Directory -Path $Path } catch { Stop-PSFFunction -Message 'Failure' -ErrorRecord $_ } } Write-PSFMessage -Level Output -Message "Note: PowerShell Gallery will say 'Installing dependent package' but it's really just saving them." Save-Module -Name dbachecks -Path $path -ErrorAction Stop } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUSJO+eGA3wE8IQ+9je+ZBEwe9 # ItCgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBSbzda1kRH70qgKXHWxVXMddWeQ # 3TANBgkqhkiG9w0BAQEFAASCAQAu7SmvmgTskYWgLMcZE9NgPpPw7LCOK2lowfVp # MJ4fSxdxUdWc6mQwRKoNkQpxHAlzgu2ZldSA3fL88OjUoSqvcOqDA6in70w+9rXV # zy/+SnrcO4g/cZgNZcSCqOIeAKG0R4/7ZllEIf2V/r1ADqzf38xd+Sj47ZuuWSXN # Afwr8vhAUCeT38uc7amLDE2uRBXNkmX+MtEGVvczRzB10Z3F8MiEnLoxstd0O7Ug # Ak8AhSa/kENBKgNShyB7IoHIe0WI+Hlx/ia6+r9st18J0+NFxgUw6evsW1hryRqq # you198O1ZVDdGKM0Bv//pI0JLf9FWlK6hndAihTWK5y6n9RB # SIG # End signature block ================================================ FILE: source/functions/Set-DbcCisConfig.ps1 ================================================ <# .SYNOPSIS Sets values for CIS checks. .DESCRIPTION Sets CIS checks to defaults values that were different than normals values. Then sets CIS test that are set to skip by default to run. .EXAMPLE Set-DbcCisConfig sets the configuration for CIS checks .EXAMPLE Set-DbcCisConfig -Verbose sets the configuration for CIS checks with verbose output .LINK https://dbachecks.readthedocs.io/en/latest/functions/Set-DbcCisConfig/ #> function Set-DbcCisConfig { [CmdletBinding(DefaultParameterSetName = 'Name', SupportsShouldProcess)] Param ( ) Reset-DbcConfig #set CIS to what they need to be if ($PSCmdlet.ShouldProcess('Configuration' , 'Setting the values for CIS configuration ')) { Set-DbcConfig -Name skip.security.nonstandardport -Value $false Set-DbcConfig -Name policy.dacallowed -Value $false Set-DbcConfig -Name policy.errorlog.logcount -Value 12 Set-DbcConfig -Name policy.security.oleautomationproceduresdisabled -Value $false Set-DbcConfig -Name policy.oleautomation -Value 0 Set-DbcConfig -Name policy.security.adhocdistributedqueriesenabled -Value $false Set-DbcConfig -Name policy.security.clrenabled -Value $false Set-DbcConfig -Name policy.security.databasemailenabled -Value $false Set-DbcConfig -Name policy.security.xpcmdshelldisabled -Value $false Set-DbcConfig -Name skip.instance.defaulttrace -Value $false Set-DbcConfig -Name policy.security.latestbuild -Value $true Set-DbcConfig -Name skip.instance.oleautomationproceduresdisabled -Value $false Set-DbcConfig -Name policy.security.remoteaccessdisabled -Value $false Set-DbcConfig -Name policy.security.scanforstartupproceduresdisabled -Value $false Set-DbcConfig -Name skip.security.agentserviceadmin -Value $false Set-DbcConfig -Name skip.security.asymmetrickeysize -Value $false Set-DbcConfig -Name skip.security.builtinadmin -Value $false Set-DbcConfig -Name skip.security.clrassembliessafe -Value $false Set-DbcConfig -Name policy.security.containedbautoclose -Value $false Set-DbcConfig -Name skip.security.containedbautoclose -Value $false Set-DbcConfig -Name policy.security.databasemailenabled -Value $false Set-DbcConfig -Name policy.security.clrenabled -Value $false Set-DbcConfig -Name policy.security.crossdbownershipchaining -Value $false Set-DbcConfig -Name policy.security.databasemailenabled -Value $false Set-DbcConfig -Name policy.security.adhocdistributedqueriesenabled -Value $false Set-DbcConfig -Name policy.security.xpcmdshelldisabled -Value $false Set-DbcConfig -Name skip.security.ContainedDBSQLAuth -Value $false Set-DbcConfig -Name skip.security.engineserviceadmin -Value $false Set-DbcConfig -Name skip.security.fulltextserviceadmin -Value $false Set-DbcConfig -Name skip.security.guestuserconnect -Value $false Set-DbcConfig -Name skip.security.hideinstance -Value $false Set-DbcConfig -Name skip.security.localwindowsgroup -Value $false Set-DbcConfig -Name skip.security.loginauditlevelfailed -Value $false Set-DbcConfig -Name skip.security.loginauditlevelsuccessful -Value $false Set-DbcConfig -Name skip.security.LoginCheckPolicy -Value $false Set-DbcConfig -Name skip.security.LoginPasswordExpiration -Value $false Set-DbcConfig -Name skip.security.LoginMustChange -Value $false Set-DbcConfig -Name skip.security.sadisabled -Value $false Set-DbcConfig -Name skip.security.saexist -Value $false Set-DbcConfig -Name skip.security.sqlagentproxiesnopublicrole -Value $false Set-DbcConfig -Name skip.security.symmetrickeyencryptionlevel -Value $false Set-DbcConfig -Name skip.security.publicrolepermission -Value $false Set-DbcConfig -Name skip.security.serverprotocol -Value $false Set-DbcConfig -Name skip.security.SQLMailXPsDisabled -Value $false } } ================================================ FILE: source/functions/Set-DbcConfig.ps1 ================================================ <# .SYNOPSIS Sets configuration values for specific checks. .DESCRIPTION Changes configuration values which enable each check to have specific thresholds .PARAMETER Name Name of the configuration entry. .PARAMETER Value The value to assign. .PARAMETER Handler A scriptblock that is executed when a value is being set. Is only executed if the validation was successful (assuming there was a validation, of course) .PARAMETER Append Adds the value to the existing configuration instead of overwriting it .PARAMETER Temporary The setting is not persisted outside the current session. By default, settings will be remembered across all powershell sessions. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .EXAMPLE Set-DbcConfig -Name app.sqlinstance -Value sql2016, sql2017, sqlcluster Sets the SQL Instances which will be checked by default using Invoke-DbcCheck to sql2016, sql2017, sqlcluster .EXAMPLE Set-DbcConfig -Name policy.validdbowner.name -Value 'TheBeard\sqldbowner' Sets the value of the configuration for the expected database owners to TheBeard\sqldbowner .EXAMPLE Set-DbcConfig -Name policy.database.status.excludereadonly -Value 'TheBeard' Sets the value of the configuration for databases that are expected to be readonly to TheBeard .EXAMPLE Set-DbcConfig -Name agent.validjobowner.name -Value 'TheBeard\SQLJobOwner' -Append Adds 'TheBeard\SQLJobOwner' to the value of the configuration for accounts that are expected to be owners of SQL Agent Jobs .LINK https://dbachecks.readthedocs.io/en/latest/functions/Set-DbcConfig/ #> function Set-DbcConfig { [CmdletBinding(DefaultParameterSetName = "FullName", SupportsShouldProcess)] param ( [string]$Name, [AllowNull()] [AllowEmptyCollection()] [AllowEmptyString()] $Value, [System.Management.Automation.ScriptBlock]$Handler, [switch]$Append, [switch]$Temporary, [switch]$EnableException ) process { if (-not (Get-DbcConfig -Name $Name)) { Stop-PSFFunction -Message "Setting named $Name does not exist. If you'd like us to support an additional setting, please file a GitHub issue." return } if ($Append) { $NewValue = (Get-DbcConfigValue -Name $Name) # this is important to fix issue 535 # Need to process arrays correctly if ($NewValue -is [System.Array]) { if ($value -is [System.Array]) { $Value.ForEach{ $NewValue += $psitem } } else { $NewValue += $Value } } else { $NewValue = $NewValue, $Value } } else { $NewValue = $Value } $Name = $Name.ToLower() if ($PSCmdlet.ShouldProcess("$name" , "Setting the value to $NewValue on ")) { Set-PSFConfig -Module dbachecks -Name $name -Value $NewValue } try { if (-not $Temporary) { if ($PSCmdlet.ShouldProcess("$name" , "Registering PSFConfig ")) { Register-PSFConfig -FullName dbachecks.$name -EnableException -WarningAction SilentlyContinue } } } catch { if ($PSCmdlet.ShouldProcess("$Value" , "Setting PSFConfig $name ")) { Set-PSFConfig -Module dbachecks -Name $name -Value ($Value -join ", ") } if (-not $Temporary) { if ($PSCmdlet.ShouldProcess("$name" , "Registering PSFConfig ")) { Register-PSFConfig -FullName dbachecks.$name } } } # Still unsure if I'll persist it here - wondering if this impacts global or keeps local if ($name -eq 'app.sqlcredential') { if ($PSCmdlet.ShouldProcess("Variable" , "Setting PSDefaultParameterValues ")) { Set-Variable -Scope 1 -Name PSDefaultParameterValues -Value @{ '*:SqlCredential' = $value } } } $script:__dbcconfig = Get-DbcConfig $__dbcconfig | Where-Object {$_.Name -eq $name} } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUB+pGjuwY8gjEzNBHHh7Zv2+O # uD6gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQrYn6ZWaQ47KzOQwtdMBx2rmr2 # yzANBgkqhkiG9w0BAQEFAASCAQB4dlpQQs9z3Ts6k+zq/8jqs0Yd4LC2sqL3qoXF # bC5QbO5/yWN26ooPc1BCUbcrQZ0a9zz4NQDTEUzZsiqfJg1nh+rx/F1ElntfHIxy # yM2qeXl9zp89O6+/G4DwdFDK0xqj0NK1HBNbKlVWrPG52xlhPu8T/pmstk+H12Cb # UiyX/lnihNFctVVzk7d8Exy+k9NCI3zAgTd6Pnq0BHgz3TwaO4JmJi8LYJfxJxRZ # K6ARTFi8hqG6QRUAdfvBDabGzIdeGcs7OxDEMVZzGdtIxic7XUts9zCjcSRi5cjF # 7+H8HT8EBEwSuD8eka7wslOaYof8cv8KqN8mRMIWw5INikfl # SIG # End signature block ================================================ FILE: source/functions/Set-DbcFile.ps1 ================================================ <# .SYNOPSIS Writes the result of Invoke-DbcCheck to a file (after converting with Convert-DbcResult) .DESCRIPTION When a check has been run with Invoke-DbcCheck (and -PassThru) and then converted with Convert-DbcResult This command will write the results to a CSV, JSON or XML file .PARAMETER InputObject The datatable created by Convert-DbcResult .PARAMETER FilePath The directory for the file .PARAMETER FileName The name of the file .PARAMETER FileType The type of file -CSV,JSON,XML .PARAMETER Append Add to an existing file or not .PARAMETER Force Overwrite Existing file .EXAMPLE $Date = Get-Date -Format "yyyy-MM-dd" Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Set-DbcFile -FilePath C:\temp\dbachecks\ -FileName Auto-close_$Date -FileType xml Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and outputs to xml and saves in C:\temp\dbachecks\Auto-close_DATE.xml .EXAMPLE Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Set-DbcFile -FilePath C:\temp\dbachecks\ -FileName Auto-close.xml -FileType xml Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and outputs to xml and saves in C:\temp\dbachecks\Auto-close.xml .EXAMPLE Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Set-DbcFile -FilePath C:\temp\dbachecks\ -FileName Auto-close.csv -FileType csv Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and outputs to csv and saves in C:\temp\dbachecks\Auto-close.csv .EXAMPLE Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Set-DbcFile -FilePath C:\temp\dbachecks\ -FileName Auto-close.json -FileType Json Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and outputs to JSON and saves in C:\temp\dbachecks\Auto-close.json .EXAMPLE Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Set-DbcFile -FilePath C:\temp\dbachecks\ -FileName Auto-close.json -FileType Json -Append Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and outputs to JSON and saves in C:\temp\dbachecks\Auto-close.json appending the results to the existing file .EXAMPLE Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Set-DbcFile -FilePath C:\temp\dbachecks\ -FileName Auto-close.json -FileType Json -Force Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and outputs to JSON and saves in C:\temp\dbachecks\Auto-close.json overwriting the existing file .NOTES Initial - RMS 28/12/2019 #> function Set-DbcFile { [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = "Default")] [OutputType([string])] Param( # The pester results object [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'Default')] [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'Append')] [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'Force')] $InputObject, [Parameter(Mandatory = $true, ParameterSetName = 'Default')] [Parameter(Mandatory = $true, ParameterSetName = 'Append')] [Parameter(Mandatory = $true, ParameterSetName = 'Force')] # The Directory for the file [string]$FilePath, [Parameter(Mandatory = $true, ParameterSetName = 'Default')] [Parameter(Mandatory = $true, ParameterSetName = 'Append')] [Parameter(Mandatory = $true, ParameterSetName = 'Force')] # The name for the file [string]$FileName, # the type of file [Parameter(Mandatory = $true, ParameterSetName = 'Default')] [Parameter(Mandatory = $true, ParameterSetName = 'Append')] [Parameter(Mandatory = $true, ParameterSetName = 'Force')] [ValidateSet('Csv', 'Json', 'Xml')] [string]$FileType, # Appending [Parameter(Mandatory = $true, ParameterSetName = 'Append')] [switch]$Append, # Overwrite file [Parameter(Mandatory = $true, ParameterSetName = 'Force')] [switch]$Force ) Write-PSFMessage "Testing we have a Test Results object" -Level Verbose if(-not $InputObject){ Write-PSFMessage "Uh-Oh - I'm really sorry - We don't have a Test Results Object" -Level Significant Write-PSFMessage "Did You forget the -PassThru parameter on Invoke-DbcCheck?" -Level Warning Return '' } Write-PSFMessage "Testing we can access $FilePath" -Level Verbose If (Test-Path -Path $FilePath) { } else { Write-PSFMessage "Uh-Oh - We cant access $FilePath - Please check that $Env:USERNAME has access" -Level Significant Return '' } $File = "$FilePath\$FileName" Write-PSFMessage "Testing if $file exists" -Level Verbose if (Test-Path -Path $file) { if (!$Force -and !$Append) { Write-PSFMessage "Uh-Oh - File $File exists - use the Force parameter to overwrite (even if your name is not Luke!)" -Level Significant Return '' } else { if (-not $Append) { Write-PSFMessage "File $File exists and will be overwritten " -Level Verbose } } if ($Append) { if ($FileType -eq 'XML') { Write-PSFMessage "I'm not coding appending to XML - Sorry - The Beard loves you but not that much" -Level Significant Return '' } else { Write-PSFMessage "File $File exists and will be appended to " -Level Verbose } } } function Add-Extension { Param ($FileType) if(-not ($FileName.ToLower().EndsWith(".$FileType"))){ Write-PSFMessage "No Extension supplied so I will add .$FileType to $Filename" -Level Verbose $FileName = $FileName + '.' + $FileType } $File = "$FilePath\$FileName" $File } try { switch ($FileType) { 'CSV' { $file = Add-Extension -FileType csv if ($PSCmdlet.ShouldProcess("$File" , "Adding results to CSV")) { $InputObject | Select-Object * -ExcludeProperty ItemArray, Table, RowError, RowState, HasErrors | Export-Csv -Path $File -NoTypeInformation -Append:$Append } } 'Json' { $file = Add-Extension -FileType json if ($PSCmdlet.ShouldProcess("$File" , "Adding results to Json file")) { $Date = @{Name = 'Date'; Expression = {($_.Date).Tostring('MM/dd/yy HH:mm:ss')}} $InputObject | Select-Object $Date, Label,Describe,Context,Name,Database,ComputerName,Instance,Result,FailureMessage | ConvertTo-Json | Out-File -FilePath $File -Append:$Append } } 'Xml' { $file = Add-Extension -FileType xml if ($PSCmdlet.ShouldProcess("$File" , "Adding results to XML file ")) { $InputObject | Select-Object * -ExcludeProperty ItemArray, Table, RowError, RowState, HasErrors | Export-CliXml -Path $File -Force:$force } } } Write-PSFMessage "Exported results to $file" -Level Output } catch { Write-PSFMessage "Uh-Oh - We failed to create the file $file :-(" } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUx0zz6Opkgx1KL+StqytBCrq5 # dligggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRT+0vM2eNscCs7R1X6mnoonUzs # oDANBgkqhkiG9w0BAQEFAASCAQBON/45klZQGxL9/H9nr+X9Vo0ETLQitGU1aj+W # zO6f8l9KfBm5O4wgbkvtRkSjs+prqVB3BYjD0ejlEK3/ewD+cR7UZLJs6TqralA7 # DJPqsBk9Ssspkv8mgJqdG0r6sUxlhsVp7+UKXhc/ANhdV6Skb1MHxHht7kp6lIB7 # ZpEWC7jJ44Zj0/2sJd2KgbyoADaw3R2IxByORc3AN3z4qDanRpLtHFPuGGpQeB8X # R0sOcXUc0076gSlW6LUMN1mtcb69PaYVos2OfQhmqSM/p/QbHV4XiX8pzQAZoYi9 # nvilZTqD8lIeCshOCmiCZT9g9vtbI6KVNOO2U1I0aK6XAZg9 # SIG # End signature block ================================================ FILE: source/functions/Start-DbcPowerBi.ps1 ================================================ <# .SYNOPSIS Launches one of the included dbachecks Power BI dashboards either the original for json files or the new one for database. **You will need refresh* the Power BI dashboard every time to see the new results! .DESCRIPTION Launches one of the included dbachecks Power BI dashboards either the original for json files or the new one for database.**You will need refresh* the Power BI dashboard every time to see the new results. .PARAMETER FromDatabase A Switch to use to open the database based PowerBi dashboard if you have stored the results in a database with Write-DbcTable. If not chosen it will use the original Power Bi file with a json data source .PARAMETER Path The location of the pbix or pbit file if you have moved it or want to use your own. "$script:ModuleRoot\bin\dbachecks.pbix" or "$script:ModuleRoot\bin\dbachecks-FromDatabase.pbit" by default. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .EXAMPLE Start-DbcPowerBi -FromDatabase Launches the Database Power Bi dashboard template, which will prompt for the Instance and database name .EXAMPLE Start-DbcPowerBi Launches the Json PowerBi from "$script:ModuleRoot\bin\dbachecks.pbix" using "C:\windows\Temp\dbachecks\*.json" (generated by Update-DbcPowerBiDataSource) as the datasource. .EXAMPLE Start-DbcPowerBi -Path \\nas\projects\dbachecks.pbix Launches \\nas\projects\dbachecks.pbix using "C:\windows\Temp\dbachecks\*.json" as the datasource .LINK https://dbachecks.readthedocs.io/en/latest/functions/Start-DbcPowerBi/ #> function Start-DbcPowerBi { [CmdletBinding(SupportsShouldProcess)] param ( [switch]$FromDatabase, [string]$Path, [switch]$EnableException ) process { if ($IsLinux) { Write-PSFMessage "We cannot run this command from linux at the moment" -Level Warning Return } else { if (-not $FromDatabase) { if (-not $Path) { $Path = "$script:ModuleRoot\bin\dbachecks.pbix" $newpath = "$script:localapp\dbachecks.pbix" $dirPath = "$Path\dbachecks.pbix" } } else { $Path = "$script:ModuleRoot\bin\dbachecks-FromDatabase.pbit" $newpath = "$script:localapp\dbachecks-FromDatabase.pbit" $DirPath = "$Path\dbachecks-FromDatabase.pbit" } if (Test-Path -Path $Path -PathType Container) { $Path = $DirPath Write-PSFMessage -Level Output -Message "Path passed in, appending file name to it." Write-PSFMessage -Level Output -Message "New path: $path" } if ($PSCmdlet.ShouldProcess("$newpath" , "Copying the file $path to ")) { try { Copy-Item -Path $Path -Destination $newpath -Force $Path = $newpath } catch { Stop-PSFFunction -Message "Failed Copying file" -ErrorRecord $_ return } } if (-not (Test-Path -Path $Path)) { Stop-PSFFunction -Message "$Path does not exist" return } try { Write-PSFMessage -Level Output -Message "Launching the dbachecks dashboard. This may take a moment." if ($PSCmdlet.ShouldProcess("$path" , "Starting PowerBi Desktop with file ")) { Invoke-Item -Path $path } } catch { Stop-PSFFunction -Message "Failure" -ErrorRecord $_ return } } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUetPRa6cC+Lkp6zDM+2AcTRnx # 6/6gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTR0ru8ENca5qKO8X5SWqRx6fYq # cjANBgkqhkiG9w0BAQEFAASCAQAwwGUB6ecdeKPSBRiTBR2dmdmeOBaZ0uhkLLfI # wrdFWhh1ybh1ieo5duo49S1ANx0fFeNULaFAuM1BHGQAVdAH6OLhEeg3NHTm+D+F # eFK9zLhbmexEOTGTtBjbwdX0KgHqfsyJVsr6Q5jhO8SeMoMxFT/SaP5CARt0JZwr # ip62S3xAxMC5ApLfxiAXhBjFMYo5K2TKWjnnTzRu/j2+jXWhLQ3NHzMF5e5x7Isp # RvOcnjLWH3/egC0hEk70j0qbgjW81JVqCYn9JwG+JGY14FqP3mkwqKKaWtpFs3Vz # XK2berv/8siVaV7feCoPZUi46FkCeXsWwSgR0y0JaccdNMxj # SIG # End signature block ================================================ FILE: source/functions/Update-DbcPowerBiDataSource.ps1 ================================================ <# .SYNOPSIS Converts Pester results and exports file in required format for launching the Power BI command. **You will need refresh* the Power BI dashboard every time to see the new results. .DESCRIPTION Converts Pester results and exports file in required format for launching the Power BI command. **You will need refresh* the Power BI dashboard every time to see the new results. Basically, it does this: $InputObject.TestResult | Select-Object -First 20 | ConvertTo-Json -Depth 3 | Out-File "$env:windir\temp\dbachecks.json" .PARAMETER InputObject Required. Resultset from Invoke-DbcCheck. If InputObject is not provided, it will be generated using a very generic resultset: .PARAMETER Path The directory to store your JSON files. "C:\windows\temp\dbachecks\*.json" by default .PARAMETER FileName if you want to give the file a specific name .PARAMETER Environment A Name to give your suite of tests IE Prod - This will also alter the name of the file .PARAMETER Force Delete all json files in the data source folder. .PARAMETER Append Appends results to existing file. Use this if you have custom check repos .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .EXAMPLE Invoke-DbcCheck -SqlInstance $Instance -Check DatabaseStatus -Show None -PassThru | Update-DbcPowerBiDataSource Runs the DatabaseStatus checks against $Instance then saves to json to $env:windir\temp\dbachecks\dbachecks_1_DatabaseStatus.json .EXAMPLE Invoke-DbcCheck -SqlInstance $Instance -Check DatabaseStatus -Show None -PassThru | Update-DbcPowerBiDataSource -Path C:\Temp Runs the DatabaseStatus checks against $Instance then saves to json to C:\Temp\dbachecks_1_DatabaseStatus.json .EXAMPLE Invoke-DbcCheck -SqlInstance $Instance -Check DatabaseStatus -Show None -PassThru | Update-DbcPowerBiDataSource -Path C:\Temp -FileName BeardyTests Runs the DatabaseStatus checks against $Instance then saves to json to C:\Temp\BeardyTests.json .EXAMPLE Invoke-DbcCheck -SqlInstance $Instance -Check DatabaseStatus -Show None -PassThru | Update-DbcPowerBiDataSource -Path C:\Temp -FileName BeardyTests.json Runs the DatabaseStatus checks against $Instance then saves to json to C:\Temp\BeardyTests.json .EXAMPLE Invoke-DbcCheck -SqlInstance $Instance -Check DatabaseStatus -Show None -PassThru | Update-DbcPowerBiDataSource -Path C:\Temp -Environment Prod_DBChecks Runs the DatabaseStatus checks against $Instance then saves to json to C:\Temp\dbachecks_1_Prod_DBChecks_DatabaseStatus.json .EXAMPLE Invoke-DbcCheck -SqlInstance $Instance -Check DatabaseStatus -Show None -PassThru | Update-DbcPowerBiDataSource -Environment Prod_DBChecks Runs the DatabaseStatus checks against $Instance then saves to json to C:\Windows\temp\dbachecks\dbachecks_1_Prod_DBChecks_DatabaseStatus.json .EXAMPLE Invoke-DbcCheck -SqlInstance sql2017 -Tag Backup -Show Summary -PassThru | Update-DbcPowerBiDataSource -Path \\nas\projects\dbachecks.json Start-DbcPowerBi -Path \\nas\projects\dbachecks.json Runs tests, saves to json to \\nas\projects\dbachecks.json Opens the PowerBi using that file then you'll have to change your data source in Power BI because by default it points to C:\Windows\Temp (limitation of Power BI) .EXAMPLE Set-DbcConfig -Name app.checkrepos -Value \\SharedPath\CustomPesterChecks Invoke-DbcCheck -SqlInstance $Instance -Check DatabaseStatus, CustomCheckTag -PassThru | Update-DbcPowerBiDataSource -Path \\SharedPath\CheckResults -Name CustomCheckResults -Append Because we are using a custom check repository you MUSTR use the Append parameter for Update-DbcPowerBiDataSource otherwise the json file will be overwritten Sets the custom check repository to \\SharedPath\CustomPesterChecks Runs the DatabaseStatus checks and custom checks with the CustomCheckTag against $Instance then saves all the results to json to \\SharedPath\CheckResults.json -Name CustomCheckResults .EXAMPLE Invoke-DbcCheck -SqlInstance sql2017 -Check SuspectPage -Show None -PassThru | Update-DbcPowerBiDataSource -Environment Test -Whatif What if: Performing the operation "Removing .json files named *Default*" on target "C:\Windows\temp\dbachecks". What if: Performing the operation "Passing results" on target "C:\Windows\temp\dbachecks\dbachecks_1_Test__SuspectPage.json". Will not actually create or update the data sources but will output what happens with the command and what the file name will be called. .LINK https://dbachecks.readthedocs.io/en/latest/functions/Update-DbcPowerBiDataSource/ #> function Update-DbcPowerBiDataSource { [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] param ( [parameter(ValueFromPipeline, Mandatory)] [pscustomobject]$InputObject, [string]$Path = "$env:windir\temp\dbachecks", [string]$FileName, [string]$Environment = "Default", [switch]$Force, [switch]$EnableException, [switch]$Append ) begin { Write-PSFMessage "Starting begin block" -Level Debug if ($IsLinux -and $Path -eq '\temp\dbachecks') { Write-PSFMessage "Setting path on Linux" -Level Verbose $Path = Get-DbcConfigValue -Name app.localapp Write-PSFMessage "Setting path on Linux to $Path" -Level Verbose } if ($Force) { if ($PSCmdlet.ShouldProcess($Path, 'Removing all .json files')) { try { $null = Remove-Item "$Path\*.json" -ErrorAction Stop Write-PSFMessage "Removed all files from $Path" -Level Verbose } catch { Stop-PSFFunction -Message "FAILED - Removing all files from $Path" -ErrorRecord $_ return } } } } process { ++$i try { if (-not (Test-Path -Path $Path)) { if ($PSCmdlet.ShouldProcess($Path, 'Creating new directory')) { $null = New-Item -ItemType Directory -Path $Path -ErrorAction Stop Write-PSFMessage "Created New Directory $Path" -Level Verbose } } } catch { Stop-PSFFunction -Message "Failed - Creating New Directory $Path" -ErrorRecord $_ return } $basename = "dbachecks_$i" if ($Environment) { $basename = "dbachecks_$i" + "_$Environment`_" } if ($FileName) { $basename = $FileName } else { if ($InputObject.TagFilter) { $tagnames = $InputObject.TagFilter[0..3] -join "_" $basename = "$basename`_" + $tagnames + ".json" } } if ($basename.EndsWith('.json')) {} else { $basename = $basename + ".json" } Write-PSFMessage "Set basename to $basename" -Level Verbose $FilePath = "$Path\$basename" Write-PSFMessage "Set filepath to $FilePath" -Level Verbose if ($InputObject.TotalCount -gt 0) { try { if ($PSCmdlet.ShouldProcess($FilePath, 'Passing results')) { if ($Append) { $InputObject.TestResult | ConvertTo-Json -Depth 5 | Out-File -FilePath $FilePath -Append Write-PSFMessage -Level Output -Message "Appended results to $FilePath" } else { $InputObject.TestResult | ConvertTo-Json -Depth 5 | Out-File -FilePath $FilePath Write-PSFMessage -Level Output -Message "Wrote results to $FilePath" } } } catch { Stop-PSFFunction -Message "Failed Passing Results to $FilePath" -ErrorRecord $_ return } } } end { if ($InputObject.TotalCount -isnot [int]) { Stop-PSFFunction -Message "Invalid TestResult. Did you forget to use -Passthru with Invoke-DbcCheck?" return } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUGad1N8rU46XXXiQXKctuXhy8 # qU+gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBS4q3UVKZeERragHnuZtyhulEMh # bzANBgkqhkiG9w0BAQEFAASCAQAIpU2w6E5wragmblIeHZRlZJ6NqOV9e0EgZdHF # hoKR+j4CBEZ2Jo0MF66siC0iQdR6amo0TNYsxo6L80ygxIrj7P6KoT3sOdzcJ0/3 # BpoyUbC8rFhA9SVxtbe3CFCj4nSBsboeLLym+plBpHYaeLKnN5E+vpuXIfkh63We # 3ovKaMAADLihQb5SU0gBndsg0xzfcinv+YtMVCmEK8TRAT5bw+tjLOgBDUFVeyz1 # x9w4cyvk6mhqW4PZDT42B2/79RPCMWifysVJ2t7sdLIkBByuQVhTFjJTQKwS6m3Y # OFwAm2rDk9l/2PuM406qXN0duVr4udpy3RMs+hXrWNa2477m # SIG # End signature block ================================================ FILE: source/functions/Update-DbcRequiredModules.ps1 ================================================ <# .SYNOPSIS Updates all required modules, including dbachecks. .DESCRIPTION Updates all required modules, including dbachecks. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. .EXAMPLE Update-DbcRequiredModules Updates all required modules including dbachecks .EXAMPLE Update-DbcRequiredModules -Verbose Updates all required modules including dbachecks and shows verbose output .LINK https://dbachecks.readthedocs.io/en/latest/functions/Update-DbcRequiredModules/ #> function Update-DbcRequiredModules { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param ( [switch]$EnableException ) $ModuleManifest = Import-PowerShellDataFile -Path "$script:ModuleRoot\dbachecks.psd1" foreach ($Module in $ModuleManifest.RequiredModules) { if ($pscmdlet.ShouldProcess("Install $($Module.ModuleName) version $($Module.ModuleVersion) from repository")) { try { Write-PSFMessage -Level Output -Message "Updating $($Module.ModuleName)" Update-Module -Name $Module.ModuleName -ErrorAction Stop } catch { Stop-PSFFunction -Message 'Failure' -ErrorRecord $_ } } } if ($pscmdlet.ShouldProcess('Install latest dbachecks from repository')) { try { Write-PSFMessage -Level Output -Message 'Updating dbachecks' Update-Module -Name dbachecks -ErrorAction Stop } catch { Stop-PSFFunction -Message 'Failure' -ErrorRecord $_ } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU3O0s7r5f5VpOyPjtA6dU3AYd # FSagggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRidFA1SR73rHOFByuQwAKq+HEH # YDANBgkqhkiG9w0BAQEFAASCAQBndiYH7StZTbAH7wsHeZgeyp/O+9J7Kul884Um # tBfBprG/Stj8p3PjxVHBARqEKdY+MHIA293Sfx6aokftJzKR5orDAm5SUVIwXvVV # zyRdnUB+tohNrrO/o0fBExr13XsXKnk8XhmZ1VzRa6FKpbeS1KnRbjxhzh0lwgZF # i0gdf/QWxszaDdYxxHICdB2AmpQy+sWuxhfqDzXluJXFagEiIGV3EWKt9/kNff9u # U6pMqyS2g8TIOqJve0obtSUSWjPy35e9ji26SglAliO+fkgtVYDP/D7fhHybobPW # nNerOskuKkkfHpdUCx5fW6Ft9G6Wy1OxDe/h6t3VdoJ6/pCz # SIG # End signature block ================================================ FILE: source/functions/Write-DbcTable.ps1 ================================================ <# .SYNOPSIS Writes the result of Invoke-DbcCheck (with -PassThru) after Convert-DbcResult to a database table .DESCRIPTION After running Invoke-DbcCheck (With PassThru) and converting it to a datatable with Convert-DbcResult, this command will write the results to a database table and will also write the current Checks to another table called dbachecksChecks .PARAMETER SqlInstance The Instance for the results .PARAMETER SqlCredential The SQL Credential for the instance if required .PARAMETER Database The database to write the results .PARAMETER InputObject The datatable from Convert-DbcResult .PARAMETER Table The name of the table for the results - will be created if it doesn't exist. By default it will be named CheckResults .PARAMETER Schema The schema for the table - defaults to dbo .PARAMETER Truncate Will truncate the existing table (if results go to a staging table for example) .EXAMPLE Invoke-DbcCheck -SqlInstance SQL2017N5 -Check AutoClose -Passthru | Convert-DbcResult -Label Beard-Check | Write-DbcTable -SqlInstance DbaInstance -Database dbadatabase Runs the AutoClose check against SQL2017N5 and converts to a datatable with a label of Beard-Check and writes it to the dbadatabase on DbaInstance .EXAMPLE Import-DbcConfig -Path \\share\ProdMorningChecks.json Invoke-DbcCheck -SqlInstance $ProdSqlInstances -Passthru | Convert-DbcResult -Label Prod-Morning-Check | Write-DbcTable -SqlInstance DbaInstance -Database dbadatabase Loads the Prod Morning Checks Configuration and runs the checks against the SQL Instances converts to a datatable with a label of Prod-Morning-Check and writes it to the dbadatabase on DbaInstance .NOTES Initial - RMS 28/12/2019 #> function Write-DbcTable { [CmdletBinding(SupportsShouldProcess)] [OutputType([string])] Param( [Parameter(Mandatory)] [ValidateNotNull()] [string]$SqlInstance, [ValidateNotNull()] [PSCredential]$SqlCredential, [object]$Database, [Parameter(Mandatory, ValueFromPipeline)] # The pester results object [ValidateNotNull()] [object]$InputObject, [ValidateNotNullOrEmpty()] [string]$Table = 'CheckResults', [ValidateNotNullOrEmpty()] [string]$Schema = 'dbo', [switch]$Truncate ) Write-PSFMessage 'Testing we have a Test Results object' -Level Verbose if (-not $InputObject) { Write-PSFMessage "Uh-Oh - I'm really sorry - We don't have a Test Results Object" -Level Significant Write-PSFMessage 'Did You forget the -PassThru parameter on Invoke-DbcCheck?' -Level Warning Return '' } Write-PSFMessage "Connecting to $SqlInstance" -Level Verbose $SqlInstanceSmo = Connect-DbaInstance -SqlInstance $SqlInstance -SqlCredential $SqlCredential Write-PSFMessage "Checking for dbachecks table in $Database" -Level Verbose if (Get-DbaDbTable -SqlInstance $SqlInstanceSmo -Database $Database -Table dbachecksChecks) { if ($PSCmdlet.ShouldProcess("$schema.$database" , "On $SqlInstance - Update the dbachecksChecks tables ")) { Get-DbcCheck | Write-DbaDbTableData -SqlInstance $SqlInstanceSmo -Database $Database -Table dbachecksChecks -Schema $Schema -AutoCreateTable -Truncate } } else { if ($PSCmdlet.ShouldProcess("$schema.$database" , "On $SqlInstance - Add the dbachecksChecks tables ")) { Get-DbcCheck | Write-DbaDbTableData -SqlInstance $SqlInstanceSmo -Database $Database -Table dbachecksChecks -Schema $Schema -AutoCreateTable } } Write-PSFMessage "Checking for $Table in $Database" -Level Verbose if (Get-DbaDbTable -SqlInstance $SqlInstanceSmo -Database $Database -Table $Table) { Write-PSFMessage "We have $table already - moving on." -Level Verbose } else { if ($PSCmdlet.ShouldProcess("$schema.$database" , "Create a new table called $table ")) { # If specified table does not exists, create with specific datatypes to avoid nvarchar(max) $sqlTableCreation = @" CREATE TABLE [$schema].[$table]( [Date] [datetime2](7) NOT NULL, [Label] [nvarchar](255) NULL, [Describe] [nvarchar](255) NULL, [Context] [nvarchar](255) NULL, [Name] [nvarchar](600) NULL, [Database] [nvarchar](255) NULL, [ComputerName] [nvarchar](255) NULL, [Instance] [nvarchar](255) NULL, [Result] [nvarchar](10) NULL, [FailureMessage] [nvarchar](MAX) NULL ) ON [PRIMARY] GO CREATE CLUSTERED INDEX CI_DATE ON [$schema].[$table] ( [Date] ) WITH (DATA_COMPRESSION = PAGE) ON [PRIMARY] GO "@ Invoke-DbaQuery -SqlInstance $SqlInstanceSmo -Database $Database -Query $sqlTableCreation } } if ($PSCmdlet.ShouldProcess("$Schema.$database" , "On $SqlInstance - Add dbachecks results to $Table ")) { $InputObject | Write-DbaDbTableData -SqlInstance $SqlInstanceSmo -Database $Database -Table $Table -Schema $Schema -AutoCreateTable -Truncate:$Truncate } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUegYAffTRCI+hKr04nGgnT1lL # /aSgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRBq4Yyaxo2ZihLKGHzCApV8wzN # YjANBgkqhkiG9w0BAQEFAASCAQBW1PSNLI/Kl12udbU1Q3TV2LOSD+EEC5wEWn9X # Qx5l89esW1UwckAZO6SG6ItrqOATPXAU7W6EgP/QwH9BaigjdRAeI6Yeym4sDM8h # 8jV8YPoMJXylEkgSsjZXeF66vu8Euk5WakE1tXfAsfYUumU/TRGo15yfNSqvkMdh # U+M84XXiNVMHlu+0MPtvnxI9PoXUuB4lBsafjjmEkoqmVsl/Y2zn2zoZkDuly/DY # vvau3Pl873m1ek2U7PtvBWuf2hTsWMIJWP2w9vlr5Kv1OSluBbsbSNdlDOlXYRSF # 0WiID26B/9duWJDW0WOyp35+uztj0ZRghn4L6v7Xr+mmAx+y # SIG # End signature block ================================================ FILE: source/internal/assertions/Agent.Assertions.ps1 ================================================ function Assert-DatabaseMailEnabled { param ( $SQLInstance, $DatabaseMailEnabled ) (Get-DbaSpConfigure -SqlInstance $SQLInstance -Name DatabaseMailEnabled).ConfiguredValue -eq 1 | Should -Be $DatabaseMailEnabled -Because 'The Database Mail XPs setting should be set correctly' } function Assert-JobHistoryRowsDisabled { param ( $AgentServer, $minimumJobHistoryRows ) $AgentServer.MaximumHistoryRows | Should -Be $minimumJobHistoryRows -Because "Maximum job history configuration should be disabled" } function Assert-JobHistoryRows { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param ( $AgentServer, $minimumJobHistoryRows ) $AgentServer.MaximumHistoryRows | Should -BeGreaterOrEqual $minimumJobHistoryRows -Because "We expect the maximum job history row configuration to be greater than the configured setting $minimumJobHistoryRows" } function Assert-JobHistoryRowsPerJob { param ( $AgentServer, $minimumJobHistoryRowsPerJob ) $AgentServer.MaximumJobHistoryRows | Should -BeGreaterOrEqual $minimumJobHistoryRowsPerJob -Because "We expect the maximum job history row configuration per agent job to be greater than the configured setting $minimumJobHistoryRowsPerJob" } function Assert-LongRunningJobs { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] Param($runningjob,$runningjobpercentage) [math]::Round($runningjob.Diff/$runningjob.AvgSec * 100) | Should -BeLessThan $runningjobpercentage -Because "The current running job $($runningjob.JobName) has been running for $($runningjob.Diff) seconds longer than the average run time. This is more than the $runningjobpercentage % specified as the maximum" } function Assert-LastJobRun { Param($lastagentjobrun,$runningjobpercentage) [math]::Round($lastagentjobrun.Diff/$lastagentjobrun.AvgSec * 100) | Should -BeLessThan $runningjobpercentage -Because "The last run of job $($lastagentjobrun.JobName) was $($lastagentjobrun.duration) seconds. This is more than the $runningjobpercentage % specified as the maximum variance" } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUVZqV3+yZ6FjNVJ1E7tFvdy58 # lIigggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRoWuosjY1u/VfrwujfwyttmErx # OjANBgkqhkiG9w0BAQEFAASCAQBfgfUgzByfZTVJ3/JPq9O9sH0758DCD4s3Q+Ly # Y0ODtMT7nXi8UiHfKerKIL8RAGtrB++u3EDU2r7bNnfB0MVE9qhTZRYs78xAMx55 # 4v79veO1cA4FZl5ZZOMegzxly/jl5XxVpqH/aaplblszPSi6CMIj1bkuoscvDhSD # qnTVDNhcaJVFoDuYlNKHTXFT11zjpingAruD5Xe7I9bsIS+IyoxWi3loUGLlcxoq # EADepMg8uyzm7u9rebPr4GiQ0dTsrF0vWSf9/O4PsZ0lOPswflZXZ9M1DUdfth0A # YUrxnWePqL3uc/ICL5PXcMKpSAbRJghtQMT6AnCth6ekbyiu # SIG # End signature block ================================================ FILE: source/internal/assertions/Database.Assertions.ps1 ================================================ function Get-Database { Param( [string]$Instance, [string[]]$ExcludedDbs, [string[]]$Database, [ValidateSet('Name')] [string]$Requiredinfo, [ValidateSet('NotAccessible')] [string]$Exclusions ) switch ($Exclusions) { NotAccessible { $dbs = (Connect-DbaInstance -SqlInstance $Instance).Databases.Where{$(if($database){$PsItem.Name -in $Database}else{$ExcludedDbs -notcontains $PsItem.Name}) -and $psitem.IsAccessible -eq $true} } Default { $dbs = (Connect-DbaInstance -SqlInstance $Instance).Databases.Where{$(if($database){$PsItem.Name -in $Database}else{$ExcludedDbs -notcontains $PsItem.Name})} } } switch ($Requiredinfo) { Name { $dbs.Name} Default {} } } function Assert-DatabaseMaxDop { Param( [pscustomobject]$MaxDop, [int]$MaxDopValue ) $MaxDop.DatabaseMaxDop | Should -Be $MaxDopValue -Because "We expect the Database MaxDop Value to be the specified value $MaxDopValue" } function Assert-DatabaseStatus { Param( [string]$instance, [string[]]$Database, [string[]]$Excludedbs, [string[]]$ExcludeReadOnly, [string[]]$ExcludeOffline, [string[]]$ExcludeRestoring ) if($Database){ $results = @((Connect-DbaInstance -SqlInstance $Instance).Databases.Where{$psitem.Name -in $Database -and $psitem.Name -notin $Excludedbs} | Select-Object Name, Status, Readonly, IsDatabaseSnapshot) } else{ $results = @((Connect-DbaInstance -SqlInstance $Instance).Databases.Where{$psitem.Name -notin $Excludedbs} | Select-Object Name, Status, Readonly, IsDatabaseSnapshot) } $results.Where{$_.Name -notin $ExcludeReadOnly -and $_.IsDatabaseSnapshot -eq $false}.Readonly | Should -Not -Contain True -Because "We expect that there will be no Read-Only databases except for those specified" $results.Where{$_.Name -notin $ExcludeOffline}.Status | Should -Not -Match 'Offline' -Because "We expect that there will be no offline databases except for those specified" $results.Where{$_.Name -notin $ExcludeRestoring}.Status | Should -Not -Match 'Restoring' -Because "We expect that there will be no databases in a restoring state except for those specified" $results.Where{$_.Name -notin $ExcludeOffline}.Status | Should -Not -Match 'AutoClosed' -Because "We expect that there will be no databases that have been auto closed" $results.Status | Should -Not -Match 'Recover' -Because "We expect that there will be no databases going through the recovery process or in a recovery pending state" $results.Status | Should -Not -Match 'Emergency' -Because "We expect that there will be no databases in EmergencyMode" $results.Status | Should -Not -Match 'Standby' -Because "We expect that there will be no databases in Standby" $results.Status | Should -Not -Match 'Suspect' -Because "We expect that there will be no databases in a Suspect state" } function Assert-DatabaseDuplicateIndex { Param( [string]$instance, [string]$Database ) @(Find-DbaDbDuplicateIndex -SqlInstance $Instance -Database $Database).Count | Should -Be 0 -Because "Duplicate indexes waste disk space and cost you extra IO, CPU, and Memory - Use Find-DbaDbDuplicateIndex to find them" } function Assert-DatabaseExists { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] Param ( [string]$Instance, [string]$ExpectedDB ) $Actual = Get-Database -Instance $instance -Requiredinfo Name $Actual | Should -Contain $expecteddb -Because "We expect $expecteddb to be on $Instance" } function Assert-GuestUserConnect { Param ( [string]$Instance, [string]$Database ) $guestperms = Get-DbaUserPermission -SqlInstance $Instance -Database $Database | Where-Object {$_.Grantee -eq "guest" -and $_.Permission -eq "CONNECT"} $guestperms.Count | Should -Be 0 -Because "We expect the guest user in $Database on $Instance to not have CONNECT permissions" } function Assert-CLRAssembliesSafe { Param ( [string]$Instance, [string]$Database ) @(Get-DbaDbAssembly -SqlInstance $Instance -Database $Database | Where-Object {$_.IsSystemObject -eq $false -and $_.SecurityLevel -ne "Safe" -and $_.Database -ne "SSISDB" -and $_.Name -ne "ISSERVER"}).Count | Should -Be 0 -Because "We expect CLR Assemblies to operate in the SAFE permission set" } function Assert-AsymmetricKeySize { Param ( [string]$Instance, [string]$Database ) @(Get-DbaDbEncryption -SqlInstance $Instance -Database $Database | Where-Object {$_.Encryption -eq "Asymmetric Key" -and $_.KeyLength -LT 2048}).Count | Should -Be 0 -Because "Asymmetric keys should have a key length greater than or equal to 2048" } function Assert-SymmetricKeyEncryptionLevel { Param ( [string]$Instance, [string]$Database ) @(Get-DbaDbEncryption -SqlInstance $Instance -Database $Database | Where-Object {$_.Encryption -eq "Symmetric Key" -and $_.EncryptionAlgrothim -notin "AES_128","AES_192","AES_256"}).Count | Should -Be 0 -Because "Symmetric keys should have an encryption algrothim of at least AES_128" } function Assert-QueryStoreEnabled { Param ( [string]$Instance, [string]$Database ) (Get-DbaDbQueryStoreOption -SqlInstance $Instance -Database $Database).ActualState | Should -Not -BeIn 'OFF', 'ERROR' -Because "We expect the Query Store to be enabled in $Database on $Instance" } function Assert-QueryStoreDisabled { Param ( [string]$Instance, [string]$Database ) (Get-DbaDbQueryStoreOption -SqlInstance $Instance -Database $Database).ActualState | Should -Be 'OFF' -Because "We expect the Query Store to be disabled in $Database on $Instance" } function Assert-ContainedDBSQLAuth { Param ( [string]$Instance, [string]$Database ) @(Get-DbaDbUser -SQLInstance $Instance -Database $Database | Where-Object {$_.LoginType -eq "SqlLogin" -and $_.HasDbAccess -eq $true}).Count | Should -Be 0 -Because "We expect there to be no sql authenticated users in contained database $Database on $Instance" } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUWV5eEvZUineXnauPcBDvBW6K # wHygggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQw7LZnAhvpN+sY8bINEHrOjzii # mjANBgkqhkiG9w0BAQEFAASCAQBtnx2QeSl3A26bXXoAwf1wkKsetkHTJzjC642v # cbrVffim+MKWNRICLZx0KLyWe5bEdOadY1GgFEaYRPeaVCFMJopNL4uJfnJ1GoBw # zZrDQaSf5hUlrQvETMtoCnX8+65eJQECAkV87LsJckC5P8F2P+iC1uDbeKGVFw3C # ncii3LHqlzx0KuRk+Y6wYcIAjAACr2/tyXxdl1rCBG3xg8XJRssQ1NfVs6W50sBz # Ql42LSzBWaaCjcyGC8optFyIQd+5vJ2KiL8MuAjuOZvd5TvzY0MXOaLohlnz5qEP # V/1CKLtRyNRyQvxgrIQlGNe5Ei//V/v44mzD8in3dsL2cGZS # SIG # End signature block ================================================ FILE: source/internal/assertions/Instance.Assertions.ps1 ================================================ <# This file is used to hold the Assertions for the Instance.Tests When adding new checks or improving existing ones - - Ensure your branch is up to date with the development branch - In the Instance.Assertions.ps1 - Add a New code block in the switch using the unique tag name 'MemoryDump' { # This is the unique tag if ($There) { ## we need $There to save trying to gather information from later checks for an instance that is not contactable ## Then a try catch to gather the required information for the assertion and set a variable to a custom object try { $MaxDump = [pscustomobject] @{ # Warning Action removes dbatools output for version too low from test results # Skip on the it will show in the results Count = (Get-DbaDump -SqlInstance $psitem -WarningAction SilentlyContinue).Count } } # In the catch set There to false and create an object with the same name but an obvious error entry catch { $There = $false $MaxDump = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } # the else matches the catch block else { $There = $false $MaxDump = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } - Create an Assertion for the Check Name must start Assert function Assert-MaxDump { Pass in params for configs Param($AllInstanceInfo,$maxdumps) Ensure Because has good information $AllInstanceInfo.MaxDump.Count | Should -BeLessThan $maxdumps -Because "We expected less than $maxdumps dumps but found $($AllInstanceInfo.MaxDump.Count). Memory dumps often suggest issues with the SQL Server instance" } - In The Instance.Tests.ps1 file create the check # Must be in its own describe block, must use an s on Tags, first tag must be unique, last tag must be $filename Describe "SQL Memory Dumps" -Tags MemoryDump, Medium, $filename { # Gather any config items here so that the code to match config to check works $maxdumps = Get-DbcConfigValue policy.dump.maxcount # We check if the instance is contactable at the top of the file, use this block with the context title the same as the proper test below if ($NotContactable -contains $psitem) { Context "Checking that dumps on $psitem do not exceed $maxdumps for $psitem" { It "Can't Connect to $Psitem" { $false | Should -BeTrue -Because "The instance should be available to be connected to!" } } } else { # The title must end $psitem Context "Checking that dumps on $psitem do not exceed $maxdumps for $psitem" { # The check itself - a skip can be added from a config value if required -Skip:$Skip or per version It "dump count of $count is less than or equal to the $maxdumps dumps on $psitem" -Skip:($InstanceSMO.Version.Major -lt 10 ) { # Call the assertion with any parameters here Assert-MaxDump -AllInstanceInfo $AllInstanceInfo -maxdumps $maxdumps } } } } - In the tests\checks\InstanceChecks.Tests.ps1 file add tests for the assertions by mocking passing and failing tests following the code in the file - In a NEW session - checkout your branch of dbachecks cd to the root of the repo import the module with ipmo .\dbachecks.psd1 Run the Pester tests Invoke-Pester .\tests\ -ExcludeTag Integration -Show Fails It starts with the Get-AllInstanceInfo which uses all of the unique tags that have been passed and gathers the required information which can then be used for the assertions. The long term aim is to make Get-AllInstanceInfo as performant as possible and to cover all of the tests #> function Get-AllInstanceInfo { # Using the unique tags gather the information required Param($Instance, $Tags, $There) # Using there so that if the instance is not contactable, no point carrying on with gathering more information switch ($tags) { 'ErrorLog' { if ($There) { try { $logWindow = Get-DbcConfigValue -Name policy.errorlog.warningwindow # so that it can be mocked function Get-ErrorLogEntry { # get the number of the first error log that was created after the log window config $OldestErrorLogNumber = ($InstanceSMO.EnumErrorLogs() | Where-Object { $psitem.CreateDate -gt (Get-Date).AddDays( - $LogWindow) } | Sort-Object ArchiveNo -Descending | Select-Object -First 1).ArchiveNo + 1 # Get the Error Log entries for each one (0..$OldestErrorLogNumber).ForEach{ $InstanceSMO.ReadErrorLog($psitem).Where{ $_.Text -match "Severity: 1[7-9]|Severity: 2[0-4]" } } } # It is not enough to check the CreateDate on the log, you must check the LogDate on every error record as well. $ErrorLog = @(Get-ErrorLogEntry).ForEach{ [PSCustomObject]@{ LogDate = $psitem.LogDate ProcessInfo = $Psitem.ProcessInfo Text = $Psitem.Text } | Where-Object { $psitem.LogDate -gt (Get-Date).AddDays( - $LogWindow) } } } catch { $There = $false $ErrorLog = [PSCustomObject]@{ LogDate = 'Do not know the Date' ProcessInfo = 'Do not know the Process' Text = 'Do not know the Test' InstanceName = 'An Error occurred ' + $Instance } } } else { $There = $false $ErrorLog = [PSCustomObject]@{ LogDate = 'Do not know the Date' ProcessInfo = 'Do not know the Process' Text = 'Do not know the Test' InstanceName = 'An Error occurred ' + $Instance } } } 'DefaultTrace' { if ($There) { try { $SpConfig = Get-DbaSpConfigure -SqlInstance $Instance -ConfigName 'DefaultTraceEnabled' $DefaultTrace = [pscustomobject] @{ ConfiguredValue = $SpConfig.ConfiguredValue } } catch { $There = $false $DefaultTrace = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } else { $There = $false $DefaultTrace = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } 'OleAutomationProceduresDisabled' { if ($There) { try { $SpConfig = Get-DbaSpConfigure -SqlInstance $Instance -ConfigName 'OleAutomationProceduresEnabled' $OleAutomationProceduresDisabled = [pscustomobject] @{ ConfiguredValue = $SpConfig.ConfiguredValue } } catch { $There = $false $OleAutomationProceduresDisabled = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } else { $There = $false $OleAutomationProceduresDisabled = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } 'CrossDBOwnershipChaining' { if ($There) { try { $SpConfig = Get-DbaSpConfigure -SqlInstance $Instance -ConfigName 'CrossDBOwnershipChaining' $CrossDBOwnershipChaining = [pscustomobject] @{ ConfiguredValue = $SpConfig.ConfiguredValue } } catch { $There = $false $CrossDBOwnershipChaining = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } else { $There = $false $CrossDBOwnershipChaining = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } 'ScanForStartupProceduresDisabled' { if ($There) { try { $SpConfig = Get-DbaSpConfigure -SqlInstance $Instance -ConfigName 'ScanForStartupProcedures' $query = " SELECT name FROM sys.procedures WHERE OBJECTPROPERTY(OBJECT_ID, 'ExecIsStartup') = 1 AND name <> 'sp_MSrepl_startup'" $results = Invoke-DbaQuery -SqlInstance $Instance -Query $query if ($null -eq $results) { $Value = 0 } else { $Value = $SpConfig.ConfiguredValue } $ScanForStartupProceduresDisabled = [pscustomobject] @{ ConfiguredValue = $Value } } catch { $There = $false $ScanForStartupProceduresDisabled = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } else { $There = $false $ScanForStartupProceduresDisabled = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } 'MemoryDump' { if ($There) { try { $daystocheck = Get-DbcConfigValue policy.instance.memorydumpsdaystocheck if ($null -eq $daystocheck) { $datetocheckfrom = '0001-01-01' } else { $datetocheckfrom = (Get-Date).ToUniversalTime().AddDays( - $daystocheck ) } $MaxDump = [pscustomobject] @{ # Warning Action removes dbatools output for version too low from test results # Skip on the it will show in the results Count = (@(Get-DbaDump -SqlInstance $Instance -WarningAction SilentlyContinue).Where{ $_.CreationTime -gt $datetocheckfrom }).Count } } catch { $There = $false $MaxDump = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } else { $There = $false $MaxDump = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } 'RemoteAccessDisabled' { if ($There) { try { $SpConfig = Get-DbaSpConfigure -SqlInstance $Instance -ConfigName 'RemoteAccess' $RemoteAccessDisabled = [pscustomobject] @{ ConfiguredValue = $SpConfig.ConfiguredValue } } catch { $There = $false $RemoteAccessDisabled = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } else { $There = $false $RemoteAccessDisabled = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } 'LatestBuild' { if ($There) { try { $results = Test-DbaBuild -SqlInstance $Instance -Latest $LatestBuild = [pscustomobject] @{ Compliant = $results.Compliant } } catch { $There = $false $LatestBuild = [pscustomobject] @{ Compliant = 'We Could not Connect to $Instance' } } } else { $There = $false $LatestBuild = [pscustomobject] @{ Compliant = 'We Could not Connect to $Instance' } } } 'SaDisabled' { if ($There) { try { #This needs to be done in query just in case the account had already been renamed $login = Get-DbaLogin -SqlInstance $Instance | Where-Object Id -EQ 1 $SaDisabled = [pscustomobject] @{ Disabled = $login.IsDisabled } } catch { $There = $false $SaDisabled = [pscustomobject] @{ Disabled = 'We Could not Connect to $Instance' } } } else { $There = $false $SaDisabled = [pscustomobject] @{ Disabled = 'We Could not Connect to $Instance' } } } 'SaExist' { if ($There) { try { $SaExist = [pscustomobject] @{ Exist = @(Get-DbaLogin -SqlInstance $Instance -Login sa).Count } } catch { $There = $false $SaExist = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } else { $There = $false $SaExist = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } 'SqlEngineServiceAccount' { if ($There) { try { $ComputerName , $InstanceName = $Instance.Name.Split('\') if ($null -eq $InstanceName) { $InstanceName = 'MSSQLSERVER' } $SqlEngineService = Get-DbaService -ComputerName $ComputerName -InstanceName $instanceName -Type Engine -ErrorAction SilentlyContinue $EngineService = [pscustomobject] @{ State = $SqlEngineService.State StartType = $SqlEngineService.StartMode } } catch { $There = $false $EngineService = [pscustomobject] @{ State = 'We Could not Connect to $Instance $ComputerName , $InstanceName from catch' StartType = 'We Could not Connect to $Instance $ComputerName , $InstanceName from catch' } } } else { $There = $false $EngineService = [pscustomobject] @{ State = 'We Could not Connect to $Instance' StartType = 'We Could not Connect to $Instance' } } } 'PublicRolePermission' { if ($There) { try { #This needs to be done in query just in case the account had already been renamed $query = " SELECT Count(*) AS [RowCount] FROM master.sys.server_permissions WHERE (grantee_principal_id = SUSER_SID(N'public') and state_desc LIKE 'GRANT%') AND NOT (state_desc = 'GRANT' and [permission_name] = 'VIEW ANY DATABASE' and class_desc = 'SERVER') AND NOT (state_desc = 'GRANT' and [permission_name] = 'CONNECT' and class_desc = 'ENDPOINT' and major_id = 2) AND NOT (state_desc = 'GRANT' and [permission_name] = 'CONNECT' and class_desc = 'ENDPOINT' and major_id = 3) AND NOT (state_desc = 'GRANT' and [permission_name] = 'CONNECT' and class_desc = 'ENDPOINT' and major_id = 4) AND NOT (state_desc = 'GRANT' and [permission_name] = 'CONNECT' and class_desc = 'ENDPOINT' and major_id = 5); " $results = Invoke-DbaQuery -SqlInstance $Instance -Query $query $PublicRolePermission = [pscustomobject] @{ Count = $results.RowCount } } catch { $There = $false $PublicRolePermission = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } else { $There = $false $PublicRolePermission = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } 'BuiltInAdmin' { if ($There) { try { $BuiltInAdmin = [pscustomobject] @{ Exist = @(Get-DbaLogin -SqlInstance $Instance -Login "BUILTIN\Administrators").Count } } catch { $There = $false $BuiltInAdmin = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } else { $There = $false $BuiltInAdmin = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } 'LocalWindowsGroup' { if ($There) { try { $ComputerName, $InstanceName = $Instance.Name.Split('\') if ($null -eq $InstanceName) { $InstanceName = 'MSSQLSERVER' } $logins = Get-DbaLogin -SqlInstance $Instance | Where-Object { $_.LoginType -eq 'WindowsGroup' -and $_.Name.Split('\') -eq $ComputerName } if ($null -ne $logins) { $LocalWindowsGroup = [pscustomobject] @{ Exist = $true } } else { $LocalWindowsGroup = [pscustomobject] @{ Exist = $false } } } catch { $There = $false $LocalWindowsGroup = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } else { $There = $false $LocalWindowsGroup = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } 'LoginAuditFailed' { if ($There) { try { $results = Get-DbaInstanceProperty -SqlInstance $instance -InstanceProperty AuditLevel $LoginAuditFailed = [pscustomobject] @{ AuditLevel = $results.Value } } catch { $There = $false $LoginAuditFailed = [pscustomobject] @{ AuditLevel = 'We Could not Connect to $Instance' } } } else { $There = $false $LoginAuditFailed = [pscustomobject] @{ AuditLevel = 'We Could not Connect to $Instance' } } } 'LoginAuditSuccessful' { if ($There) { try { $results = Get-DbaInstanceProperty -SqlInstance $instance -InstanceProperty AuditLevel $LoginAuditSuccessful = [pscustomobject] @{ AuditLevel = $results.Value } } catch { $There = $false $LoginAuditSuccessful = [pscustomobject] @{ AuditLevel = 'We Could not Connect to $Instance' } } } else { $There = $false $LoginAuditSuccessful = [pscustomobject] @{ AuditLevel = 'We Could not Connect to $Instance' } } } 'SqlAgentProxiesNoPublicRole' { if ($There) { try { $SqlAgentProxiesWithPublicRole = @() Get-DbaAgentProxy -SqlInstance $Instance | ForEach-Object { if ($psitem.EnumMsdbRoles().Name -contains 'public') { $SqlAgentProxyWithPublicRole = [pscustomobject] @{ Name = $psitem.Name CredentialName = $psitem.CredentialName CredentialIdentity = $psitem.CredentialIdentity } $SqlAgentProxiesWithPublicRole += $SqlAgentProxyWithPublicRole } } } catch { $There = $false $SqlAgentProxiesWithPublicRole = [pscustomobject] @{ Name = 'We Could not Connect to $Instance' CredentialName = $null CredentialIdentity = $null } } } else { $There = $false $SqlAgentProxiesWithPublicRole = [pscustomobject] @{ Name = 'We Could not Connect to $Instance' CredentialName = $null CredentialIdentity = $null } } } 'HideInstance' { if ($There) { try { $results = Get-DbaHideInstance -SqlInstance $Instance $HideInstance = [pscustomobject] @{ HideInstance = $results.HideInstance } } catch { $There = $false $HideInstance = [pscustomobject] @{ HideInstance = 'We Could not Connect to $Instance' } } } else { $There = $false $HideInstance = [pscustomobject] @{ HideInstance = 'We Could not Connect to $Instance' } } } 'EngineServiceAdmin' { if ($There) { if ($IsLinux) { $EngineServiceAdmin = [pscustomobject] @{ Exist = 'We Cant Check running on Linux' } } else { try { $ComputerName , $InstanceName = $Instance.Name.Split('\') if ($null -eq $InstanceName) { $InstanceName = 'MSSQLSERVER' } $SqlEngineService = Get-DbaService -ComputerName $ComputerName -InstanceName $instanceName -Type Engine -ErrorAction SilentlyContinue $LocalAdmins = Invoke-Command -ComputerName $ComputerName -ScriptBlock { Get-LocalGroupMember -Group "Administrators" } -ErrorAction SilentlyContinue $EngineServiceAdmin = [pscustomobject] @{ Exist = $localAdmins.Name.Contains($SqlEngineService.StartName) } } catch [System.Exception] { if ($_.Exception.Message -like '*No services found in relevant namespaces*') { $EngineServiceAdmin = [pscustomobject] @{ Exist = $false } } else { $EngineServiceAdmin = [pscustomobject] @{ Exist = 'Some sort of failure' } } } catch { $There = $false $EngineServiceAdmin = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance $ComputerName , $InstanceName from catch' } } } } else { $There = $false $EngineServiceAdmin = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } 'AgentServiceAdmin' { if ($There) { if ($IsLinux) { $AgentServiceAdmin = [pscustomobject] @{ Exist = 'We Cant Check running on Linux' } } else { try { $ComputerName , $InstanceName = $Instance.Name.Split('\') if ($null -eq $InstanceName) { $InstanceName = 'MSSQLSERVER' } $SqlAgentService = Get-DbaService -ComputerName $ComputerName -InstanceName $instanceName -Type Agent -ErrorAction SilentlyContinue $LocalAdmins = Invoke-Command -ComputerName $ComputerName -ScriptBlock { Get-LocalGroupMember -Group "Administrators" } -ErrorAction SilentlyContinue $AgentServiceAdmin = [pscustomobject] @{ Exist = $localAdmins.Name.Contains($SqlAgentService.StartName) } } catch [System.Exception] { if ($_.Exception.Message -like '*No services found in relevant namespaces*') { $AgentServiceAdmin = [pscustomobject] @{ Exist = $false } } else { $AgentServiceAdmin = [pscustomobject] @{ Exist = 'Some sort of failure' } } } catch { $There = $false $AgentServiceAdmin = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance $ComputerName , $InstanceName from catch' } } } } else { $There = $false $AgentServiceAdmin = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } 'FullTextServiceAdmin' { if ($There) { if ($IsLinux) { $FullTextServiceAdmin = [pscustomobject] @{ Exist = 'We Cant Check running on Linux' } } else { try { $ComputerName , $InstanceName = $Instance.Name.Split('\') if ($null -eq $InstanceName) { $InstanceName = 'MSSQLSERVER' } $SqlFullTextService = Get-DbaService -ComputerName $ComputerName -InstanceName $instanceName -Type FullText -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -WarningVariable WarVar $LocalAdmins = Invoke-Command -ComputerName $ComputerName -ScriptBlock { Get-LocalGroupMember -Group "Administrators" } -ErrorAction SilentlyContinue $FullTextServiceAdmin = [pscustomobject] @{ Exist = $localAdmins.Name.Contains($SqlFullTextService.StartName) } } catch [System.Exception] { if ($_.Exception.Message -like '*No services found in relevant namespaces*') { $FullTextServiceAdmin = [pscustomobject] @{ Exist = $false } } else { $FullTextServiceAdmin = [pscustomobject] @{ Exist = 'Some sort of failure' } } } catch { $There = $false $FullTextServiceAdmin = [pscustomobject] @{ Exist = "We Could not Connect to $Instance $ComputerName , $InstanceName from catch" } } } } else { $There = $false $FullTextServiceAdmin = [pscustomobject] @{ Exist = 'We Could not Connect to $Instance' } } } 'LoginCheckPolicy' { if ($There) { try { $LoginCheckPolicy = [pscustomobject] @{ Count = @(Get-DbaLogin -SqlInstance $instance -Type SQL | Where-Object { $_.PasswordPolicyEnforced -eq $false -and $_.IsDisabled -eq $false }).Count } } catch { $There = $false $LoginCheckPolicy = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } else { $There = $false $LoginCheckPolicy = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } 'LoginPasswordExpiration' { if ($There) { try { $role = Get-DbaServerRole -SqlInstance $instance -ServerRole "sysadmin" $LoginPasswordExpiration = [pscustomobject] @{ Count = @(Get-DbaLogin -SqlInstance $instance -Login @($role.Login) -Type SQL | Where-Object { $_.PasswordExpirationEnabled -eq $false -and $_.IsDisabled -eq $false }).Count } } catch { $There = $false $LoginPasswordExpiration = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } else { $There = $false $LoginPasswordExpiration = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } 'LoginMustChange' { if ($There) { try { $role = Get-DbaServerRole -SqlInstance $instance -ServerRole "sysadmin" $LoginMustChange = [pscustomobject] @{ Count = @(Get-DbaLogin -SqlInstance $instance -Login @($role.Login) -Type SQL | Where-Object { $_.MustChangePassword -eq $false -and $_.IsDisabled -eq $false -and $null -eq $_.LastLogin }).Count } } catch { $There = $false $LoginMustChange = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } else { $There = $false $LoginMustChange = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } 'SQLMailXPsDisabled' { if ($There) { try { $SpConfig = Get-DbaSpConfigure -SqlInstance $Instance -ConfigName 'SqlMailXPsEnabled' $SQLMailXPsDisabled = [pscustomobject] @{ ConfiguredValue = $SpConfig.ConfiguredValue } } catch { $There = $false $SQLMailXPsDisabled = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } else { $There = $false $SQLMailXPsDisabled = [pscustomobject] @{ ConfiguredValue = 'We Could not Connect to $Instance' } } } Default { } } [PSCustomObject]@{ ErrorLog = $ErrorLog DefaultTrace = $DefaultTrace MaxDump = $MaxDump CrossDBOwnershipChaining = $CrossDBOwnershipChaining ScanForStartupProceduresDisabled = $ScanForStartupProceduresDisabled RemoteAccess = $RemoteAccessDisabled OleAutomationProceduresDisabled = $OleAutomationProceduresDisabled LatestBuild = $LatestBuild SaExist = $SaExist SaDisabled = $SaDisabled EngineService = $EngineService SqlAgentProxiesWithPublicRole = $SqlAgentProxiesWithPublicRole HideInstance = $HideInstance LoginAuditFailed = $LoginAuditFailed LoginAuditSuccessful = $LoginAuditSuccessful EngineServiceAdmin = $EngineServiceAdmin AgentServiceAdmin = $AgentServiceAdmin FullTextServiceAdmin = $FullTextServiceAdmin LocalWindowsGroup = $LocalWindowsGroup BuiltInAdmin = $BuiltInAdmin PublicRolePermission = $PublicRolePermission LoginCheckPolicy = $LoginCheckPolicy LoginPasswordExpiration = $LoginPasswordExpiration LoginMustChange = $LoginMustChange SQLMailXPsDisabled = $SQLMailXPsDisabled } } function Assert-DefaultTrace { Param($AllInstanceInfo) $AllInstanceInfo.DefaultTrace.ConfiguredValue | Should -Be 1 -Because "We expected the Default Trace to be enabled" } function Assert-EngineState { Param($AllInstanceInfo, $state) $AllInstanceInfo.EngineService.State | Should -Be $state -Because "The SQL Service was expected to be $state" } function Assert-EngineStartType { Param($AllInstanceInfo, $starttype) $AllInstanceInfo.EngineService.StartType | Should -Be $starttype -Because "The SQL Service Start Type was expected to be $starttype" } function Assert-EngineStartTypeCluster { Param($AllInstanceInfo) $AllInstanceInfo.EngineService.StartType | Should -Be "Manual" -Because 'Clustered Instances required that the SQL engine service is set to manual' } function Assert-OleAutomationProcedures { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] Param($AllInstanceInfo) $AllInstanceInfo.OleAutomationProceduresDisabled.ConfiguredValue | Should -Be 0 -Because "We expect the OLE Automation Procedures to be disabled" } function Assert-ScanForStartupProcedures { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param ($AllInstanceInfo, $ScanForStartupProcsDisabled) ($AllInstanceInfo.ScanForStartupProceduresDisabled.ConfiguredValue -eq 0) | Should -Be $ScanForStartupProcsDisabled -Because "We expected the scan for startup procedures to be configured correctly" } function Assert-MaxDump { Param($AllInstanceInfo, $maxdumps) $AllInstanceInfo.MaxDump.Count | Should -BeLessThan $maxdumps -Because "We expected less than $maxdumps dumps but found $($AllInstanceInfo.MaxDump.Count). Memory dumps often suggest issues with the SQL Server instance" } function Assert-RemoteAccess { param ($AllInstanceInfo) $AllInstanceInfo.RemoteAccess.ConfiguredValue | Should -Be 0 -Because "We expected Remote Access to be disabled" } function Assert-InstanceMaxDop { Param( [string]$Instance, [switch]$UseRecommended, [int]$MaxDopValue ) $MaxDop = @(Test-DbaMaxDop -SqlInstance $Instance)[0] if ($UseRecommended) { #if UseRecommended - check that the CurrentInstanceMaxDop property returned from Test-DbaMaxDop matches the the RecommendedMaxDop property $MaxDop.CurrentInstanceMaxDop | Should -Be $MaxDop.RecommendedMaxDop -Because "We expect the MaxDop Setting to be the recommended value $($MaxDop.RecommendedMaxDop)" } else { #if not UseRecommended - check that the CurrentInstanceMaxDop property returned from Test-DbaMaxDop matches the MaxDopValue parameter $MaxDop.CurrentInstanceMaxDop | Should -Be $MaxDopValue -Because "We expect the MaxDop Setting to be $MaxDopValue" } } function Assert-BackupCompression { Param($Instance, $defaultbackupcompression) (Get-DbaSpConfigure -SqlInstance $Instance -ConfigName 'DefaultBackupCompression').ConfiguredValue -eq 1 | Should -Be $defaultbackupcompression -Because 'The default backup compression should be set correctly' } function Assert-TempDBSize { Param($Instance) @((Get-DbaDbFile -SqlInstance $Instance -Database tempdb).Where{ $_.Type -eq 0 }.Size.Megabyte | Select-Object -Unique).Count | Should -Be 1 -Because "We want all the tempdb data files to be the same size - See https://blogs.sentryone.com/aaronbertrand/sql-server-2016-tempdb-fixes/ and https://www.brentozar.com/blitz/tempdb-data-files/ for more information" } function Assert-InstanceSupportedBuild { Param( [string]$Instance, [int]$BuildWarning, [string]$BuildBehind, [DateTime]$Date ) #If $BuildBehind check against SP/CU parameter to determine validity of the build if ($BuildBehind) { $results = Test-DbaBuild -SqlInstance $Instance -SqlCredential $sqlcredential -MaxBehind $BuildBehind $Compliant = $results.Compliant $Build = $results.build $Compliant | Should -Be $true -Because "this build $Build should not be behind the required build" #If no $BuildBehind only check against support dates } else { $Results = Test-DbaBuild -SqlInstance $Instance -SqlCredential $sqlcredential -Latest [DateTime]$SupportedUntil = Get-Date $results.SupportedUntil -Format O $Build = $results.build #If $BuildWarning, check for support date within the warning window if ($BuildWarning) { [DateTime]$expected = Get-Date ($Date).AddMonths($BuildWarning) -Format O $SupportedUntil | Should -BeGreaterThan $expected -Because "this build $Build will be unsupported by Microsoft on $(Get-Date $SupportedUntil -Format O) which is less than $BuildWarning months away" } #If neither, check for Microsoft support date else { $SupportedUntil | Should -BeGreaterThan $Date -Because "this build $Build is now unsupported by Microsoft" } } } function Assert-TwoDigitYearCutoff { Param( [string]$Instance, [int]$TwoDigitYearCutoff ) (Get-DbaSpConfigure -SqlInstance $Instance -ConfigName 'TwoDigitYearCutoff').ConfiguredValue | Should -Be $TwoDigitYearCutoff -Because 'This is the value that you have chosen for Two Digit Year Cutoff configuration' } function Assert-TraceFlag { Param( $ActualTraceflags, [int[]]$ExpectedTraceFlag ) if ($ExpectedTraceFlag -ne 0) { $ExpectedTraceFlag | Should -BeIn $ActualTraceflags -Because "We expect that Trace Flag $ExpectedTraceFlag will be set" } else { $ActualTraceflags | Should -BeNullOrEmpty -Because "We expect that there will be no Trace Flags set" } } function Assert-NotTraceFlag { [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'ExpectedTraceFlag')] Param( [string]$SQLInstance, [int[]]$NotExpectedTraceFlag, [int[]]$ExpectedTraceFlag ) if ($null -eq $NotExpectedTraceFlag) { (@(Get-DbaTraceFlag -SqlInstance $SQLInstance).Where{ $_.TraceFlag -notin $ExpectedTraceFlag } | Select-Object).TraceFlag | Should -BeNullOrEmpty -Because "We expect that there will be no Trace Flags set on $SQLInstance" } else { @($NotExpectedTraceFlag).ForEach{ (Get-DbaTraceFlag -SqlInstance $SQLInstance).TraceFlag | Should -Not -Contain $PSItem -Because "We expect that Trace Flag $PsItem will not be set on $SQLInstance" } } } function Assert-CLREnabled { param ( $SQLInstance, $CLREnabled ) (Get-DbaSpConfigure -SqlInstance $SQLInstance -Name IsSqlClrEnabled).ConfiguredValue -eq 1 | Should -Be $CLREnabled -Because 'The CLR Enabled should be set correctly' } function Assert-CrossDBOwnershipChaining { Param($AllInstanceInfo) $AllInstanceInfo.CrossDBOwnershipChaining.ConfiguredValue | Should -Be 0 -Because "We expected the Cross DB Ownership Chaining to be disabled" } function Assert-AdHocDistributedQueriesEnabled { param ( $SQLInstance, $AdHocDistributedQueriesEnabled ) (Get-DbaSpConfigure -SqlInstance $SQLInstance -Name AdHocDistributedQueriesEnabled).ConfiguredValue -eq 1 | Should -Be $AdHocDistributedQueriesEnabled -Because 'The AdHoc Distributed Queries Enabled setting should be set correctly' } function Assert-XpCmdShellDisabled { param ( $SQLInstance, $XpCmdShellDisabled ) (Get-DbaSpConfigure -SqlInstance $SQLInstance -Name XPCmdShellEnabled).ConfiguredValue -eq 0 | Should -Be $XpCmdShellDisabled -Because 'The XP CmdShell setting should be set correctly' } function Assert-ErrorLogCount { param ( $SQLInstance, $errorLogCount ) (Get-DbaErrorLogConfig -SqlInstance $SQLInstance).LogCount | Should -BeGreaterOrEqual $errorLogCount -Because "We expect to have at least $errorLogCount number of error log files" } function Assert-ErrorLogEntry { Param($AllInstanceInfo) $AllInstanceInfo.ErrorLog | Should -BeNullOrEmpty -Because "these severities indicate serious problems" } function Assert-LatestBuild { Param($AllInstanceInfo) $AllInstanceInfo.LatestBuild.Compliant | Should -Be $true -Because "We expected the SQL Server to be on the newest SQL Server Packs/CUs" } function Assert-SaDisabled { Param($AllInstanceInfo) $AllInstanceInfo.SaDisabled.Disabled | Should -Be $true -Because "We expected the original sa login to be disabled" } function Assert-SaExist { Param($AllInstanceInfo) $AllInstanceInfo.SaExist.Exist | Should -Be 0 -Because "We expected no login to exist with the name sa" } function Assert-SqlAgentProxiesNoPublicRole { Param($AllInstanceInfo) $AllInstanceInfo.SqlAgentProxiesWithPublicRole | Should -BeNull -Because "We expected the public role to not have access to any SQL Agent proxies" } function Assert-HideInstance { Param($AllInstanceInfo) $AllInstanceInfo.HideInstance.HideInstance | Should -Be $true -Because "We expected the hide instance property to be set to $true" } function Assert-LocalWindowsGroup { Param($AllInstanceInfo) $AllInstanceInfo.LocalWindowsGroup.Exist | Should -Be $false -Because "We expected to have no local Windows groups as SQL logins" } function Assert-PublicRolePermission { Param($AllInstanceInfo) $AllInstanceInfo.PublicRolePermission.Count | Should -Be 0 -Because "We expected the public server role to have been granted no permissions" } function Assert-BuiltInAdmin { Param($AllInstanceInfo) $AllInstanceInfo.BuiltInAdmin.Exist | Should -Be 0 -Because "We expected no login to exist with the name BUILTIN\Administrators" } function Assert-LoginAuditSuccessful { Param($AllInstanceInfo) $AllInstanceInfo.LoginAuditSuccessful.AuditLevel | Should -Be "All" -Because "We expected the audit level to be set to capture all logins (successful and failed)" } function Assert-LoginAuditFailed { Param($AllInstanceInfo) $AllInstanceInfo.LoginAuditFailed.AuditLevel | Should -BeIn @("Failure", "All") -Because "We expected the audit level to be set to capture failed logins" } function Assert-AgentServiceAdmin { Param($AllInstanceInfo) $AllInstanceInfo.AgentServiceAdmin.Exist | Should -Be $false -Because "We expected the service account for the SQL Agent to not be a local administrator" } function Assert-EngineServiceAdmin { Param($AllInstanceInfo) $AllInstanceInfo.EngineServiceAdmin.Exist | Should -Be $false -Because "We expected the service account for the SQL Engine to not be a local administrator" } function Assert-FullTextServiceAdmin { Param($AllInstanceInfo) $AllInstanceInfo.FullTextServiceAdmin.Exist | Should -Be $false -Because "We expected the service account for the SQL Full Text to not be a local administrator" } function Assert-LoginCheckPolicy { Param($AllInstanceInfo) $AllInstanceInfo.LoginCheckPolicy.Count | Should -Be 0 -Because "We expected the CHECK_POLICY for the all logins to be enabled" } function Assert-LoginPasswordExpiration { Param($AllInstanceInfo) $AllInstanceInfo.LoginPasswordExpiration.Count | Should -Be 0 -Because "We expected the password expiration policy to set on all sql logins in the sysadmin role" } function Assert-LoginMustChange { Param($AllInstanceInfo) $AllInstanceInfo.LoginMustChange.Count | Should -Be 0 -Because "We expected the all the new sql logins to have change the password on first login" } function Assert-SQLMailXPsDisabled { param ($AllInstanceInfo) $AllInstanceInfo.SQLMailXPsDisabled.ConfiguredValue | Should -Be 0 -Because "We expected Sql Mail XPs to be disabled" } function Assert-PublicPermission { Param($AllInstanceInfo) $AllInstanceInfo.PublicPermission.Count | Should -Be 0 -Because "We expected the public role to have no permissions for CIS compliance." } ================================================ FILE: source/internal/assertions/Server.Assertions.ps1 ================================================ <# This file is used to hold the Assertions for the Server.Tests Follow the guidance in Instance.Assertions to add new checks It starts with the Get-AllServerInfo which uses all of the unique tags that have been passed and gathers the required information which can then be used for the assertions. The long term aim is to make Get-AllServerInfo as performant as possible #> function Get-AllServerInfo { # Using the unique tags gather the information required # 2018/09/04 - Added PowerPlan Tag - RMS # 2018/09/06 - Added more Tags - RMS Param($ComputerName, $Tags) $There = $true switch ($tags) { 'PingComputer' { if ($There) { try { $pingcount = Get-DbcConfigValue policy.connection.pingcount $PingComputer = Test-Connection -Count $pingcount -ComputerName $ComputerName -ErrorAction Stop } catch { $There = $false $PingComputer = [PSCustomObject] @{ Count = -1 ResponseTime = 50000000 } } } else { $PingComputer = [PSCustomObject] @{ Count = -1 ResponseTime = 50000000 } } } 'DiskAllocationUnit' { if ($There) { try { $DiskAllocation = Test-DbaDiskAllocation -ComputerName $ComputerName -EnableException -WarningAction SilentlyContinue -WarningVariable DiskAllocationWarning } catch { $There = $false $DiskAllocation = [PSCustomObject]@{ Name = '? ' isbestpractice = $false IsSqlDisk = $true } } } else { $DiskAllocation = [PSCustomObject]@{ Name = '? ' isbestpractice = $false IsSqlDisk = $true } } } 'PowerPlan' { if ($There) { try { $PowerPlan = (Test-DbaPowerPlan -ComputerName $ComputerName -EnableException -WarningVariable PowerWarning -WarningAction SilentlyContinue).IsBestPractice } catch { $PowerPlan = $false } } else { $PowerPlan = $false } } 'SPN' { if ($There) { try { $SPNs = Test-DbaSpn -ComputerName $ComputerName -EnableException -WarningVariable SPNWarning -WarningAction SilentlyContinue if ($SPNWarning) { if ($SPNWarning[1].ToString().Contains('Cannot resolve IP address')) { $There = $false $SPNs = [PSCustomObject]@{ RequiredSPN = 'Dont know the SPN' InstanceServiceAccount = 'Dont know the Account' Error = 'Could not connect' } } else { $SPNs = [PSCustomObject]@{ RequiredSPN = 'Dont know the SPN' InstanceServiceAccount = 'Dont know the Account' Error = 'An Error occurred' } } } } catch { $SPNs = [PSCustomObject]@{ RequiredSPN = 'Dont know the SPN' InstanceServiceAccount = 'Dont know the Account' Error = 'An Error occurred' } } } else { $SPNs = [PSCustomObject]@{ RequiredSPN = 'Dont know the SPN' InstanceServiceAccount = 'Dont know the Account' Error = 'An Error occurred' } } } 'DiskCapacity' { if ($There) { try { $DiskSpace = Get-DbaDiskSpace -ComputerName $ComputerName -EnableException -WarningVariable DiskSpaceWarning -WarningAction SilentlyContinue } catch { if ($DiskSpaceWarning) { $There = $false if ($DiskSpaceWarning[1].ToString().Contains('Couldn''t resolve hostname')) { $DiskSpace = [PSCustomObject]@{ Name = 'Do not know the Name' PercentFree = -1 ComputerName = 'Cannot resolve ' + $ComputerName } } } else { $DiskSpace = [PSCustomObject]@{ Name = 'Do not know the Name' PercentFree = -1 ComputerName = 'An Error occurred ' + $ComputerName } } } } else { $DiskSpace = [PSCustomObject]@{ Name = 'Do not know the Name' PercentFree = -1 ComputerName = 'An Error occurred ' + $ComputerName } } } 'NonStandardPort' { if ($There) { try { $count = (Find-DbaInstance -ComputerName $ComputerName -TCPPort 1433).Count $StandardPortCount = [pscustomobject] @{ Count = $count } } catch { $There = $false $StandardPortCount = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } else { $There = $false $StandardPortCount = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } 'ServerProtocol' { if ($There) { try { $count = (Get-DbaInstanceProtocol -ComputerName $ComputerName | Where-Object {$_.DisplayName -ne "TCP/IP" -and $_.IsEnabled -eq $true}).Count $ServerProtocol = [pscustomobject] @{ Count = $count } } catch { $There = $false $ServerProtocol = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } else { $There = $false $ServerProtocol = [pscustomobject] @{ Count = 'We Could not Connect to $Instance' } } } Default {} } [PSCustomObject]@{ PowerPlan = $PowerPlan SPNs = $SPNs DiskSpace = $DiskSpace PingComputer = $PingComputer DiskAllocation = $DiskAllocation StandardPortCount = $StandardPortCount ServerProtocol = $ServerProtocol } } function Assert-CPUPrioritisation { [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'ComputerName')] Param( [string]$ComputerName ) function Get-RemoteRegistryValue { $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $ComputerName) $RegSubKey = $Reg.OpenSubKey("System\CurrentControlSet\Control\PriorityControl") $RegSubKey.GetValue('Win32PrioritySeparation') } Get-RemoteRegistryValue | Should -BeExactly 24 -Because "a server should prioritise CPU to it's Services, not to the user experience when someone logs on" } function Assert-DiskAllocationUnit { Param($DiskAllocationObject) $DiskAllocationObject.isbestpractice | Should -BeTrue -Because "SQL Server performance will be better when accessing data from a disk that is formatted with 64Kb block allocation unit" } function Assert-PowerPlan { Param($AllServerInfo) $AllServerInfo.PowerPlan | Should -Be 'True' -Because "You want your SQL Server to not be throttled by the Power Plan settings - See https://support.microsoft.com/en-us/help/2207548/slow-performance-on-windows-server-when-using-the-balanced-power-plan" } function Assert-SPN { Param($SPN) $SPN.Error | Should -Be 'None' -Because "We expect to have a SPN $($SPN.RequiredSPN) for $($SPN.InstanceServiceAccount)" } function Assert-DiskSpace { Param($Disk) $free = Get-DbcConfigValue policy.diskspace.percentfree $Disk.PercentFree | Should -BeGreaterThan $free -Because "You Do not want to run out of space on your disks" } function Assert-Ping { Param( $AllServerInfo, $Type ) $pingcount = Get-DbcConfigValue policy.connection.pingcount $pingmsmax = Get-DbcConfigValue policy.connection.pingmaxms switch ($type) { Ping { ($AllServerInfo.PingComputer).Count | Should -Be $pingcount -Because "We expect the server to respond to ping" } Average { if ($IsCoreCLR) { ($AllServerInfo.PingComputer | Measure-Object -Property Latency -Average).Average / $pingcount | Should -BeLessThan $pingmsmax -Because "We expect the server to respond within $pingmsmax" } else { ($AllServerInfo.PingComputer | Measure-Object -Property ResponseTime -Average).Average / $pingcount | Should -BeLessThan $pingmsmax -Because "We expect the server to respond within $pingmsmax" } } Default {} } } function Assert-NonStandardPort { Param($AllServerInfo) $AllServerInfo.StandardPortCount.count | Should -Be 0 -Because "SQL Server should be configured to not use the standard port of 1433" } function Assert-ServerProtocol { Param($AllServerInfo) $AllServerInfo.ServerProtocol.Count | Should -Be 0 -Because "SQL Server should be configured to use only the TCP/IP protocol" } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUkbWiF6k6prHEAiMVnoEKu09n # bPygggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBT4os0MlMhlV4UraAiFxccwRITI # uTANBgkqhkiG9w0BAQEFAASCAQCKNm/SlwW5wDhBqZCVycDNtcEt3+/CdqsxM9AE # SVOHD31uUTQB/pgUyu0TE2VFlLYKCCbwxy/Rz4jLbbz3z+Dd/dm9wNvYnJc7rEs3 # pj6VOVwCG+hwtneIjEJFF9DmoWgNczpuuDriHo6KsLZYX33t0PRpDpUsKq7WTXS9 # YAm7zTvSPJnZhgBbDAC8QrGfngE+iaJu+OwquKikbgH5DsvBgGSkOsgaPztAtqjR # SEDeN3OGT5BsJKAh8qw8nezZXvYjd0ffsNEMNro/hN8SbTlR1kMm9NaUKyrTS48A # wpRxkz3cFtkEH5ql8BZTH3Nj4GsDrK40mCE2+1TKcboajhKM # SIG # End signature block ================================================ FILE: source/internal/configurations/DbcCheckDescriptions.json ================================================ [{ "UniqueTag": "AgentServiceAccount", "Description": "Tests that the SQL Agent Account is running and set to automatic." }, { "UniqueTag": "DbaOperator", "Description": "Tests that the specified (default blank) DBA Operators exist and have the correct email address." }, { "UniqueTag": "FailsafeOperator", "Description": "Tests that the specified (default blank) Failsafe Operator exists." }, { "UniqueTag": "DatabaseMailProfile", "Description": "Tests that the specified (default blank) Database Mail Profile exists." }, { "UniqueTag": "FailedJob", "Description": "Tests that enabled Agent Jobs last outcome was succeeded since specified start date (default 30 days ago) and can exclude cancelled jobs (default false)." }, { "UniqueTag": "ValidJobOwner", "Description": "Tests that all Agent Jobs have a Job Owner in the list specified (default sa)." }, { "UniqueTag": "InvalidJobOwner", "Description": "Tests that all Agent Jobs do not have a Job Owner in the list specified (default null)." }, { "UniqueTag": "AgentAlert", "Description": "Tests that there are Agent Alerts set up for the specified (default 16-25) alert severities and ids (default 823-825) and if specified Agent Jobs and/or notifications." }, { "UniqueTag": "DatabaseCollation", "Description": "Tests that the Database Collation matches the instance collation except for specified databases." }, { "UniqueTag": "SuspectPage", "Description": "Tests that there are 0 Suspect Pages for the database." }, { "UniqueTag": "SuspectPageLimit", "Description": "Tests that the suspect_pages table in msdb is not nearing the limit of 1000 rows." }, { "UniqueTag": "TestLastBackup", "Description": "Restores the last backup of a database onto a specified (default blank so will use the same instance) restore instance and checks if the DBCC result was successful as well as the DBCC result. This can obviously take some time for large databases!" }, { "UniqueTag": "TestLastBackupVerifyOnly", "Description": "Does a verify only restore of the last backup of the database and test the result." }, { "UniqueTag": "ValidDatabaseOwner", "Description": "Tests that the database owner is in the specified (default blank) list." }, { "UniqueTag": "InvalidDatabaseOwner", "Description": "Tests that the Database Owner is NOT in the specified (default blank) list." }, { "UniqueTag": "LastGoodCheckDb", "Description": "Tests that there was a Last Good DBCC CHECKDB within the specified limit (default blank) and if specified that the DATA_PURITY flag is set." }, { "UniqueTag": "IdentityUsage", "Description": "Tests that identity columns values are not above the specified percentage (default blank) of the maximum value for that data type." }, { "UniqueTag": "RecoveryModel", "Description": "Tests that the Recovery model for all of the databases is set as specified (default blank) except for any specified." }, { "UniqueTag": "DuplicateIndex", "Description": "Tests for any duplicate indexes." }, { "UniqueTag": "UnusedIndex", "Description": "Tests for any unused indexes." }, { "UniqueTag": "DisabledIndex", "Description": "Tests for any disabled indexes." }, { "UniqueTag": "DatabaseGrowthEvent", "Description": "Tests for any database growth events in the default system trace." }, { "UniqueTag": "PageVerify", "Description": "Tests the page verify setting." }, { "UniqueTag": "AutoClose", "Description": "Tests the auto-close setting." }, { "UniqueTag": "AutoShrink", "Description": "Tests the Auto Shrink setting." }, { "UniqueTag": "LastFullBackup", "Description": "Tests if the last full backup of a database is less than the specified number of days (default 7) except for offline databases and read-only databases (read-only if specified) and databases created recently (if specified)." }, { "UniqueTag": "LastDiffBackup", "Description": "Tests if the last diff backup of a database is less than the specified number of hours (default 24) except for offline databases and read-only databases (read-only if specified) and databases created recently (if specified)." }, { "UniqueTag": "LastLogBackup", "Description": "Tests if the last log backup of a database is less than the specified number of minutes (default 30) except for simple databases, offline databases and read-only databases (read-only if specified) and databases created recently (if specified)." }, { "UniqueTag": "VirtualLogFile", "Description": "Tests the number of the Virtual Log Files are less than the specified number." }, { "UniqueTag": "LogfileCount", "Description": "Tests that the number of log files are less than the specified amount (default is 1) in all databases except those specified to be skipped by default." }, { "UniqueTag": "LogfileSize", "Description": "Tests that the database log files are less than the specified percentage of the specified comparison (maximum size or average - default is average) of the data file size (default 100)." }, { "UniqueTag": "LogfilePercentUsed", "Description": "Tests that the database percent log file used is less than the specified percentage (default 75)." }, { "UniqueTag": "FutureFileGrowth", "Description": "Tests if a database (except for those specified to be skipped explicitly) has free space less than the specified percentage (default 20)." }, { "UniqueTag": "FileGroupBalanced", "Description": "Tests that all of the files within each filegroup are sized within the specified percentage (default 5) of the average." }, { "UniqueTag": "CertificateExpiration", "Description": "Tests that all certificates have not expired and are not due to expire within the specified (default 1) number of months." }, { "UniqueTag": "AutoCreateStatistics", "Description": "Tests the Auto Create Statistics property on each database is set to the specified (default false) value." }, { "UniqueTag": "AutoUpdateStatistics", "Description": "Tests the Auto Update Statistics property on each database is set to the specified (default true) value." }, { "UniqueTag": "AutoUpdateStatisticsAsynchronously", "Description": "Tests the Auto Update Statistics Asynchronously property on each database is set to the specified (default false) value." }, { "UniqueTag": "DatafileAutoGrowthType", "Description": "Tests that the Datafile Auto Growth type and value on each database except those specified is set to the specified (default type = kb, value = 65535) values." }, { "UniqueTag": "Trustworthy", "Description": "Tests that the Trustworthy Option for each database is set to false." }, { "UniqueTag": "OrphanedUser", "Description": "Tests that each database has 0 orphaned users." }, { "UniqueTag": "PseudoSimple", "Description": "Tests that databases are not in PseudoSimple Recovery Model." }, { "UniqueTag": "CompatibilityLevel", "Description": "tests that the servers compatibility level matches the compatibility level." }, { "UniqueTag": "DomainName", "Description": "Uses WMI Win32_ComputerSystem to check that the host machine is on the correct domain." }, { "UniqueTag": "OrganizationalUnit", "Description": "Currently skipped - Active Directory OU." }, { "UniqueTag": "ClusterHealth", "Description": "Runs a suite of tests against an Availability Group on a Windows cluster to ensure that everything is as it should be. Tests cluster resources are online, cluster nodes are up, at least one IP Address for the AG listener is available, that each replica and listener are pingable (listener ping check can be skipped), can be connected to via T-SQL, have the correct domain name and TCP port, that each replica is synchronized/ing, is connected, is not in an unknown state, each database is synchronized/ing, failover ready and joined to the domain and that the Always On Health Extended Event sessions are running and set to auto-start." }, { "UniqueTag": "SqlEngineServiceAccount", "Description": "Tests that the SQL Engine Service state is set to the configured value (default - Running) and that the start mode is set to the configured value (default - Automatic) unless it is a cluster in which case it checks that the start mode is set to Manual." }, { "UniqueTag": "SqlBrowserServiceAccount", "Description": "Tests that the SQL Browser Service is started and set to auto-start if there are multiple instances and stopped and set to disabled if there is only one." }, { "UniqueTag": "TempDbConfiguration", "Description": "Tests that the TempDB Configuration is correct, that TF118 is enabled, there are the recommended number of files, autogrowth is not set to percent, that the files can grow and that they are not located on the C drive (each of these tests can be configured individually to be skipped." }, { "UniqueTag": "AdHocWorkload", "Description": "Tests that the AAd Hoc Workload Optimization is enabled." }, { "UniqueTag": "BackupPathAccess", "Description": "Tests that the SQL Service account has access to the default backup path or the specified folder path." }, { "UniqueTag": "DAC", "Description": "Tests that the Dedicated Administrator Connection configuration setting matches the specified value (default true)." }, { "UniqueTag": "TwoDigitYearCutoff", "Description": "Tests that the 'Two Digit Year Cutoff' configuration setting matches the specified value (default 2049)." }, { "UniqueTag": "NetworkLatency", "Description": "Tests that the Network Latency is less than the specified (default 40 (ms))." }, { "UniqueTag": "LinkedServerConnection", "Description": "Tests for successful connection to all Linked Servers." }, { "UniqueTag": "MaxMemory", "Description": "Tests an instances Max Memory." }, { "UniqueTag": "OrphanedFile", "Description": "Tests that there are 0 orphaned data files." }, { "UniqueTag": "ServerNameMatch", "Description": "Tests that the SQL + Windows names match." }, { "UniqueTag": "MemoryDump", "Description": "Tests that there are less than the specified (default 1) number of SQL Memory Dumps." }, { "UniqueTag": "SupportedBuild", "Description": "Tests that the instance is still under Microsoft support and that it will still be under support in a specified (default 6) months." }, { "UniqueTag": "SaRenamed", "Description": "Tests that the SA Login has been renamed." }, { "UniqueTag": "SaExist", "Description": "Tests that a sa login does not exist." }, { "UniqueTag": "SaDisabled", "Description": "Tests that the original SA Login is disabled." }, { "UniqueTag": "DefaultBackupCompression", "Description": "Tests that an instances Default Backup Compression is set to the specified (default true) setting." }, { "UniqueTag": "XESessionStopped", "Description": "Tests that the specified (default blank) XE Sessions are stopped." }, { "UniqueTag": "XESessionRunning", "Description": "Tests that the specified (default blank) XE Sessions that are expected to be running are running." }, { "UniqueTag": "XESessionRunningAllowed", "Description": "Tests that the specified (default blank) XE Sessions that are allowed to be running are running." }, { "UniqueTag": "OLEAutomation", "Description": "Tests that OLE Automation is set to the specified (default false) setting." }, { "UniqueTag": "WhoIsActiveInstalled", "Description": "Tests that sp_whoisactive is Installed by testing the specified (default master) database for the stored procedure." }, { "UniqueTag": "ModelDbGrowth", "Description": "Tests that the Model Database Growth settings are not set to default." }, { "UniqueTag": "ADUser", "Description": "Tests that Ad Users and Groups, except those specified, that are logins on a SQL Server exist in Active Directory, do not have an expired password, are not locked out, are enabled in AD and on the SQL Server." }, { "UniqueTag": "ErrorLog", "Description": "Tests that the SQL Server Error Log does not have any Severity 17-24 level entries within the specified (default 2) days." }, { "UniqueTag": "ErrorLogCount", "Description": "Tests that the number of SQL Server Error Logs configured. Default value is -1 which means off (will use 6 files)." }, { "UniqueTag": "LogShippingPrimary", "Description": "Tests that the Log Shipping Primary status is ok." }, { "UniqueTag": "LogShippingSecondary", "Description": "Tests that the Log Shipping Secondary status is ok." }, { "UniqueTag": "OlaInstalled", "Description": "Tests that Ola maintenance solution is installed by testing the specified (default master) database for the command log table and the stored procedures." }, { "UniqueTag": "SystemFull", "Description": "Tests that the Ola - System Full Agent Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled and that the backup retention setting for the job is set as specified (default 192 (hours))." }, { "UniqueTag": "UserFull", "Description": "Tests that the Ola - User Full Agent Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled and that the backup retention setting for the job is set as specified (default 192 (hours))." }, { "UniqueTag": "UserDiff", "Description": "Tests that the Ola - User Diff Agent Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled and that the backup retention setting for the job is set as specified (default 192 (hours))." }, { "UniqueTag": "UserLog", "Description": "Tests that the Ola - User Log Agent Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled and that the backup retention setting for the job is set as specified (default 192 (hours))." }, { "UniqueTag": "CommandLog", "Description": "Tests that the Ola - Command Log Cleanup Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled and that the clean up setting for the job is set as specified (default 30 (days))." }, { "UniqueTag": "SystemIntegrityCheck", "Description": "Tests that the Ola - System Integrity Check Agent Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled." }, { "UniqueTag": "UserIntegrityCheck", "Description": "Tests that the Ola - User Integrity Check Agent Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled." }, { "UniqueTag": "UserIndexOptimize", "Description": "Tests that the Ola - User Index Optimise Agent Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled." }, { "UniqueTag": "OutputFileCleanup", "Description": "Tests that the Ola - Output File Cleanup Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled and that the clean up setting for the job is set as specified (default 30 (days))." }, { "UniqueTag": "DeleteBackupHistory", "Description": "Tests that the Ola - Delete Backup History Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled and that the clean up setting for the job is set as specified (default 30 (days))." }, { "UniqueTag": "PurgeJobHistory", "Description": "Tests that the Ola - Purge Job History Job (using the specified name defaults to Olas default naming) enabled setting is set as specified (default true), the schedules are set as specified (default true) and enabled and that the clean up setting for the job is set as specified (default 30 (days))." }, { "UniqueTag": "PowerPlan", "Description": "Tests that the Server Power Plan is set to High Performance." }, { "UniqueTag": "InstanceConnection", "Description": "Tests that a SQL query can be run, that the specified authentication scheme (default kerberos) is being used, that the host responds to one ping and that the host supports PS Remoting." }, { "UniqueTag": "SPN", "Description": "Tests that all default SQL SPNs have been correctly registered." }, { "UniqueTag": "DiskCapacity", "Description": "Tests that each drive has at least the specified percentage (default 20) free space." }, { "UniqueTag": "PingComputer", "Description": "Tests that a host has been pinged a specified number of times (default 3) and that the average response time is less than specified (default 10 (ms))." }, { "UniqueTag": "FKCKTrusted", "Description": "Tests that each foreign key and each constraint is trusted." }, { "UniqueTag": "MaxDopInstance", "Description": "Tests that the instance level MaxDop settings on all instances (except those specified default blank) are set to the recommended value if specified (default false) or to the specified value (default 0)." }, { "UniqueTag": "MaxDopDatabase", "Description": "Tests that the database level MaxDop settings for all databases on all instances from version 2016 up are set to the specified value (default 0)." }, { "UniqueTag": "DatabaseStatus", "Description": "Tests that there are no databases on an instance that are in a state of AutoClose, Offline, ReadOnly, Restoring, Recovery, Recovery Pending, EmergencyMode, Suspect or StandBy. Databases that are in ReadOnly,Offline and Restoring mode can be specified (default none)." }, { "UniqueTag": "CPUPrioritisation", "Description": "Tests that the CPU is prioritised for background activity over user UI experience. unless specified to ignore (default true)." }, { "UniqueTag": "DiskAllocationUnit", "Description": "Tests that the disks available to the server are formatted for optimum performance (64KB allocation unit) unless a specified disk name (default none)." }, { "UniqueTag": "DatabaseExists", "Description": "Tests that the databases are specified are on the instance (Note - Does not check if they are available - Use DatabaseStatus for that)." }, { "UniqueTag": "TraceFlagsExpected", "Description": "Tests that the specified (default none) trace flags are running on the instance." }, { "UniqueTag": "TraceFlagsNotExpected", "Description": "Tests that the specified (default none) trace flags are not running on the instance." }, { "UniqueTag": "CLREnabled", "Description": "Tests that the CLR Enabled configuration setting is set as specified (default false)." }, { "UniqueTag": "CrossDBOwnershipChaining", "Description": "Tests that the Cross Database Ownership Chaining configuration setting is set as specified (default false)." }, { "UniqueTag": "DatabaseMailEnabled", "Description": "Tests that the Database Mail XPs configuration setting is set as specified (default false)." }, { "UniqueTag": "DefaultFilePath", "Description": "Tests that the default file path for an instance is not the C drive." }, { "UniqueTag": "AdHocDistributedQueriesEnabled", "Description": "Tests that the AdHoc Distributed Queries configuration setting is set as specified (default false)." }, { "UniqueTag": "XpCmdShellDisabled", "Description": "Tests that the XP CmdShell configuration setting is set as specified (default true - meaning it should be disabled)." }, { "UniqueTag": "OLEAutomationProceduresDisabled", "Description": "Tests that the OLE Automation Procedures configuration setting is set as specified (default 0 - meaning it should be disabled)." }, { "UniqueTag": "RemoteAccessDisabled", "Description": "Tests that the Remote Access configuration setting is set as specified (default true - meaning it should be disabled)." }, { "UniqueTag": "ScanForStartupProceduresDisabled", "Description": "Tests that the Scan For Startup Procedures configuration setting is set as specified (default 0 - meaning it should be disabled)." }, { "UniqueTag": "JobHistory", "Description": "Tests that the job history configuration for max number of rows in the whole agent log is greater than or equal to the specified value (default 1000) and that the max number of rows per job configuration is greater than or equal to the specified value (default 100)." }, { "UniqueTag": "DefaultTrace", "Description": "Tests that the default trace configuration is set to enabled." }, { "UniqueTag": "LongRunningJob", "Description": "Tests that any currently running agent jobs have not been running for longer than the configured percentage (default 50) of time more than the average job run." }, { "UniqueTag": "LastJobRunTime", "Description": "Tests that the last durations of the agent jobs were not longer than the configured percentage (default 50) of time more than the average job run." }, { "UniqueTag": "LatestBuild", "Description": "Tests that the sees is SQL Server has the newest Service Packs and CUs installed." }, { "UniqueTag": "ContainedDBAutoClose", "Description": "Tests that each contained database has AUTO CLOSE disabled." }, { "UniqueTag": "SqlAgentProxiesNoPublicRole", "Description": "Tests that the public role does not have access to SQL Agent Proxies." }, { "UniqueTag": "SymmetricKeyEncryptionLevel", "Description": "Tests that Symmetric Key Encryption Level is at least AES_128 in non-system databases." }, { "UniqueTag": "AsymmetricKeySize", "Description": "Tests that Asymmetric Key Sizes are at least 2048 in non-system databases." }, { "UniqueTag": "HideInstance", "Description": "Tests that each hide instance is set to YES for the instance." }, { "UniqueTag": "CLRAssembliesSafe", "Description": "Tests that CLR assembly permissions are set to SAFE_ACCESS." }, { "UniqueTag": "EngineServiceAdmin", "Description": "Tests that the SQL Engine service account is not a local administrator." }, { "UniqueTag": "AgentServiceAdmin", "Description": "Tests that the SQL Agent service account is not a local administrator." }, { "UniqueTag": "FullTextServiceAdmin", "Description": "Tests that the SQL Full Text service account is not a local administrator." }, { "UniqueTag": "LoginAuditFailed", "Description": "Tests that server level logins are recorded for failed logins." }, { "UniqueTag": "LoginAuditSuccessful", "Description": "Tests that server level logins are recorded for successful and failed logins." }, { "UniqueTag": "LocalWindowsGroup", "Description": "Tests that no local Windows group has a SQL Login." }, { "UniqueTag": "PublicRolePermission", "Description": "Tests that server public role does not have any permissions." }, { "UniqueTag": "GuestUserConnect", "Description": "Tests that guest user does not have CONNECT permission." }, { "UniqueTag": "BuiltInAdmin", "Description": "Tests to see if the BUILTIN\\Administrator login exist." }, { "UniqueTag": "QueryStoreEnabled", "Description": "Tests to see Query Store is enabled on each database except those specified." }, { "UniqueTag": "QueryStoreDisabled", "Description": "Tests to see Query Store is disabled on each database except those specified." }, { "UniqueTag": "ContainedDBSQLAuth", "Description": "Tests to see a contained database contains sql authenticated users." }, { "UniqueTag": "LoginCheckPolicy", "Description": "Tests to see if CHECK_POLICY property is set for all logins." }, { "UniqueTag": "LoginPasswordExpiration", "Description": "Tests to see if password expiration policy is set for sql logins in sysadmin role." }, { "UniqueTag": "LoginMustChange", "Description": "Tests to see if password must change is enabled for new logins." }, { "UniqueTag": "NonStandardPort", "Description": "Tests to see if the SQL Server Instances are NOT running on the default port of 1433." }, { "UniqueTag": "AgentMailProfile", "Description": "Tests to see if the SQL Server Agent Alert System has an enabled database mail profile." }, { "UniqueTag": "SQLMailXPsDisabled", "Description": "Tests to see SQL Mail XPs are disabled." }, { "UniqueTag": "PublicPermission", "Description": "Tests to see if public role has extra permissions based on CIS requirements." }, { "UniqueTag": "ServerProtocol", "Description": "Tests to see if the SQL Server Instances are running other protocols besides TCP/IP." } ] ================================================ FILE: source/internal/configurations/configuration.ps1 ================================================ # Fred magic #Set-PSFConfig -Handler { if (Get-PSFTaskEngineCache -Module dbachecks -Name module-imported) { Write-PSFMessage -Level Warning -Message "This setting will only take effect on the next console start" } } #Add some validation for values with limited options [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidAssignmentToAutomaticVariable', 'input')] $LogFileComparisonValidationssb = { param ([string]$input) if ($input -in ('average', 'maximum')) { [PsCustomObject]@{Success = $true; value = $input } } else { [PsCustomObject]@{Success = $false; message = "must be average or maximum - $input" } } } Register-PSFConfigValidation -Name validation.LogFileComparisonValidations -ScriptBlock $LogFileComparisonValidationssb $EmailValidationSb = { param ([string]$input) $EmailRegEx = "^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$" if (($input -match $EmailRegEx) -or -not ($input) ) { [PsCustomObject]@{Success = $true; value = $input } } else { [PsCustomObject]@{Success = $false; message = "does not appear to be an email address - $input" } } } Register-PSFConfigValidation -Name validation.EmailValidation -ScriptBlock $EmailValidationSb $__dbachecksNotv5 = 'ADUser', 'BuiltInAdmin', 'EngineServiceAdmin', 'FullTextServiceAdmin', 'LocalWindowsGroup', 'PublicPermission', 'SqlBrowserServiceAccount', 'TempDbConfiguration','CertificateExpiration', 'DatabaseExists', 'DatabaseGrowthEvent', 'DatafileAutoGrowthType', 'DisabledIndex', 'DuplicateIndex', 'FileGroupBalanced', 'FutureFileGrowth', 'IdentityUsage', 'LastDiffBackup', 'LastFullBackup', 'LastGoodCheckDb', 'LastLogBackup', 'LogfilePercentUsed', 'LogfileSize', 'MaxDopDatabase', 'OrphanedUser', 'SymmetricKeyEncryptionLevel', 'TestLastBackup', 'TestLastBackupVerifyOnly', 'UnusedIndex', 'PowerPlan', 'SPN', 'DiskCapacity', 'PingComputer', 'CPUPrioritisation', 'DiskAllocationUnit', 'NonStandardPort', 'ServerProtocol', 'OlaInstalled', 'SystemFull', 'UserFull', 'UserDiff', 'UserLog', 'CommandLog', 'SystemIntegrityCheck', 'UserIntegrityCheck', 'UserIndexOptimize', 'OutputFileCleanup', 'DeleteBackupHistory', 'PurgeJobHistory', 'DomainName', 'OrganizationalUnit', 'ClusterHealth', 'LogShippingPrimary', 'LogShippingSecondary' Set-PSFConfig -Module dbachecks -Name checks.notv5ready -Value @($__dbachecksNotv5) -Initialize -Description "Checks that have not been converted to v5 yet" # some configs to help with autocompletes and other module level stuff #apps $defaultRepo = Join-Path -Path $script:ModuleRoot -ChildPath checks Set-PSFConfig -Module dbachecks -Name app.checkrepos -Value @($defaultRepo) -Initialize -Description "Where Pester tests/checks are stored" Set-PSFConfig -Module dbachecks -Name app.sqlinstance -Value $null -Initialize -Description "List of SQL Server instances that SQL-based tests will run against" Set-PSFConfig -Module dbachecks -Name app.computername -Value $null -Initialize -Description "List of Windows Servers that Windows-based tests will run against" Set-PSFConfig -Module dbachecks -Name app.sqlcredential -Value $null -Initialize -Description "The universal SQL credential if Trusted/Windows Authentication is not used" Set-PSFConfig -Module dbachecks -Name app.wincredential -Value $null -Initialize -Description "The universal Windows if default Windows Authentication is not used" if ($IsLinux) { Set-PSFConfig -Module dbachecks -Name app.localapp -Value "$home/dbachecks" -Initialize -Description "Persisted files live here" Set-PSFConfig -Module dbachecks -Name app.maildirectory -Value "$home/dbachecks/dbachecks.mail" -Initialize -Description "Files for mail are stored here" } else { Set-PSFConfig -Module dbachecks -Name app.localapp -Value "$env:localappdata\dbachecks" -Initialize -Description "Persisted files live here" Set-PSFConfig -Module dbachecks -Name app.maildirectory -Value "$env:localappdata\dbachecks\dbachecks.mail" -Initialize -Description "Files for mail are stored here" } Set-PSFConfig -Module dbachecks -Name app.cluster -Value $null -Initialize -Description "One host name for each cluster for the HADR checks" # Policy Configs #instance Set-PSFConfig -Module dbachecks -Name policy.instance.sqlenginestart -Value 'Automatic' -Initialize -Description "The expected start type of the SQL Engine Service - Automatic, Manual, Disabled - Defaults to Automatic" Set-PSFConfig -Module dbachecks -Name policy.instance.sqlenginestate -Value 'Running' -Initialize -Description "The expected state of the SQL Engine Service - Running, Stopped - Defaults to Running" Set-PSFConfig -Module dbachecks -Name policy.instance.memorydumpsdaystocheck -Value $null -Initialize -Description "The number of days to go back and check for memory dumps" #Storage Set-PSFConfig -Module dbachecks -Name policy.storage.backuppath -Value $null -Initialize -Description "Enables tests to check if servers have access to centralized backup location" #Backup Set-PSFConfig -Module dbachecks -Name policy.backup.testserver -Value $null -Initialize -Description "Destination server for backuptests" Set-PSFConfig -Module dbachecks -Name policy.backup.datadir -Value $null -Initialize -Description "Destination server data directory" Set-PSFConfig -Module dbachecks -Name policy.backup.logdir -Value $null -Initialize -Description "Destination server log directory" Set-PSFConfig -Module dbachecks -Name policy.backup.fullmaxdays -Value 7 -Initialize -Description "Maximum number of days before Full Backups are considered outdated" Set-PSFConfig -Module dbachecks -Name policy.backup.diffmaxhours -Value 25 -Initialize -Description "Maximum number of hours before Diff Backups are considered outdated" Set-PSFConfig -Module dbachecks -Name policy.backup.logmaxminutes -Value 15 -Initialize -Description "Maximum number of minutes before Log Backups are considered outdated" Set-PSFConfig -Module dbachecks -Name policy.backup.newdbgraceperiod -Value 0 -Initialize -Description "The number of hours a newly created database is allowed to not have backups" Set-PSFConfig -Module dbachecks -Name policy.backup.defaultbackupcompression -Validation bool -Value $true -Initialize -Description "Default Backup Compression should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.security.clrenabled -Validation bool -Value $false -Initialize -Description "CLR Enabled should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.security.crossdbownershipchaining -Validation bool -Value $false -Initialize -Description "Cross Database Ownership Chaining should be disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.security.databasemailenabled -Validation bool -Value $false -Initialize -Description "Database Mail XPs should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.security.adhocdistributedqueriesenabled -Validation bool -Value $false -Initialize -Description "Ad Hoc Distributed Queries should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.security.xpcmdshelldisabled -Validation bool -Value $true -Initialize -Description "XP CmdShell should be disabled `$true or enabled `$false" Set-PSFConfig -Module dbachecks -Name policy.security.oleautomationproceduresdisabled -Validation bool -Value $true -Initialize -Description "OLE Automation Procedures should be disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.security.remoteaccessdisabled -Value 0 -Initialize -Description "Remote Access should be disabled 0" Set-PSFConfig -Module dbachecks -Name policy.security.scanforstartupproceduresdisabled -Validation bool -Value $true -Initialize -Description "Scan For Startup Procedures disabled `$true or enabled `$false" Set-PSFConfig -Module dbachecks -Name policy.security.latestbuild -Validation bool -Value $true -Initialize -Description "SQL Server should have the latest SQL build (service packs/CUs) installed" Set-PSFConfig -Module dbachecks -Name policy.security.containedbautoclose -Validation bool -Value $false -Initialize -Description "Contained databases should have auto close enabled" #diskspce Set-PSFConfig -Module dbachecks -Name policy.diskspace.percentfree -Value 20 -Initialize -Description "Percent disk free" #DBCC Set-PSFConfig -Module dbachecks -Name policy.dbcc.maxdays -Value 7 -Initialize -Description "Maximum number of days before DBCC CHECKDB is considered outdated" #Encryption Set-PSFConfig -Module dbachecks -Name policy.certificateexpiration.excludedb -Value @('master', 'msdb', 'model', 'tempdb') -Initialize -Description "Databases to exclude from expired certificate checks" Set-PSFConfig -Module dbachecks -Name policy.certificateexpiration.warningwindow -Value 1 -Initialize -Description "The number of months prior to a certificate being expired that you want warning about" #Identity Set-PSFConfig -Module dbachecks -Name policy.identity.usagepercent -Value 90 -Initialize -Description "Maximum percentage of max of identity column" #Network Set-PSFConfig -Module dbachecks -Name policy.network.latencymaxms -Value 40 -Initialize -Description "Max network latency average" #Recovery Model Set-PSFConfig -Module dbachecks -Name policy.recoverymodel.type -Value "Full" -Initialize -Description "Standard recovery model" Set-PSFConfig -Module dbachecks -Name policy.recoverymodel.excludedb -Value @('master', 'tempdb') -Initialize -Description "Databases to exclude from standard recovery model check" #Logins Set-PSFConfig -Module dbachecks -Name policy.adloginuser.excludecheck -Value "" -Initialize -Description "Active Directory User logins to exclude from test." Set-PSFConfig -Module dbachecks -Name policy.adlogingroup.excludecheck -Value "" -Initialize -Description "Active Directory Groups logins to exclude from test." #DBOwners Set-PSFConfig -Module dbachecks -Name policy.validdbowner.name -Value "sa" -Initialize -Description "The database owner account should be this user" Set-PSFConfig -Module dbachecks -Name policy.validdbowner.excludedb -Value @('master', 'msdb', 'model', 'tempdb') -Initialize -Description "Databases to exclude from valid dbowner checks" Set-PSFConfig -Module dbachecks -Name policy.invaliddbowner.name -Value "sa" -Initialize -Description "The database owner account should not be this user" Set-PSFConfig -Module dbachecks -Name policy.invaliddbowner.excludedb -Value @('master', 'msdb', 'model', 'tempdb') -Initialize -Description "Databases to exclude from invalid dbowner checks" #Error Log Set-PSFConfig -Module dbachecks -Name policy.errorlog.warningwindow -Value 2 -Initialize -Description "The number of days prior to check for error log issues" Set-PSFConfig -Module dbachecks -Name policy.errorlog.logcount -Value -1 -Initialize -Description "The minimum number of error log files that should be configured. -1 means off/default" #DAC Set-PSFConfig -Module dbachecks -Name policy.dacallowed -Validation bool -Value $true -Initialize -Description "DAC should be allowed `$true or disallowed `$false" #OLE Automation Set-PSFConfig -Module dbachecks -Name policy.oleautomation -Validation bool -Value $false -Initialize -Description "OLE Automation should be enabled `$true or disabled `$false" #Two Digit Year Cutoff Set-PSFConfig -Module dbachecks -Name policy.twodigityearcutoff -Value 2049 -Initialize -Description "The value for 'Two Digit Year Cutoff' configuration. Default is 2049. " #Connectivity Set-PSFConfig -Module dbachecks -Name policy.connection.authscheme -Value "Kerberos" -Initialize -Description "Auth requirement (Kerberos, NTLM, etc)" Set-PSFConfig -Module dbachecks -Name policy.connection.pingmaxms -Value 10 -Initialize -Description "Maximum response time in ms" Set-PSFConfig -Module dbachecks -Name policy.connection.pingcount -Value 3 -Initialize -Description "Number of times to ping a server to establish average response time" #HADR Set-PSFConfig -Module dbachecks -Name policy.hadr.agtcpport -Value "" -Initialize -Description "The TCPPort for the HADR listener check" Set-PSFConfig -Module dbachecks -Name policy.hadr.tcpport -Value "1433" -Initialize -Description "The TCPPort for the HADR replica check" Set-PSFConfig -Module dbachecks -Name policy.hadr.endpointname -Value "Hadr_Endpoint" -Initialize -Description "The name for the HADR Endpoint check" Set-PSFConfig -Module dbachecks -Name policy.hadr.endpointport -Value 5022 -Initialize -Description "The TCPPort for the HADR endpoint check" Set-PSFConfig -Module dbachecks -Name policy.hadr.failureconditionlevel -Value 3 -Initialize -Description "Availability Group flexible automatic failover policy for the HADR cluster check" Set-PSFConfig -Module dbachecks -Name policy.hadr.healthchecktimeout -Value 30000 -Initialize -Description "Availability Group healthcheck timeout for the HADR cluster check" Set-PSFConfig -Module dbachecks -Name policy.hadr.leasetimeout -Value 20000 -Initialize -Description "Availability Group Lease timeout for the HADR cluster check" Set-PSFConfig -Module dbachecks -Name policy.hadr.sessiontimeout -Value 10 -Initialize -Description "Availability Group Replica Session timeout for the HADR replica check" Set-PSFConfig -Module dbachecks -Name policy.cluster.NetworkProtocolsIPV4 -Value @('Internet Protocol Version 4 (TCP/IPv4)', 'Client for Microsoft Networks', 'File and Printer Sharing for Microsoft Networks') -Initialize -Description "Minimum Private Cluster Network protocols for the HADR Cluster check" Set-PSFConfig -Module dbachecks -Name policy.cluster.hostrecordttl -Value 1200 -Initialize -Description "Cluster Network Resource - HostRecordTTL for the HADR Cluster check" Set-PSFConfig -Module dbachecks -Name policy.cluster.registerallprovidersIP -Value 0 -Initialize -Description "Cluster Network Resource - RegisterAllProvidersIP for the HADR Cluster check" #Dump Files Set-PSFConfig -Module dbachecks -Name policy.dump.maxcount -Value 1 -Initialize -Description "Maximum number of expected dumps" #pageverify #TODO: Only 2 part name - should we fix this? Set-PSFConfig -Module dbachecks -Name policy.pageverify -Value "Checksum" -Initialize -Description "Page verify option should be set to this value" # InstanceMaxDop Set-PSFConfig -Module dbachecks -Name policy.instancemaxdop.userecommended -Value $false -Initialize -Description "Use the recommendation from Test-DbaMaxDop to test the Max DOP settings - If set to false the value in policy.instancemaxdop.maxdop is used" Set-PSFConfig -Module dbachecks -Name policy.instancemaxdop.maxdop -Value 0 -Initialize -Description "The value for the Instance Level MaxDop Settings we expect" Set-PSFConfig -Module dbachecks -Name policy.instancemaxdop.excludeinstance -Value @() -Initialize -Description "Any Instances to exclude from checking Instance Level MaxDop - Useful if your estate contains SQL instances supporting Sharepoint for example" # Database Set-PSFConfig -Module dbachecks -Name policy.database.autoclose -Validation bool -Value $false -Initialize -Description "Auto Close should be allowed `$true or disallowed `$false" Set-PSFConfig -Module dbachecks -Name policy.database.autoshrink -Validation bool -Value $false -Initialize -Description "Auto Shrink should be allowed `$true or disallowed `$false" Set-PSFConfig -Module dbachecks -Name policy.database.maxvlf -Value 512 -Initialize -Description "Max virtual log files" Set-PSFConfig -Module dbachecks -Name policy.database.autocreatestatistics -Validation bool -Value $true -Initialize -Description "Auto Create Statistics should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.database.autoupdatestatistics -Validation bool -Value $true -Initialize -Description "Auto Update Statistics should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.database.autoupdatestatisticsasynchronously -Validation bool -Value $false -Initialize -Description "Auto Update Statistics Asynchronously should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.database.filegrowthexcludedb -Value @() -Initialize -Description "Databases to exclude from the file growth check" Set-PSFConfig -Module dbachecks -Name policy.database.filegrowthtype -Value "kb" -Initialize -Description "Growth Type should be 'kb' or 'percent'" Set-PSFConfig -Module dbachecks -Name policy.database.filegrowthvalue -Value 65535 -Initialize -Description "The auto growth value (in kb) should be equal or higher than this value. Example: A value of 65535 means at least 64MB. " Set-PSFConfig -Module dbachecks -Name policy.database.logfilecount -Value 1 -Initialize -Description "The number of Log files expected on a database" Set-PSFConfig -Module dbachecks -Name policy.database.logfilesizepercentage -Value 100 -Initialize -Description "Maximum percentage of Data file Size that logfile is allowed to be." Set-PSFConfig -Module dbachecks -Name policy.database.logfilesizecomparison -Validation validation.logfilecomparisonvalidations -Value 'average' -Initialize -Description "How to compare data and log file size, options are maximum or average" Set-PSFConfig -Module dbachecks -Name policy.database.filebalancetolerance -Value 5 -Initialize -Description "Percentage for Tolerance for checking for balanced files in a filegroups" Set-PSFConfig -Module dbachecks -Name policy.database.filegrowthfreespacethreshold -Value 20 -Initialize -Description "Integer representing percentage of free space within a database file before warning" Set-PSFConfig -Module dbachecks -Name policy.database.wrongcollation -Value @('ReportingServer', 'ReportingServerTempDB') -Initialize -Description "Databases that doesnt match server collation check" Set-PSFConfig -Module dbachecks -Name policy.database.maxdopexcludedb -Value @() -Initialize -Description "Database Names that we don't want to check for maxdop" Set-PSFConfig -Module dbachecks -Name policy.database.maxdop -Value 0 -Initialize -Description "The value for the database maxdop that we expect" Set-PSFConfig -Module dbachecks -Name policy.database.status.excludereadonly -Value @() -Initialize -Description "Database names that we expect to be readonly" Set-PSFConfig -Module dbachecks -Name policy.database.status.excludeoffline -Value @() -Initialize -Description "Database names that we expect to be offline" Set-PSFConfig -Module dbachecks -Name policy.database.status.excluderestoring -Value @() -Initialize -Description "Database names that we expect to be restoring" Set-PSFConfig -Module dbachecks -Name database.querystoreenabled.excludedb -Value @('model', 'tempdb', 'master') -Initialize -Description "A List of databases that we do not want to check for Query Store enabled" Set-PSFConfig -Module dbachecks -Name database.querystoredisabled.excludedb -Value @('model', 'tempdb', 'master') -Initialize -Description "A List of databases that we do not want to check for Query Store disabled" Set-PSFConfig -Module dbachecks -Name database.compatibilitylevel.excludedb -Value @() -Initialize -Description "A list of databases that we do not want to check compatibility level" Set-PSFConfig -Module dbachecks -Name database.guestuser.excludedb -Value @('master', 'tempdb', 'msdb') -Initialize -Description "A list of databases that we do not want to check guest user connect permissions for" Set-PSFConfig -Module dbachecks -Name policy.database.filegrowthdaystocheck -Value $null -Initialize -Description "The number of days to go back to check for growth events" Set-PSFConfig -Module dbachecks -Name policy.database.trustworthyexcludedb -Value @('msdb') -Initialize -Description "A List of databases that we do not want to check for Trustworthy being on" Set-PSFConfig -Module dbachecks -Name policy.database.duplicateindexexcludedb -Value @('msdb', 'ReportServer', 'ReportServerTempDB') -Initialize -Description "A List of databases we do not want to check for Duplicate Indexes" Set-PSFConfig -Module dbachecks -Name policy.database.clrassembliessafeexcludedb -Value @() -Initialize -Description " A List of database what we do not want to check for SAFE CLR Assemblies" Set-PSFConfig -Module dbachecks -Name policy.database.pseudosimpleexcludedb -Value @('tempdb', 'model') -Initialize -Description "A List of databases that we do not want to check for pseudosimple recovery modelasd a" Set-PSFConfig -Module dbachecks -Name policy.database.contdbautocloseexclude -Value @('msdb') -Initialize -Description "A List of contained database that we we do not want to check for autoclose" Set-PSFConfig -Module dbachecks -Name policy.database.contdbsqlauthexclude -Value @() -Initialize -Description "A list of databases that we do not want to check for contained databases with SQL authenticated users" Set-PSFConfig -Module dbachecks -Name policy.database.logfilepercentused -Value 75 -Initialize -Description " The % log used we should stay below" # Policy for Ola Hallengren Maintenance Solution Set-PSFConfig -Module dbachecks -Name policy.ola.installed -Validation bool -Value $true -Initialize -Description "Checks to see if Ola Hallengren solution is installed" Set-PSFConfig -Module dbachecks -Name policy.ola.database -Validation string -Value 'master' -Initialize -Description "The database where Ola's maintenance solution is installed" Set-PSFConfig -Module dbachecks -Name policy.ola.systemfullenabled -Validation bool -Value $true -Initialize -Description "Ola's Full System Database Backup should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.userfullenabled -Validation bool -Value $true -Initialize -Description "Ola's Full User Database Backup should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.userdiffenabled -Validation bool -Value $true -Initialize -Description "Ola's Diff User Database Backup should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.userlogenabled -Validation bool -Value $true -Initialize -Description "Ola's Log User Database Backup should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.systemfullscheduled -Validation bool -Value $true -Initialize -Description "Ola's Full System Database Backup should be scheduled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.userfullscheduled -Validation bool -Value $true -Initialize -Description "Ola's Full User Database Backup should be scheduled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.userdiffscheduled -Validation bool -Value $true -Initialize -Description "Ola's Diff User Database Backup should be scheduled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.userlogscheduled -Validation bool -Value $true -Initialize -Description "Ola's Log User Database Backup should be scheduled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.systemfullretention -Value 192 -Initialize -Description "Ola's Full System Database Backup retention number of hours" Set-PSFConfig -Module dbachecks -Name policy.ola.userfullretention -Value 192 -Initialize -Description "Ola's Full User Database Backup retention number of hours" Set-PSFConfig -Module dbachecks -Name policy.ola.userdiffretention -Value 192 -Initialize -Description "Ola's Diff User Database Backup retention number of hours" Set-PSFConfig -Module dbachecks -Name policy.ola.userlogretention -Value 192 -Initialize -Description "Ola's Log User Database Backup retention number of hours" Set-PSFConfig -Module dbachecks -Name policy.ola.CommandLogenabled -Validation bool -Value $true -Initialize -Description "Ola's CommandLog Cleanup should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.CommandLogscheduled -Validation bool -Value $true -Initialize -Description "Ola's CommandLog Cleanup should be scheduled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.CommandLogCleanUp -Value 30 -Initialize -Description "Ola's CommandLog Cleanup setting should be this many days" Set-PSFConfig -Module dbachecks -Name policy.ola.SystemIntegrityCheckenabled -Validation bool -Value $true -Initialize -Description "Ola's System Database Integrity should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.SystemIntegrityCheckscheduled -Validation bool -Value $true -Initialize -Description "Ola's System Database Integrity should be scheduled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.UserIntegrityCheckenabled -Validation bool -Value $true -Initialize -Description "Ola's User Database Integrity should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.UserIntegrityCheckscheduled -Validation bool -Value $true -Initialize -Description "Ola's User Database Integrity should be scheduled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.UserIndexOptimizeenabled -Validation bool -Value $true -Initialize -Description "Ola's User Index Optimization should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.UserIndexOptimizescheduled -Validation bool -Value $true -Initialize -Description "Ola's User Index Optimization should be scheduled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.OutputFileCleanupenabled -Validation bool -Value $true -Initialize -Description "Ola's Output File Cleanup should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.OutputFileCleanupscheduled -Validation bool -Value $true -Initialize -Description "Ola's Output File Cleanup should be scheduled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.OutputFileCleanUp -Value 30 -Initialize -Description "Ola's OutputFile Cleanup setting should be this many days" Set-PSFConfig -Module dbachecks -Name policy.ola.DeleteBackupHistoryenabled -Validation bool -Value $true -Initialize -Description "Ola's Delete Backup History should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.DeleteBackupHistoryscheduled -Validation bool -Value $true -Initialize -Description "Ola's Delete Backup History should be scheduled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.DeleteBackupHistoryCleanUp -Value 30 -Initialize -Description "Ola's Delete Backup History Cleanup setting should be this many days" Set-PSFConfig -Module dbachecks -Name policy.ola.PurgeJobHistoryenabled -Validation bool -Value $true -Initialize -Description "Ola's Purge Job History should be enabled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.PurgeJobHistoryscheduled -Validation bool -Value $true -Initialize -Description "Ola's Purge Job History should be scheduled `$true or disabled `$false" Set-PSFConfig -Module dbachecks -Name policy.ola.PurgeJobHistoryCleanUp -Value 30 -Initialize -Description "Ola's Purge Backup History Cleanup setting should be this many days" Set-PSFConfig -Module dbachecks -Name ola.JobName.SystemFull -Value 'DatabaseBackup - SYSTEM_DATABASES - FULL' -Initialize -Description "The name for the Ola System Full Job" Set-PSFConfig -Module dbachecks -Name ola.JobName.UserFull -Value 'DatabaseBackup - USER_DATABASES - FULL' -Initialize -Description "The name for the Ola User Full Job" Set-PSFConfig -Module dbachecks -Name ola.JobName.UserDiff -Value 'DatabaseBackup - USER_DATABASES - DIFF' -Initialize -Description "The name for the Ola User Diff Job" Set-PSFConfig -Module dbachecks -Name ola.JobName.UserLog -Value 'DatabaseBackup - USER_DATABASES - Log' -Initialize -Description "The name for the Ola User Log Job" Set-PSFConfig -Module dbachecks -Name ola.JobName.CommandLogCleanup -Value 'CommandLog Cleanup' -Initialize -Description "The name for the Ola CommandLog Cleanup Job" Set-PSFConfig -Module dbachecks -Name ola.JobName.SystemIntegrity -Value 'DatabaseIntegrityCheck - SYSTEM_DATABASES' -Initialize -Description "The name for the Ola System Integrity Job" Set-PSFConfig -Module dbachecks -Name ola.JobName.UserIntegrity -Value 'DatabaseIntegrityCheck - USER_DATABASES' -Initialize -Description "The name for the Ola User Integrity Job" Set-PSFConfig -Module dbachecks -Name ola.JobName.UserIndex -Value 'IndexOptimize - USER_DATABASES' -Initialize -Description "The name for the Ola User Index Job" Set-PSFConfig -Module dbachecks -Name ola.JobName.OutputFileCleanup -Value 'Output File Cleanup' -Initialize -Description "The name for the Ola Output File Cleanup Job" Set-PSFConfig -Module dbachecks -Name ola.JobName.DeleteBackupHistory -Value 'sp_delete_backuphistory' -Initialize -Description "The name for the Ola Delete Backup History Job" Set-PSFConfig -Module dbachecks -Name ola.JobName.PurgeBackupHistory -Value 'sp_purge_jobhistory' -Initialize -Description "The name for the Ola Delete Purge History Job" # xevents Set-PSFConfig -Module dbachecks -Name policy.xevent.requiredexists -Value $null -Initialize -Description "List of XE Sessions that should exist. This does not check if they are running" Set-PSFConfig -Module dbachecks -Name policy.xevent.validrunningsession -Value $null -Initialize -Description "List of XE Sessions that can be be running." Set-PSFConfig -Module dbachecks -Name policy.xevent.requiredrunningsession -Value $null -Initialize -Description "List of XE Sessions that should be running." Set-PSFConfig -Module dbachecks -Name policy.xevent.requiredstoppedsession -Value $null -Initialize -Description "List of XE Sessions that should not be running." # sp_WhoIsActive Set-PSFConfig -Module dbachecks -Name policy.whoisactive.database -Value "master" -Initialize -Description "Which database should contain the sp_WhoIsActive stored procedure" #Build Set-PSFConfig -Module dbachecks -Name policy.build.warningwindow -Value 6 -Initialize -Description "The number of months prior to a build being unsupported that you want warning about" Set-PSFConfig -Module dbachecks -Name policy.build.behind -Value $null -Initialize -Description "The max number of service packs or cumulative updates a build can be behind by (ex. 1SP or 3CU). Null by default." # The frequency of the Ola Hallengrens User Full backups # See https://msdn.microsoft.com/en-us/library/microsoft.sqlserver.management.smo.agent.jobschedule.frequencyinterval.aspx # for full options # 1 for Sunday 127 for every day # exclude databases Set-PSFConfig -Module dbachecks -Name policy.asymmetrickeysize.excludedb -Value @('master', 'msdb', 'tempdb') -Initialize -Description "Databases to exclude from asymmetric key size checks" Set-PSFConfig -Module dbachecks -Name policy.autoclose.excludedb -Value @() -Initialize -Description "Databases to exclude from autoclose key size checks" Set-PSFConfig -Module dbachecks -Name policy.autoshrink.excludedb -Value @() -Initialize -Description "Databases to exclude from autoclose key size checks" Set-PSFConfig -Module dbachecks -Name policy.vlf.excludedb -Value @('master', 'msdb', 'tempdb', 'model') -Initialize -Description "Databases to exclude from asymmetric key size checks" Set-PSFConfig -Module dbachecks -Name policy.logfilecount.excludedb -Value @() -Initialize -Description "Databases to exclude from log file count checks" Set-PSFConfig -Module dbachecks -Name policy.autocreatestats.excludedb -Value @() -Initialize -Description "Databases to exclude from the auto create stats checks" Set-PSFConfig -Module dbachecks -Name policy.autoupdatestats.excludedb -Value @() -Initialize -Description "Databases to exclude from the auto update stats checks" Set-PSFConfig -Module dbachecks -Name policy.autoupdatestatisticsasynchronously.excludedb -Value @() -Initialize -Description "Databases to exclude from the auto update stats asynchronously checks" Set-PSFConfig -Module dbachecks -Name policy.database.statusexcludedb -Value @() -Initialize -Description "Databases to exclude from the database status checks" Set-PSFConfig -Module dbachecks -Name policy.database.symmetrickeyencryptionlevelexcludedb -Value @('master', 'msdb', 'tempdb') -Initialize -Description "Databases to exclude from the Symmetric Key Encryption Level checks" Set-PSFConfig -Module dbachecks -Name policy.database.fkcktrustedexclude -Value @() -Initialize -Description "Databases to exclude from the foreign key and constraints trusted checks" # skips - these are for whole checks that should not run by default or internal commands that can't be skipped using ExcludeTag # instance Set-PSFConfig -Module dbachecks -Name skip.instance.memorydump -Validation bool -Value $false -Initialize -Description "Skip the memory dump check" Set-PSFConfig -Module dbachecks -Name skip.instance.modeldbgrowth -Validation bool -Value $false -Initialize -Description "Skip the model database growth settings check" Set-PSFConfig -Module dbachecks -Name skip.instance.defaulttrace -Validation bool -Value $false -Initialize -Description "Skip the default trace check" Set-PSFConfig -Module dbachecks -Name skip.instance.dac -Validation bool -Value $false -Initialize -Description "Skip Dedicated Administrator Connection (DAC) check" Set-PSFConfig -Module dbachecks -Name skip.instance.CrossDBOwnershipChaining -Validation bool -Value $false -Initialize -Description "Skip Cross Database Ownership Chaining check" Set-PSFConfig -Module dbachecks -Name skip.instance.SQLMailXPsDisabled -Validation bool -Value $false -Initialize -Description "Skip SQL Mail XPs Disabled check" Set-PSFConfig -Module dbachecks -Name skip.instance.oleautomation -Validation bool -Value $false -Initialize -Description "Skip OLE Automation check" Set-PSFConfig -Module dbachecks -Name skip.instance.oleautomationproceduresdisabled -Validation bool -Value $false -Initialize -Description "Skip OLE Automation Procedures check" Set-PSFConfig -Module dbachecks -Name skip.instance.remoteaccessdisabled -Validation bool -Value $false -Initialize -Description "Skip the remote access check" Set-PSFConfig -Module dbachecks -Name skip.instance.scanforstartupproceduresdisabled -Validation bool -Value $false -Initialize -Description "Skip the scan for startup procedures disabled check" Set-PSFConfig -Module dbachecks -Name skip.instance.latestbuild -Validation bool -Value $false -Initialize -Description "Skip the scan the latest build of SQL Server check" Set-PSFConfig -Module dbachecks -Name skip.instance.suspectpagelimit -Validation bool -Value $false -Initialize -Description "Skip the check for whether the suspect_pages table is nearing the row limit of 1000" Set-PSFConfig -Module dbachecks -Name skip.instance.AdHocWorkload -Validation bool -Value $false -Initialize -Description "Skip the check for whether AdHocWorkload Optimization is enabled" Set-PSFConfig -Module dbachecks -Name skip.instance.AdHocDistributedQueriesEnabled -Validation bool -Value $false -Initialize -Description "Skip the check for whether AdHoc Distributed Queries Enabled settings" Set-PSFConfig -Module dbachecks -Name skip.instance.DefaultFilePath -Validation bool -Value $false -Initialize -Description "Skip the check for Default File Path" Set-PSFConfig -Module dbachecks -Name skip.instance.SaRenamed -Validation bool -Value $false -Initialize -Description "Skip the check for Sa Renamed" Set-PSFConfig -Module dbachecks -Name skip.security.sadisabled -Validation bool -Value $true -Initialize -Description "Skip the check for if the sa login is disabled" Set-PSFConfig -Module dbachecks -Name skip.security.saexist -Validation bool -Value $true -Initialize -Description "Skip the check for a login named sa does not exist" Set-PSFConfig -Module dbachecks -Name skip.instance.DefaultBackupCompression -Validation bool -Value $false -Initialize -Description "Skip the check for default backup compression" Set-PSFConfig -Module dbachecks -Name skip.instance.ErrorLogCount -Validation bool -Value $false -Initialize -Description "Skip the check for the number of Error Log Entries" Set-PSFConfig -Module dbachecks -Name skip.instance.MaxDopInstance -Validation bool -Value $false -Initialize -Description "Skip the check for the Max Dop Instance" Set-PSFConfig -Module dbachecks -Name skip.instance.TwoDigitYearCutoff -Validation bool -Value $false -Initialize -Description "Skip the check for the Two Digit Year Cut off setting" Set-PSFConfig -Module dbachecks -Name skip.instance.TraceFlagsExpected -Validation bool -Value $false -Initialize -Description "Skip the check for expected Trace Flags" Set-PSFConfig -Module dbachecks -Name skip.instance.TraceFlagsNotExpected -Validation bool -Value $false -Initialize -Description "Skip the check for not expected Trace Flags" Set-PSFConfig -Module dbachecks -Name skip.instance.CLREnabled -Validation bool -Value $false -Initialize -Description "Skip the check for CLR Enabled" Set-PSFConfig -Module dbachecks -Name skip.instance.WhoIsActiveInstalled -Validation bool -Value $false -Initialize -Description "Skip the check for whether WhoIsActive is Installed" Set-PSFConfig -Module dbachecks -Name skip.instance.XpCmdShellDisabled -Validation bool -Value $false -Initialize -Description "Skip the check for whether XpCmdShell is Disabled" Set-PSFConfig -Module dbachecks -Name skip.instance.XESessionStopped -Validation bool -Value $false -Initialize -Description "Skip the check for XESessions that are stopped" Set-PSFConfig -Module dbachecks -Name skip.instance.XESessionRunning -Validation bool -Value $false -Initialize -Description "Skip the check for XESessions that should be running" Set-PSFConfig -Module dbachecks -Name skip.instance.XESessionRunningAllowed -Validation bool -Value $false -Initialize -Description "Skip the check for XESessions that are allowed to be running" Set-PSFConfig -Module dbachecks -Name skip.instance.errorlogentries -Validation bool -Value $false -Initialize -Description "Skip the check for errorlog entries" Set-PSFConfig -Module dbachecks -Name skip.instance.tempdb -Validation bool -Value $false -Initialize -Description "Skip all the checks for the tempdb database" Set-PSFConfig -Module dbachecks -Name skip.instance.BackupPathAccess -Validation bool -Value $false -Initialize -Description "Skip the check for the backup path access check" Set-PSFConfig -Module dbachecks -Name skip.instance.networklatency -Validation bool -Value $false -Initialize -Description "Skip the check for network latency" Set-PSFConfig -Module dbachecks -Name skip.instance.linkedserverconnection -Validation bool -Value $false -Initialize -Description "Skip the check for linked server connection" Set-PSFConfig -Module dbachecks -Name skip.instance.maxmemory -Validation bool -Value $false -Initialize -Description "Skip the check for max memory" Set-PSFConfig -Module dbachecks -Name skip.instance.orphanedfile -Validation bool -Value $false -Initialize -Description "Skip the check for orphaned file" Set-PSFConfig -Module dbachecks -Name skip.instance.servernamematch -Validation bool -Value $false -Initialize -Description "Skip the check for server name match" Set-PSFConfig -Module dbachecks -Name skip.instance.supportedbuild -Validation bool -Value $false -Initialize -Description "Skip the checks for supported build" # becuase we can't run this on core if ($IsCoreCLR) { $value = $true } { $value = $false } Set-PSFConfig -Module dbachecks -Name skip.instance.sqlengineserviceaccount -Validation bool -Value $value -Initialize -Description "Skip the checks for sql engine service account" Set-PSFConfig -Module dbachecks -Name skip.dbcc.datapuritycheck -Validation bool -Value $false -Initialize -Description "Skip data purity check in last good dbcc command" Set-PSFConfig -Module dbachecks -Name skip.backup.testing -Validation bool -Value $true -Initialize -Description "Don't run Test-DbaLastBackup by default (it's not read-only)" Set-PSFConfig -Module dbachecks -Name skip.backup.readonly -Validation bool -Value $false -Initialize -Description "Check read-only databases for last backup" Set-PSFConfig -Module dbachecks -Name skip.backup.secondaries -Validation bool -Value $false -Initialize -Description "Check hadr secondary databases for last backup" Set-PSFConfig -Module dbachecks -Name skip.tempdb1118 -Validation bool -Value $false -Initialize -Description "Don't run test for Trace Flag 1118" Set-PSFConfig -Module dbachecks -Name skip.tempdbfilecount -Validation bool -Value $false -Initialize -Description "Don't run test for Temp Database File Count" Set-PSFConfig -Module dbachecks -Name skip.tempdbfilegrowthpercent -Validation bool -Value $false -Initialize -Description "Don't run test for Temp Database File Growth in Percent" Set-PSFConfig -Module dbachecks -Name skip.tempdbfilesonc -Validation bool -Value $false -Initialize -Description "Don't run test for Temp Database Files on C" Set-PSFConfig -Module dbachecks -Name skip.tempdbfilesizemax -Validation bool -Value $false -Initialize -Description "Don't run test for Temp Database Files Max Size" Set-PSFConfig -Module dbachecks -Name skip.connection.remoting -Validation bool -Value $false -Initialize -Description "Skip PowerShell remoting check for connectivity" Set-PSFConfig -Module dbachecks -Name skip.connection.ping -Validation bool -Value $false -Initialize -Description "Skip the ping check for connectivity" Set-PSFConfig -Module dbachecks -Name skip.connection.auth -Validation bool -Value $false -Initialize -Description "Skip the authenticaton scheme check for connectivity" Set-PSFConfig -Module dbachecks -Name skip.connection -Validation bool -Value $false -Initialize -Description "Skip the connection checks" Set-PSFConfig -Module dbachecks -Name skip.datafilegrowthdisabled -Validation bool -Value $true -Initialize -Description "Skip validation of datafiles which have growth value equal to zero." Set-PSFConfig -Module dbachecks -Name skip.logfilecounttest -Validation bool -Value $false -Initialize -Description "Skip the logfilecount test" Set-PSFConfig -Module dbachecks -Name skip.diffbackuptest -Validation bool -Value $false -Initialize -Description "Skip the Differential backup test" Set-PSFConfig -Module dbachecks -Name skip.database.filegrowthdisabled -Validation bool -Value $true -Initialize -Description "Skip validation of datafiles which have growth value equal to zero." Set-PSFConfig -Module dbachecks -Name skip.database.logfilecounttest -Validation bool -Value $false -Initialize -Description "Skip the logfilecount test" Set-PSFConfig -Module dbachecks -Name skip.database.validdatabaseowner -Validation bool -Value $false -Initialize -Description "Skip the valid database owner test" Set-PSFConfig -Module dbachecks -Name skip.database.invaliddatabaseowner -Validation bool -Value $false -Initialize -Description "Skip the invalid database owner test" Set-PSFConfig -Module dbachecks -Name skip.database.databasecollation -Validation bool -Value $false -Initialize -Description "Skip the database collation test" Set-PSFConfig -Module dbachecks -Name skip.database.suspectpage -Validation bool -Value $false -Initialize -Description "Skip the suspect pages test" Set-PSFConfig -Module dbachecks -Name skip.database.autoclose -Validation bool -Value $false -Initialize -Description "Skip the autoclose test" Set-PSFConfig -Module dbachecks -Name skip.database.vlf -Validation bool -Value $false -Initialize -Description "Skip the virtual log file test" Set-PSFConfig -Module dbachecks -Name skip.database.autocreatestatistics -Validation bool -Value $false -Initialize -Description "Skip the auto create statistics test" Set-PSFConfig -Module dbachecks -Name skip.database.autoupdatestatistics -Validation bool -Value $false -Initialize -Description "Skip the auto update statistics test" Set-PSFConfig -Module dbachecks -Name skip.database.autoupdatestatisticsasynchronously -Validation bool -Value $false -Initialize -Description "Skip the auto update statistics asynchronously test" Set-PSFConfig -Module dbachecks -Name skip.database.trustworthy -Validation bool -Value $false -Initialize -Description "Skip the trustworthy database test" Set-PSFConfig -Module dbachecks -Name skip.database.status -Validation bool -Value $false -Initialize -Description "Skip the database status test" Set-PSFConfig -Module dbachecks -Name skip.database.compatibilitylevel -Validation bool -Value $false -Initialize -Description "Skip the database compatibility test" Set-PSFConfig -Module dbachecks -Name skip.database.recoverymodel -Validation bool -Value $false -Initialize -Description "Skip the database recovery model test" Set-PSFConfig -Module dbachecks -Name skip.database.pseudosimple -Validation bool -Value $false -Initialize -Description "Skip the database PseudoSimple recovery model test" Set-PSFConfig -Module dbachecks -Name skip.database.pageverify -Validation bool -Value $false -Initialize -Description "Skip the database page verify test" Set-PSFConfig -Module dbachecks -Name skip.database.fkcktrusted -Validation bool -Value $false -Initialize -Description "Skip the check for foreign keys and constraints being trusted" Set-PSFConfig -Module dbachecks -Name skip.logshiptesting -Validation bool -Value $false -Initialize -Description "Skip the logshipping test" Set-PSFConfig -Module dbachecks -Name skip.cluster.netclusterinterface -Validation bool -Value $false -Initialize -Description "Skip cluster private network interface checks" Set-PSFConfig -Module dbachecks -Name skip.hadr.listener.pingcheck -Validation bool -Value $false -Initialize -Description "Skip the HADR listener ping test (especially useful for Azure and AWS)" Set-PSFConfig -Module dbachecks -Name skip.hadr.listener.tcpport -Validation bool -Value $false -Initialize -Description "Skip the HADR AG Listener TCP port number (If port number is not standard across the entire AG architecture)" Set-PSFConfig -Module dbachecks -Name skip.hadr.replica.tcpport -Validation bool -Value $false -Initialize -Description "Skip the HADR Replica TCP port number (If port number is not standard across the entire AG architecture)" Set-PSFConfig -Module dbachecks -Name skip.hadr.listener.pingcheck -Validation bool -Value $false -Initialize -Description "Skip the HADR listener ping test (especially useful for Azure and AWS)" Set-PSFConfig -Module dbachecks -Name skip.agent.databasemailenabled -Validation bool -Value $false -Initialize -Description "Skip the Database Mail Enabled agent check" Set-PSFConfig -Module dbachecks -Name skip.agent.servicestartmode -Validation bool -Value $false -Initialize -Description "Skip the Agent Service State check" Set-PSFConfig -Module dbachecks -Name skip.agent.servicestate -Validation bool -Value $false -Initialize -Description "Skip the Agent Service Start Mode check" Set-PSFConfig -Module dbachecks -Name skip.agent.dbaoperatorname -Validation bool -Value $false -Initialize -Description "Skip the Agent Operator Name check" Set-PSFConfig -Module dbachecks -Name skip.agent.dbaoperatoremail -Validation bool -Value $false -Initialize -Description "Skip the Agent Operator Email check" Set-PSFConfig -Module dbachecks -Name skip.agent.failsafeoperator -Validation bool -Value $false -Initialize -Description "Skip the Agent Failsafe Operator check" Set-PSFConfig -Module dbachecks -Name skip.agent.databasemailprofile -Validation bool -Value $false -Initialize -Description "Skip the Database Mail Profile check" Set-PSFConfig -Module dbachecks -Name skip.agent.mailprofile -Validation bool -Value $false -Initialize -Description "Skip the SQL Server Agent Mail Profile check" Set-PSFConfig -Module dbachecks -Name skip.agent.longrunningjobs -Validation bool -Value $false -Initialize -Description "Skip the long running agent jobs check" Set-PSFConfig -Module dbachecks -Name skip.agent.lastjobruntime -Validation bool -Value $false -Initialize -Description "Skip the last agent job time check" Set-PSFConfig -Module dbachecks -Name skip.agent.jobowner -Validation bool -Value $false -Initialize -Description "Skip the Agent Job Owner check" Set-PSFConfig -Module dbachecks -Name skip.agent.invalidjobowner.name -Validation bool -Value $false -Initialize -Description "Skip the Agent Job Invalid Owner check" Set-PSFConfig -Module dbachecks -Name skip.agent.failedjobs -Validation bool -Value $false -Initialize -Description "Skip the Agent Failed Jobs check" Set-PSFConfig -Module dbachecks -Name skip.agent.JobHistory -Validation bool -Value $false -Initialize -Description "Skip the Agent Job History check" Set-PSFConfig -Module dbachecks -Name skip.security.containedbautoclose -Validation bool -Value $true -Initialize -Description "Skips the scan for contained databases should have auto close enabled" Set-PSFConfig -Module dbachecks -Name skip.security.sqlagentproxiesnopublicrole -Validation bool -Value $true -Initialize -Description "Skips the scan for if the public role has access to SQL Agent proxies" Set-PSFConfig -Module dbachecks -Name skip.security.symmetrickeyencryptionlevel -Validation bool -Value $true -Initialize -Description "Skips the test for if the Symmetric Encryption is at least AES_128 or higher in non-system databases" Set-PSFConfig -Module dbachecks -Name skip.security.asymmetrickeysize -Validation bool -Value $true -Initialize -Description "Skips the test for the size of the Assymetric Key sizes being above 2048 in non-system databases" Set-PSFConfig -Module dbachecks -Name skip.security.hideinstance -Validation bool -Value $true -Initialize -Description "Skips the scan for if hide instance is set to YES on the instance" Set-PSFConfig -Module dbachecks -Name skip.security.clrassembliessafe -Validation bool -Value $true -Initialize -Description "Skips the scan for CLR Assemblies set to SAFE_ACCESS" Set-PSFConfig -Module dbachecks -Name skip.security.engineserviceadmin -Validation bool -Value $true -Initialize -Description "Skips the scan for the SQL Server Engine account is a local administrator" Set-PSFConfig -Module dbachecks -Name skip.security.agentserviceadmin -Validation bool -Value $true -Initialize -Description "Skips the scan for the SQL Server Agent account is a local administrator" Set-PSFConfig -Module dbachecks -Name skip.security.fulltextserviceadmin -Validation bool -Value $true -Initialize -Description "Skips the scan for the SQL Server Full Text account is a local administrator" Set-PSFConfig -Module dbachecks -Name skip.security.querystoredisabled -Validation bool -Value $true -Initialize -Description "Skips the check for if Query Store is disabled" Set-PSFConfig -Module dbachecks -Name skip.security.querystoreenabled -Validation bool -Value $false -Initialize -Description "Skips the check for if Query Store is enabled" Set-PSFConfig -Module dbachecks -Name skip.security.loginauditlevelfailed -Validation bool -Value $true -Initialize -Description "Skips the scan for if server login level records failed logins" Set-PSFConfig -Module dbachecks -Name skip.security.loginauditlevelsuccessful -Validation bool -Value $true -Initialize -Description "Skips the scan for if server login level records successful and failed logins" Set-PSFConfig -Module dbachecks -Name skip.security.localwindowsgroup -Validation bool -Value $true -Initialize -Description "Skips the scan for if local windows groups have SQL Logins" Set-PSFConfig -Module dbachecks -Name skip.security.publicrolepermission -Validation bool -Value $true -Initialize -Description "Skips the scan for if the public server role has permissions" Set-PSFConfig -Module dbachecks -Name skip.security.builtinadmin -Validation bool -Value $true -Initialize -Description "Skips the scan for BUILTIN\Administrators login" Set-PSFConfig -Module dbachecks -Name skip.security.guestuserconnect -Validation bool -Value $true -Initialize -Description "Skips the scan for guest user have CONNECT permission" Set-PSFConfig -Module dbachecks -Name skip.security.ContainedDBSQLAuth -Validation bool -Value $true -Initialize -Description "Skips the scan for if a contained database as sql authenticated users" Set-PSFConfig -Module dbachecks -Name skip.agent.alert -Validation bool -Value $false -Initialize -Description "Skips the agent alerts checks" Set-PSFConfig -Module dbachecks -Name skip.security.LoginCheckPolicy -Validation bool -Value $true -Initialize -Description "Skips the scan for CHECK_POLICY on for all logins" Set-PSFConfig -Module dbachecks -Name skip.security.LoginPasswordExpiration -Validation bool -Value $true -Initialize -Description "Skips the scan for password expiration on for all logins in sysadmin role" Set-PSFConfig -Module dbachecks -Name skip.security.LoginMustChange -Validation bool -Value $true -Initialize -Description "Skips the scan for new logins must have password change turned on" Set-PSFConfig -Module dbachecks -Name skip.security.nonstandardport -Validation bool -Value $true -Initialize -Description "Skips the check for whether SQL Server should be configured with a non standard port" Set-PSFConfig -Module dbachecks -Name skip.security.SQLMailXPsDisabled -Validation bool -Value $true -Initialize -Description "Skip the check for Sql Mail XPs being disabled" Set-PSFConfig -Module dbachecks -Name skip.security.PublicPermission -Validation bool -Value $true -Initialize -Description "Skips the check for whether public role has permissions" Set-PSFConfig -Module dbachecks -Name skip.security.serverprotocol -Validation bool -Value $true -Initialize -Description "Skips the check for whether SQL Server is running on any other protocols but TCP/IP" #agent Set-PSFConfig -Module dbachecks -Name agent.dbaoperatorname -Value $null -Initialize -Description "Name of the DBA Operator in SQL Agent" Set-PSFConfig -Module dbachecks -Name agent.dbaoperatoremail -Value $null -Initialize -Description "Email address of the DBA Operator in SQL Agent" Set-PSFConfig -Module dbachecks -Name agent.failsafeoperator -Value $null -Initialize -Description "Email address of the Failsafe Operator in SQL Agent" # TODO: Should this be instance instead of agent? Set-PSFConfig -Module dbachecks -Name agent.databasemailprofile -Value $null -Initialize -Description "Name of the Database Mail Profile in SQL Agent" Set-PSFConfig -Module dbachecks -Name agent.mailprofile -Value $null -Initialize -Description "Name of the SQL Server Agent Mail Profile in SQL Agent" Set-PSFConfig -Module dbachecks -Name agent.validjobowner.name -Value "sa" -Initialize -Description "Agent job owner account should be this user" Set-PSFConfig -Module dbachecks -Name agent.invalidjobowner.name -Value $null -Initialize -Description "Agent job owner account should not be this user" Set-PSFConfig -Module dbachecks -Name agent.alert.messageid -Value @('823', '824', '825') -Initialize -Description "Agent alert messageid to validate; https://www.brentozar.com/blitz/configure-sql-server-alerts/" Set-PSFConfig -Module dbachecks -Name agent.alert.severity -Value @('16', '17', '18', '19', '20', '21', '22', '23', '24', '25') -Initialize -Description "Agent alert severity to validate; https://www.brentozar.com/blitz/configure-sql-server-alerts/" Set-PSFConfig -Module dbachecks -Name agent.alert.job -Value $false -Initialize -Description "Should we check for an agent job for the Agent Alert checks?" Set-PSFConfig -Module dbachecks -Name agent.alert.notification -Value $true -Initialize -Description "Should we check for a notification for the Agent Alert checks?" Set-PSFConfig -Module dbachecks -Name agent.history.maximumhistoryrows -Value 1000 -Initialize -Description "Maximum job history log size (in rows). The value -1 means disabled" Set-PSFConfig -Module dbachecks -Name agent.history.maximumjobhistoryrows -Value 100 -Initialize -Description "Maximum job history row per job. When the property is disabled the value is 0." Set-PSFConfig -Module dbachecks -Name agent.failedjob.excludecancelled -Value $false -Initialize -Description "Exclude agent jobs with a status of cancelled" Set-PSFConfig -Module dbachecks -Name agent.failedjob.since -Value 30 -Initialize -Description "The maximum number of days to check for failed jobs" Set-PSFConfig -Module dbachecks -Name agent.longrunningjob.percentage -Value 50 -Initialize -Description "The maximum percentage variance that a currently running job is allowed over the average for that job" Set-PSFConfig -Module dbachecks -Name agent.lastjobruntime.percentage -Value 50 -Initialize -Description "The maximum percentage variance that the last run of a job is allowed over the average for that job" # domain Set-PSFConfig -Module dbachecks -Name domain.name -Value $null -Initialize -Description "The Active Directory domain that your server is a part of" Set-PSFConfig -Module dbachecks -Name domain.organizationalunit -Value $null -Initialize -Description "The OU that your server should be a part of" Set-PSFConfig -Module dbachecks -Name domain.domaincontroller -Value $null -Initialize -Description "The domain controller to process your requests" # email Set-PSFConfig -Module dbachecks -Name mail.failurethreshhold -Value 0 -Initialize -Description "Number of errors that must be present to generate an email report" Set-PSFConfig -Module dbachecks -Name mail.smtpserver -Value $null -Initialize -Description "Store the name of the smtp server to send email reports" Set-PSFConfig -Module dbachecks -Name mail.to -Value $null -Validation validation.EmailValidation -Initialize -Description "Email address to send the report to" Set-PSFConfig -Module dbachecks -Name mail.from -Value $null -Validation validation.EmailValidation -Initialize -Description "Email address the email reports should come from" Set-PSFConfig -Module dbachecks -Name mail.subject -Value 'dbachecks results' -Validation String -Initialize -Description "Subject line of the email report" # Command parameter default values Set-PSFConfig -Module dbachecks -Name command.invokedbccheck.excludecheck -Value @() -Initialize -Description "Invoke-DbcCheck: The checks that should be skipped by default." Set-PSFConfig -Module dbachecks -Name command.invokedbccheck.excludedatabases -Value @() -Initialize -Description "Invoke-DbcCheck: The databases that should be skipped by default." # config for integration testing Set-PSFConfig -Module dbachecks -Name testing.integration.instance -Value @("localhost") -Initialize -Description "Default SQL Server instances to be used by integration tests" # Suspect pages Set-PSFConfig -Module dbachecks -Name policy.suspectpage.excludedb -Value 90 -Initialize -Description "Default threshold (%) to check whether suspect_pages is nearing row limit of 1000" Set-PSFConfig -Module dbachecks -Name policy.suspectpage.threshold -Value 90 -Initialize -Description "Default threshold (%) to check whether suspect_pages is nearing row limit of 1000" # Server Set-PSFConfig -Module dbachecks -Name policy.server.cpuprioritisation -Value $true -Initialize -Description "Shall we skip the CPU Prioritisation check" Set-PSFConfig -Module dbachecks -Name policy.server.excludeDiskAllocationUnit -Value @() -Initialize -Description "The disks to skip from the Disk Allocation Unit check - Must be 'DISKLETTER:\'" # Devops Set-PSFConfig -Module dbachecks -Name database.exists -Value @("master", "msdb", "tempdb", "model") -Initialize -Description "The databases we expect to be on the instances" # Not Contactable Set-PSFConfig -Module dbachecks -Name global.notcontactable -Value @() -Initialize -Description "This is used within the checks to avoid trying to contact none-responsive instances many times - do not set manually" Set-PSFConfig -Module dbachecks -Name policy.traceflags.expected -Value @() -Initialize -Description "The trace flags we expect to be running" Set-PSFConfig -Module dbachecks -Name policy.traceflags.notexpected -Value @() -Initialize -Description "The trace flags we expect not to be running" ================================================ FILE: source/internal/functions/Get-AllAgentInfo.ps1 ================================================ function Get-AllAgentInfo { # Using the unique tags gather the information required Param($Instance, $Tags) #ToDo: Clean unused SMO classes #clear out the default initialised fields $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Login], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Operator], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.AlertSystem], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.StoredProcedure], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Information], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Settings], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.LogFile], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.DataFile], $false) # set the default init fields for all the tags # Server Initial fields $ServerInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server]) $ServerInitFields.Add("VersionMajor") | Out-Null # so we can check versions $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server], $ServerInitFields) # Job Server Initial fields $OperatorInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Operator]) # Job Server Alert System Initial fields $FailsafeInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.AlertSystem]) # JobServer Initial fields $AgentMailProfileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer]) # Database Mail Profile Initial fields $DatabaseMailProfileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Mail.MailProfile]) # JobOwner Initial fields $JobOwnerInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job]) # Invalid JobOwner Initial fields $InvalidJobOwnerInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job]) # Failed Job Initial fields $FailedJobInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job]) # Agent Alerts Initial fields $AgentAlertsInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Alert]) # Agent Job History Initial fields $AgentJobHistory = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer]) # Set up blank ConfigValues object for any config we need to use in the checks $ConfigValues = [PSCustomObject]@{} # Using there so that if the instance is not contactable, no point carrying on with gathering more information switch ($tags) { 'DatabaseMailEnabled' { $configurations = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'DatabaseMailEnabled' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.security.databasemailenabled' }).Value) } 'AgentServiceAccount' { if (($Instance.VersionMajor -ge 14) -or $IsLinux -or $Instance.HostPlatform -eq 'Linux') { $Agent = @($Instance.Query("SELECT status_desc, startup_type_desc, servicename FROM sys.dm_server_services") | Where-Object servicename -Like '*Agent*').ForEach{ [PSCustomObject]@{ State = $PSItem.status_desc StartMode = $PSItem.startup_type_desc } } } else { # Windows $Agent = @(Get-DbaService -ComputerName $Instance.ComputerName -Type Agent) } } 'DbaOperator' { $OperatorInitFields.Add("Name") | Out-Null # so we can check operators $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Operator], $OperatorInitFields) $OperatorInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Operator]) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'DbaOperatorName' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.dbaoperatorname' }).Value) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'DbaOperatorEmail' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.dbaoperatoremail' }).Value) $Operator = $ConfigValues.DbaOperatorName.ForEach{ [PSCustomObject]@{ InstanceName = $Instance.Name ExpectedOperatorName = $PSItem ActualOperatorName = $Instance.JobServer.Operators.Name ExpectedOperatorEmail = 'null' ActualOperatorEmail = 'null' } } $Operator += $ConfigValues.DbaOperatorEmail.ForEach{ [PSCustomObject]@{ InstanceName = $Instance.Name ExpectedOperatorName = 'null' ActualOperatorName = 'null' ExpectedOperatorEmail = $PSItem ActualOperatorEmail = $Instance.JobServer.Operators.EmailAddress } } } 'FailsafeOperator' { $FailsafeInitFields.Add("FailSafeOperator") | Out-Null # so we can check failsafe operators $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.AlertSystem], $FailsafeInitFields) $FailsafeInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.AlertSystem]) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'FailsafeOperator' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.failsafeoperator' }).Value) $failsafeOperator = $ConfigValues.FailsafeOperator.ForEach{ [PSCustomObject]@{ InstanceName = $Instance.Name ExpectedFailSafeOperator = $PSItem ActualFailSafeOperator = $Instance.JobServer.AlertSystem.FailSafeOperator } } } 'DatabaseMailProfile' { $DatabaseMailProfileInitFields.Add("Name") | Out-Null # so we can check failsafe operators $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Mail.MailProfile], $DatabaseMailProfileInitFields) $DatabaseMailProfileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Mail.MailProfile]) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'DatabaseMailProfile' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.databasemailprofile' }).Value) $databaseMailProfile = $ConfigValues.DatabaseMailProfile.ForEach{ [PSCustomObject]@{ InstanceName = $Instance.Name ExpectedDatabaseMailProfile = $ConfigValues.DatabaseMailProfile ActualDatabaseMailProfile = $Instance.Mail.Profiles.Name } } } 'AgentMailProfile' { $AgentMailProfileInitFields.Add("DatabaseMailProfile") | Out-Null # so we can check failsafe operators $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer], $AgentMailProfileInitFields) $AgentMailProfileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer]) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AgentMailProfile' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.databasemailprofile' }).Value) $agentMailProfile = $ConfigValues.AgentMailProfile.ForEach{ [PSCustomObject]@{ InstanceName = $Instance.Name ExpectedAgentMailProfile = $ConfigValues.AgentMailProfile ActualAgentMailProfile = $Instance.JobServer.DatabaseMailProfile } } } 'FailedJob' { $FailedJobInitFields.Add("Name") | Out-Null # so we can check Job Name $FailedJobInitFields.Add("IsEnabled") | Out-Null # so we can check Job status $FailedJobInitFields.Add("LastRunDate") | Out-Null # so we can check Job LastRunDate $FailedJobInitFields.Add("LastRunOutcome") | Out-Null # so we can check Job LastRunOutcome $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job], $FailedJobInitFields) $FailedJobInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job]) $maxdays = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.failedjob.since' }).Value $startdate = (Get-Date).AddDays( - $maxdays) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'FailedJob' -Value 'Succeeded' $JobsFailed = ($Instance.JobServer.Jobs | Where-Object { $_.IsEnabled -and ($_.LastRunDate -gt $startdate) }).ForEach{ [PSCustomObject]@{ InstanceName = $Instance.Name JobName = $PSItem.Name ExpectedOutcome = $ConfigValues.FailedJob LastRunOutcome = $PSItem.LastRunOutcome } } } 'ValidJobOwner' { $JobOwnerInitFields.Add("OwnerLoginName") | Out-Null # so we can check Job Owner $JobOwnerInitFields.Add("Name") | Out-Null # so we can check Job Name $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job], $JobOwnerInitFields) $JobOwnerInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job]) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'TargetJobOwner' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.validjobowner.name' }).Value) $JobOwner = $Instance.JobServer.Jobs.ForEach{ [PSCustomObject]@{ InstanceName = $Instance.Name JobName = $PSItem.Name ExpectedJobOwnerName = $ConfigValues.TargetJobOwner #$PSItem ActualJobOwnerName = $PSItem.OwnerLoginName } } } 'InvalidJobOwner' { $InvalidJobOwnerInitFields.Add("OwnerLoginName") | Out-Null # so we can check Job Owner $InvalidJobOwnerInitFields.Add("Name") | Out-Null # so we can check Job Name $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job], $InvalidJobOwnerInitFields) $InvalidJobOwnerInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job]) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'InvalidJobOwner' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.invalidjobowner.name' }).Value) $InvalidJobOwner = $Instance.JobServer.Jobs.ForEach{ [PSCustomObject]@{ InstanceName = $Instance.Name JobName = $PSItem.Name ExpectedJobOwnerName = $ConfigValues.InvalidJobOwner ActualJobOwnerName = $PSItem.OwnerLoginName } } } 'AgentAlert' { $AgentAlertsInitFields.Add("Severity") | Out-Null # so we can check Alert Severity $AgentAlertsInitFields.Add("IsEnabled") | Out-Null # so we can check Alert status $AgentAlertsInitFields.Add("JobName") | Out-Null # so we can check Alert job $AgentAlertsInitFields.Add("HasNotification") | Out-Null # so we can check Alert notification $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Alert], $AgentAlertsInitFields) $AgentAlertsInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Alert]) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AgentAlertSeverity' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.alert.Severity' }).Value) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AgentAlertMessageId' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.alert.messageid' }).Value) $Severities = $ConfigValues.AgentAlertSeverity.ForEach{ $Severity = [int]($PSItem) $sev = $Instance.JobServer.Alerts.Where{ $_.Severity -eq $Severity } [PSCustomObject]@{ InstanceName = $Instance.Name AlertName = $sev.Name Severity = $sev.Severity IsEnabled = $sev.IsEnabled JobName = $sev.JobName HasNotification = $sev.HasNotification AgentAlertSeverity = $Severity } } $MessageIDs = $ConfigValues.AgentAlertMessageId.ForEach{ $MessageID = [int]($PSItem) $msgID = $Instance.JobServer.Alerts.Where{ $_.MessageID -eq $MessageID } [PSCustomObject]@{ InstanceName = $Instance.Name AlertName = $msgID.Name MessageID = $msgID.MessageID IsEnabled = $msgID.IsEnabled JobName = $msgID.JobName HasNotification = $msgID.HasNotification AgentMessageID = $MessageID } } $AgentAlerts = [PSCustomObject]@{ Severities = $Severities MessageIDs = $MessageIDs } } 'JobHistory' { $AgentJobHistory.Add("MaximumHistoryRows") | Out-Null # so we can check Alert Severity $AgentJobHistory.Add("MaximumJobHistoryRows") | Out-Null # so we can check Alert status $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer], $AgentJobHistory) $AgentJobHistory = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer]) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AgentMaximumHistoryRows' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.history.maximumhistoryrows' }).Value) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AgentMaximumJobHistoryRows' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.history.maximumjobhistoryrows' }).Value) $JobHistory = [PSCustomObject]@{ InstanceName = $Instance.Name CurrentMaximumHistoryRows = $Instance.JobServer.MaximumHistoryRows ExpectedMaximumHistoryRows = $ConfigValues.AgentMaximumHistoryRows CurrentMaximumJobHistoryRows = $Instance.JobServer.MaximumJobHistoryRows ExpectedMaximumJobHistoryRows = $ConfigValues.AgentMaximumJobHistoryRows } } 'LongRunningJob' { $query = "SELECT JobName, AvgSec, start_execution_date as StartDate, RunningSeconds, RunningSeconds - AvgSec AS Diff FROM ( SELECT j.name AS JobName, start_execution_date, AVG(DATEDIFF(SECOND, 0, STUFF(STUFF(RIGHT('000000' + CONVERT(VARCHAR(6),jh.run_duration),6),5,0,':'),3,0,':'))) AS AvgSec, ja.start_execution_date as startdate, DATEDIFF(second, ja.start_execution_date, GetDate()) AS RunningSeconds FROM msdb.dbo.sysjobactivity ja JOIN msdb.dbo.sysjobs j ON ja.job_id = j.job_id JOIN msdb.dbo.sysjobhistory jh ON jh.job_id = j.job_id WHERE start_execution_date is not null AND stop_execution_date is null AND run_duration < 235959 AND run_duration >= 0 AND ja.start_execution_date > DATEADD(day,-1,GETDATE()) GROUP BY j.name,j.job_id,start_execution_date,stop_execution_date,ja.job_id ) AS t ORDER BY JobName;" $runningjobs = Invoke-DbaQuery -SqlInstance $Instance -Database msdb -Query $query $ConfigValues | Add-Member -MemberType NoteProperty -Name 'LongRunningJob' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.longrunningjob.percentage' }).Value) $LongRunningJobs = $($runningjobs | Where-Object { $_.AvgSec -ne 0 }).ForEach{ [PSCustomObject]@{ InstanceName = $Instance.Name JobName = $PSItem.JobName RunningSeconds = $PSItem.RunningSeconds Average = $PSItem.AvgSec Diff = $PSItem.Diff ExpectedLongRunningJobPercentage = $ConfigValues.LongRunningJob ActualLongRunningJobPercentage = [math]::Round($PSItem.Diff / $PSItem.AvgSec * 100) } } } 'LastJobRunTime' { $maxdays = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.failedjob.since' }).Value $query = "IF OBJECT_ID('tempdb..#dbachecksLastRunTime') IS NOT NULL DROP Table #dbachecksLastRunTime SELECT * INTO #dbachecksLastRunTime FROM ( SELECT j.job_id, j.name AS JobName, DATEDIFF(SECOND, 0, STUFF(STUFF(RIGHT('000000' + CONVERT(VARCHAR(6),jh.run_duration),6),5,0,':'),3,0,':')) AS Duration FROM msdb.dbo.sysjobs j INNER JOIN ( SELECT job_id, instance_id = MAX(instance_id) FROM msdb.dbo.sysjobhistory GROUP BY job_id ) AS h ON j.job_id = h.job_id INNER JOIN msdb.dbo.sysjobhistory AS jh ON jh.job_id = h.job_id AND jh.instance_id = h.instance_id WHERE msdb.dbo.agent_datetime(jh.run_date, jh.run_time) > DATEADD(DAY,- {0},GETDATE()) AND jh.step_id = 0 ) AS lrt IF OBJECT_ID('tempdb..#dbachecksAverageRunTime') IS NOT NULL DROP Table #dbachecksAverageRunTime SELECT * INTO #dbachecksAverageRunTime FROM ( SELECT job_id, AVG(DATEDIFF(SECOND, 0, STUFF(STUFF(RIGHT('000000' + CONVERT(VARCHAR(6),run_duration),6),5,0,':'),3,0,':'))) AS AvgSec FROM msdb.dbo.sysjobhistory hist WHERE msdb.dbo.agent_datetime(run_date, run_time) > DATEADD(DAY,- {0},GETDATE()) AND Step_id = 0 AND run_duration >= 0 GROUP BY job_id ) as art SELECT JobName, Duration, AvgSec, Duration - AvgSec AS Diff FROM #dbachecksLastRunTime lastrun JOIN #dbachecksAverageRunTime avgrun ON lastrun.job_id = avgrun.job_id DROP Table #dbachecksLastRunTime DROP Table #dbachecksAverageRunTime" -f $maxdays $lastagentjobruns = Invoke-DbaQuery -SqlInstance $Instance -Database msdb -Query $query $ConfigValues | Add-Member -MemberType NoteProperty -Name 'LastJobRuns' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.lastjobruntime.percentage' }).Value) $LastJobRuns = $($lastagentjobruns | Where-Object { $_.AvgSec -ne 0 }).ForEach{ [PSCustomObject]@{ InstanceName = $Instance.Name JobName = $PSItem.JobName Duration = $PSItem.Duration Average = $PSItem.AvgSec ExpectedRunningJobPercentage = $ConfigValues.LastJobRuns ActualRunningJobPercentage = [math]::Round($PSItem.Diff / $PSItem.AvgSec * 100) } } } Default { } } #build the object $testInstanceObject = [PSCustomObject]@{ ComputerName = $Instance.ComputerName InstanceName = $Instance.DbaInstanceName Name = $Instance.Name ConfigValues = @($ConfigValues) HostPlatform = $Instance.HostPlatform IsClustered = $Instance.IsClustered DatabaseMailEnabled = $Instance.Configuration.DatabaseMailEnabled.ConfigValue Agent = @($Agent) Operator = @($Operator) FailSafeOperator = @($failsafeOperator) DatabaseMailProfile = @($databaseMailProfile) AgentMailProfile = @($agentMailProfile) JobOwner = $JobOwner InvalidJobOwner = $InvalidJobOwner JobsFailed = $JobsFailed LastJobRuns = $LastJobRuns LongRunningJobs = $LongRunningJobs AgentAlerts = $AgentAlerts JobHistory = @($JobHistory) } return $testInstanceObject } ================================================ FILE: source/internal/functions/Get-AllDatabaseInfo.ps1 ================================================ function Get-AllDatabaseInfo { # Using the unique tags gather the information required Param($Instance, $Tags) #clear out the default initialised fields $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Login], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.StoredProcedure], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Information], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Settings], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.LogFile], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.DataFile], $false) # set the default init fields for all the tags # Server Initial fields $ServerInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server]) $ServerInitFields.Add("VersionMajor") | Out-Null # so we can check versions $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server], $ServerInitFields) # Database Initial Fields $DatabaseInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database]) # Stored Procedure Initial Fields $StoredProcedureInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.StoredProcedure]) # Information Initial Fields # Settings Initial Fields $SettingsInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Settings]) # Login Initial Fields $LoginInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Login]) # Log File Initial Fields $LogFileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.LogFile]) # Data File Initial Fields $DataFileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.DataFile]) # Configuration cannot have default init fields :-) $configurations = $false # Set up blank ConfigValues object for any config we need to use in the checks $ConfigValues = [PSCustomObject]@{} # Using there so that if the instance is not contactable, no point carrying on with gathering more information switch ($tags) { 'AsymmetricKeySize' { $asymmetrickey = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'asymmetrickeysizeexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.asymmetrickeysize.excludedb').Value } 'AutoClose' { $autoclose = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'autoclose' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.autoclose').Value $ConfigValues | Add-Member -MemberType NoteProperty -Name 'autocloseexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.autoclose.excludedb').Value } 'AutoShrink' { $autoshrink = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'autoshrink' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.autoshrink').Value $ConfigValues | Add-Member -MemberType NoteProperty -Name 'autoshrinkexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.autoshrinke.excludedb').Value } 'ValidDatabaseOwner' { $owner = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'validdbownername' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.validdbowner.name').Value $ConfigValues | Add-Member -MemberType NoteProperty -Name 'validdbownerexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.validdbowner.excludedb').Value } 'InvalidDatabaseOwner' { $owner = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'invaliddbownername' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.invaliddbowner.name').Value $ConfigValues | Add-Member -MemberType NoteProperty -Name 'invaliddbownerexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.invaliddbowner.excludedb').Value } 'DatabaseCollation' { $collation = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'wrongcollation' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.wrongcollation').Value } 'SuspectPage' { $suspectPage = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'suspectpageexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.suspectpage.excludedb').Value } 'VirtualLogFile' { $vlf = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'maxvlf' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.maxvlf').Value $ConfigValues | Add-Member -MemberType NoteProperty -Name 'vlfexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.vlf.excludedb').Value } 'LogFileCount' { $logfilecount = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'logfilecount' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.logfilecount').Value $ConfigValues | Add-Member -MemberType NoteProperty -Name 'logfilecountexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.logfilecount.excludedb').Value } 'AutoCreateStatistics' { $autocreatestats = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'autocreatestats' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.autocreatestatistics').Value $ConfigValues | Add-Member -MemberType NoteProperty -Name 'autocreatestatsexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.autocreatestats.excludedb').Value } 'AutoUpdateStatistics' { $autoupdatestats = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'autoupdatestats' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.autoupdatestatistics').Value $ConfigValues | Add-Member -MemberType NoteProperty -Name 'autoupdatestatsexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.autoupdatestats.excludedb').Value } 'AutoUpdateStatisticsAsynchronously' { $autoupdatestatsasync = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'autoupdatestatsasync' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.autoupdatestatisticsasynchronously').Value $ConfigValues | Add-Member -MemberType NoteProperty -Name 'autoupdatestatsasyncexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.autoupdatestatisticsasynchronously.excludedb').Value } 'Trustworthy' { $trustworthy = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'trustworthyexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.trustworthyexcludedb').Value } 'DatabaseStatus' { $status = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'excludereadonly' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.status.excludereadonly').Value $ConfigValues | Add-Member -MemberType NoteProperty -Name 'excludeoffline' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.status.excludeoffline').Value $ConfigValues | Add-Member -MemberType NoteProperty -Name 'excluderestoring' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.status.excluderestoring').Value $ConfigValues | Add-Member -MemberType NoteProperty -Name 'statusexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.statusexcludedb').Value } 'QueryStoreEnabled' { $qs = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'qsenabledexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'database.querystoreenabled.excludedb').Value } 'QueryStoreDisabled' { $qs = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'qsdisabledexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'database.querystoredisabled.excludedb').Value } 'CompatibilityLevel' { $compatibilityLevel = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'compatexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'database.compatibilitylevel.excludedb').Value } 'GuestUserConnect' { $guestUserConnect = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'guestuserexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'database.guestuser.excludedb').Value } 'RecoveryModel' { $recoverymodel = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'recoverymodeltype' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.recoverymodel.type').Value $ConfigValues | Add-Member -MemberType NoteProperty -Name 'recoverymodelexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.recoverymodel.excludedb').Value } 'PseudoSimple' { $pseudoSimple = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'pseudosimpleexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.pseudosimpleexcludedb').Value } 'ContainedDBAutoClose' { $containedDbAutoClose = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'contdbautocloseexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.contdbautocloseexclude').Value } 'ContainedDBSQLAuth' { $containedDbSqlAuthUsers = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'contdbsqlauthexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.contdbsqlauthexclude').Value } 'PageVerify' { $pageverify = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'pageverifyexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.contdbsqlauthexclude').Value $ConfigValues | Add-Member -MemberType NoteProperty -Name 'pageverify' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.pageverify').Value } 'FKCKTrusted' { $trusted = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'fkcktrustedexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.fkcktrustedexclude').Value } Default { } } #build the object $testInstanceObject = [PSCustomObject]@{ ComputerName = $Instance.ComputerName InstanceName = $Instance.DbaInstanceName Name = $Instance.Name ConfigValues = $ConfigValues MajorVersion = $Instance.VersionMajor Databases = $Instance.Databases.Foreach{ [PSCustomObject]@{ Name = $psitem.Name SqlInstance = $Instance.Name Owner = @(if ($owner) { $psitem.owner }) ServerCollation = @(if ($collation) { $Instance.collation }) Collation = @(if ($collation) { $psitem.collation }) SuspectPage = @(if ($suspectPage) { (Get-DbaSuspectPage -SqlInstance $Instance -Database $psitem.Name | Measure-Object).Count }) ConfigValues = $ConfigValues AsymmetricKeySize = @(if ($asymmetrickey) { ($psitem.AsymmetricKeys | Where-Object { $_.KeyLength -lt 2048 } | Measure-Object).Count }) AutoClose = @(if ($autoclose -or $containedDbAutoClose) { $psitem.AutoClose }) AutoCreateStatistics = @(if ($autocreatestats) { $psitem.AutoCreateStatisticsEnabled }) AutoUpdateStatistics = @(if ($autoupdatestats) { $psitem.AutoUpdateStatisticsEnabled }) AutoUpdateStatisticsAsync = @(if ($autoupdatestatsasync) { $psitem.AutoUpdateStatisticsAsync }) AutoShrink = @(if ($autoshrink) { $psitem.AutoShrink }) VLF = @(if ($vlf) { ($psitem.Query("DBCC LOGINFO") | Measure-Object).Count }) LogFileCount = @(if ($logfilecount) { ($psitem.LogFiles | Measure-Object).Count }) Trustworthy = @(if ($trustworthy) { $psitem.Trustworthy }) Status = @(if ($status) { $psitem.Status }) IsDatabaseSnapshot = @(if ($status) { $psitem.IsDatabaseSnapshot }) # needed for status test Readonly = @(if ($status) { $psitem.Readonly }) # needed for status test QueryStore = @(if ($qs) { $psitem.QueryStoreOptions.ActualState }) CompatibilityLevel = @(if ($compatibilitylevel) { $psitem.CompatibilityLevel }) ServerLevel = @(if ($compatibilitylevel) { [Enum]::GetNames('Microsoft.SqlServer.Management.Smo.CompatibilityLevel').Where{ $psitem -match $Instance.VersionMajor } }) GuestUserConnect = @(if ($guestUserConnect) { if ($psitem.EnumDatabasePermissions('guest') | Where-Object { $_.PermissionState -eq 'Grant' -and $_.PermissionType.Connect }) { $true } } ) RecoveryModel = @(if ($pseudoSimple -or $recoverymodel) { $psitem.RecoveryModel }) PseudoSimple = @(if ($pseudoSimple) { '' -eq (($psitem.Query('Select last_log_backup_lsn from sys.database_recovery_status where database_id = DB_ID()')).last_log_backup_lsn) }) ContainmentType = @(if ($containedDbAutoClose -or $containedDbSqlAuthUsers) { $psitem.ContainmentType }) ContainedDbAutoClose = @(if ($containedDbAutoClose) { if (($psItem.ContainmentType -ne "NONE") -and ($null -ne $psItem.ContainmentType) -and $psitem.AutoClose) { $true } else { $false } } ) ContainedDbSqlAuthUsers = @(if ($containedDbSqlAuthUsers) { if ($psItem.ContainmentType -ne "NONE" -and ($null -ne $psItem.ContainmentType)) { ($psitem.Users | Where-Object { $_.LoginType -eq "SqlLogin" -and $_.HasDbAccess -eq $true } | Measure-Object ).Count } } ) PageVerify = @(if ($pageverify) { $psitem.PageVerify }) ForeignKeys = @(if ($trusted) {$psitem.Tables.ForeignKeys | Where-Object {-not $_.NotForReplication} | Select-Object Name, Parent, @{l='Database';e={$_.Parent.Parent.Name}}, IsChecked } ) Constraints = @(if ($trusted) {$psitem.Tables.Checks | Where-Object {(-not $_.NotForReplication) -and $_.IsEnabled} | Select-Object Name, Parent, @{l='Database';e={$_.Parent.Parent.Name}}, IsChecked } ) } } } return $testInstanceObject } ================================================ FILE: source/internal/functions/Get-CheckFile.ps1 ================================================ <# .SYNOPSIS This will return all of the files that match a Check name - either by name or by pester tag .DESCRIPTION This will return all of the files that match a Check name - either by name or by pester tag for either v4 or v5 Pester checks using the v5 switch .PARAMETER Repo The repo paths to check - normally defined by Get-CheckRepo .PARAMETER Check The Check .PARAMETER v5 Are we looking for Pester v5 files or not .EXAMPLE Get-CheckFile -Check AutoClose Gets the files for the AutoClose check .NOTES Internal - used in Invoke-DbcCheckv4 and Invoke-DbcCheckv5 #> function Get-CheckFile { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [String]$Repo, [Parameter(Mandatory = $true)] [String[]]$Check, [Parameter()] [switch]$v5 ) $script:selectedFiles = New-Object System.Collections.Generic.List[String] switch ($v5) { $false { if ($Check.Count -gt 0) { # specific checks were requested. find them. $TestsPath = Join-Path -Path $Repo -ChildPath '*.Tests.ps1' @(Get-ChildItem -Path $TestsPath ).ForEach{ # we do not want v5 files here if ($psitem.Name -notmatch 'v5') { $script:checksFile = $psitem.FullName if ($Check -contains ($PSItem.Name -replace '.Tests.ps1', '')) { # file matches by name if (!($script:selectedFiles -contains $script:checksFile)) { $script:selectedFiles.Add($script:checksFile) } } else { @($check).ForEach{ if (@([System.IO.File]::ReadAllLines($script:checksFile) | Select-String -Pattern "^\s*Describe.*-Tags\s+.*($psitem)").Matches.Count) { # file matches by one of the tags if (!($script:selectedFiles -contains $script:checksFile)) { $script:selectedFiles.Add($script:checksFile) } } } } } } } } $true { $message = 'We are going to use v5 files' Write-PSFMessage -Message $message -Level Verbose if ($Check.Count -gt 0) { # specific checks were requested. find them. $message = 'Specific checks were requested. find them' Write-PSFMessage -Message $message -Level Verbose $message = 'Searching Path {0} for test files' -f $repo Write-PSFMessage -Message $message -Level Verbose $TestsPath = Join-Path -Path $Repo -ChildPath '*.Tests.ps1' @(Get-ChildItem -Path $TestsPath ).ForEach{ $message = 'Processing {0}' -f $psitem.Name Write-PSFMessage -Message $message -Level Verbose # but we only want v5 files if ($psitem.Name -match 'v5') { $message = '{0} is a v5 file' -f $psitem.Name Write-PSFMessage -Message $message -Level Verbose $script:checksFile = $psitem.FullName if ($Check -contains ($PSItem.Name -replace 'v5.Tests.ps1', '')) { $message = '{0} file matches check {1}' -f $psitem.Name, ($Check | Out-String) Write-PSFMessage -Message $message -Level Verbose # file matches by name if (!($script:selectedFiles -contains $script:checksFile)) { $script:selectedFiles.Add($script:checksFile) } } else { $message = '{0} file does not match check {1} lets check for the tag' -f $psitem.Name, ($Check | Out-String) Write-PSFMessage -Message $message -Level Verbose $fileContent = [System.IO.File]::ReadAllLines($script:checksFile) @($check).ForEach{ $message = 'Check file {0} for the tag {1}' -f $script:checksFile, $psitem Write-PSFMessage -Message $message -Level Verbose if (@($fileContent | Select-String -Pattern "^\s*Describe.*-Tag\s+.*($psitem)").Matches.Count) { $message = 'The file {0} has the tag {1}' -f $script:checksFile, $psitem Write-PSFMessage -Message $message -Level Verbose # file matches by one of the tags if (!($script:selectedFiles -contains $script:checksFile)) { $script:selectedFiles.Add($script:checksFile) } } else { $message = 'The file {0} does not have the tag {1}' -f $script:checksFile, $psitem Write-PSFMessage -Message $message -Level Verbose } } } } } } } } return $script:selectedFiles } ================================================ FILE: source/internal/functions/Get-CheckInformation.ps1 ================================================ # Returns all of the tags that have been specified in the checks file for this run of the Invoke-DbcCheck function Get-CheckInformation { Param($Group, $Check, $AllChecks ,$ExcludeCheck) ## need to reset the variable here $script:localapp = Get-DbcConfigValue -Name app.localapp $GroupChecksConfig = Get-DbcCheck -Group $Group # Nothing if we exclude the group if ($ExcludeCheck -contains $Group) {Return} # Create an array of tags for the group except the Group Name #It's a bit clubnky but it works # This will create a list of all the tags for the group that has been specified ( so the instance checks or the database checks for example) $GroupChecks = @() @($GroupChecksConfig.AllTags).foreach{ @($psitem.Split(',')).ForEach{ $checkitem = $_.Trim() if ($checkitem -eq $Group) {} elseif ($ExcludeCheck -match $Checkitem) {} else { if (-not $GroupChecks.Contains($checkitem)) { $GroupChecks += $checkitem } } } } # Now we have a list of tags if we have a group. We need to have a list of tags for all the possible checks passed in #BUT # If we have called Invoke-DbcCheck without using the Check parameter (IE using the config) we have nothing in Check # So Lets fix that! if($null -eq $Check){ $Check = $GroupChecks } ## OK - Now we can return all of the tags for all fo the checks whether they are specified individually, by group, in the Check parameter or not specified and included by the config as either a group or an individual tag (Which is what I want!) $CheckInfo = @() if(($Check -eq $Group) -or ($Check -contains $Group) -or ($AllChecks)){ $CheckInfo = $GroupChecks } else{ @($Check).ForEach{ if($GroupChecks -contains $psitem){ ## BUT - This falls flat when you use a tag for a number of Checks that is not a group (like CIS) in that case all you get in $CheckInfo is CIS and not the relevant unique tags @(Get-DbcCheck -Tag $psitem).ForEach{ if (-not $CheckInfo.Contains($psitem.UniqueTag)) { $CheckInfo += $psitem.UniqueTag } } } } } Return $CheckInfo } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUb7Xe99cKDYQhSmLwA7GVuxpD # O2OgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBS0Jl/mFVoeWuv7lxKDeeVAXzM7 # /jANBgkqhkiG9w0BAQEFAASCAQB/UhD2mtAuccy4MtMMu4QYH9tMUsQ7y3ea0adX # FDp6Ql2zWswo29Tc1LUjXcLLuH9hHy4r+pDheKKnPqo33L9r1HWqDi23noVUn/r4 # EdapCkfNISgGfpiGzjuATDkpYjvsePGJBgyhDQvSfP2ORFUzVj/qe12jGgFQe81m # C4aU7ylTEaK7fJT0WUpTc4xbP/OW6q1K/0ldYHAimzSI2BqQ345v2NY6MhhPMbaj # ETC0AA880BkH5FMRmNRwYzB8KBSrY2jgVKk6b+2u70y1auTXJf/AiAygRHoP5sQt # 6h7G6EtF6XEhYT2i3LhSSsZ3oAICq4ayluV4eM7Fv2iKmWMw # SIG # End signature block ================================================ FILE: source/internal/functions/Get-CheckRepo.ps1 ================================================ # Can't set arrays right now, w/e function Get-CheckRepo { $repos = Get-DbcConfigValue app.checkrepos if ($repos -match ", ") { $repos = $repos.Replace(", ", ",") $repos = $repos.Split(",") } return $repos } ================================================ FILE: source/internal/functions/Get-ComputerName.ps1 ================================================ function Get-ComputerName { if ($null -ne $computername) { return [array]$computername } else { $computers = Get-DbcConfigValue app.computername if ($computers.Length -eq 0) { Write-PSFMessage -Level Warning -Message "You must specify -ComputerName or use Set-DbcConfig app.computername to setup a list of servers" } else { [array]$computers } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUdfbAm1rLK0g7UGS6g2B4tpnb # ZmagggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQBpuyrkz1GEocfEFleol//Lre9 # nTANBgkqhkiG9w0BAQEFAASCAQAH6gE99C9zUcjbtRJIg6Sfzp+gXzF4jrttF0Kf # zWZoT4wkZPqHa51teeUfWZrsR02cEAuyhuFGyYeWNpxJ7N4VI2tGsEAOycCfy/Xv # hUkaZQbLV4LhuixgEOGF3p7lydfxFnJA7GNxhgfkNNTsX4zQ0q+7eb8vcqRnlFIg # TlbdHSyVjlOSTuqVJf+cyr5C4vafz9t49dUFBP44z45nz5pqfxOCRf9YjS9JiJN0 # vgloSbqih+EAqb6NAOpCQB37EsNdVJrhxwA/Vn0knzxxrOyX2ga2TM44Nix9MJwW # 3V7FsF7U9gvTVBfXqSQv+TIcO1PnXt0QozQsPlZbfQAtIwvo # SIG # End signature block ================================================ FILE: source/internal/functions/Get-DatabaseDetail.ps1 ================================================ function Get-DatabaseDetail { param ( [DbaInstanceParameter[]]$SqlInstance, [object[]]$ExcludeDatabase ) begin { if (!(test-path variable:script:results)) { $script:results = @{} } } process { foreach ($instance in $SqlInstance) { try { if (!($script:results.ContainsKey($instance))) { $server = Connect-DbaInstance -SqlInstance $instance -SqlCredential $sqlcredential $dbs = $server.Query(" select quotename(d.name) [Database] ,d.collation_name DatabaseCollation ,suser_sname(d.owner_sid) CurrentOwner ,d.recovery_model_desc RecoveryModel ,d.is_auto_shrink_on AutoShrink ,d.is_auto_close_on AutoClose ,d.is_auto_create_stats_on AutoCreateStatisticsEnabled ,d.is_auto_update_stats_on AutoUpdateStatisticsEnabled ,d.is_auto_update_stats_async_on AutoUpdateStatisticsAsync ,d.is_trustworthy_on Trustworthy ,d.page_verify_option_desc PageVerify ,isnull((select count(*) from msdb..suspect_pages sp where sp.database_id = d.database_id and event_type in (1,2,3)),0) SuspectPages ,d.state_desc Status ,d.compatibility_level CompatibilityLevel ,d.user_access_desc UserAccess ,d.is_read_only IsReadOnly from sys.databases d ") foreach($db in $dbs) { $db | Add-Member -Force -MemberType NoteProperty -Name ServerCollation -Value $server.Collation $db | Add-Member -Force -MemberType NoteProperty -Name SqlInstance -Value $server.DomainInstanceName $db | Add-Member -Force -MemberType NoteProperty -Name SqlVersion -Value $server.VersionMajor } $script:results.Add($instance, $dbs) } $server.DomainInstanceName $server.VersionMajor return $script:results[$instance] | Where-Object { $psitem.Database -notin $ExcludeDatabase -or !$ExcludeDatabase } } catch { #Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue throw } } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUHYJW1aa82Kb8/1c6ja8kIoWs # CzygggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBSip9SPeC6nD6iY7Nf+9bPrzhJA # fjANBgkqhkiG9w0BAQEFAASCAQBHy9vZF0+Vx/0afb0MqqAndcOztUqnspf9EJ/8 # Ewh+fQWbFm/VInVu4nvtU5rXK00rIbp1nesQJi4BUq/uSmyW5SOUMvW18OLu4U9C # x0PhTmsf/uZPD9K6DGNPXKOuJgTDov2jOM4gH25JbQJfSZZjAmNCIhWPU3e//n3d # T1pTcajBAOn0Nfggfz9z2EMaJlDpvN1DGdzYKuGlPbPfuA26M6d3fvYaXtwtDnMs # vLObZluM0ovvvcunNzjIwWB0hgKTM/XuUbEfEgkwp1kNsE3PRKAgY0/Iz0lIU6TI # SyijkgMOclb9CxY65lyu1/1AM/ogAPaB/YFasCi4P7TPp8JZ # SIG # End signature block ================================================ FILE: source/internal/functions/Get-SqlInstance.ps1 ================================================ function Get-Instance { if ($null -ne $sqlinstance) { return [array]$sqlinstance } $instances = Get-DbcConfigValue app.sqlinstance if ($instances.Length -eq 0) { Write-PSFMessage -Level Warning -Message "You must specify -SqlInstance or use Set-DbcConfig app.sqlinstance to setup a list of servers" return } else { [array]$instances } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUKG+fi8Y+2vCSeOs1aYV/2+vA # /GSgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQWo5+F0QJWSu2APCWXfQhpAxKM # rjANBgkqhkiG9w0BAQEFAASCAQAgEYgaTNo9JN40KuthlhfYpd6kE/CHB/ukv1OR # O6cLnyxTLWSr6myjtLTmo0MfRc1pnhs8nSIvkklAier8xLqw2ENINOGx9umhKJTU # YA4gTjhVn8PD+Cx3aLkxJKP/Ka8Vfzff9E36cXae3g1q/TQvGgX+JPDkrMWNFPbn # ThfWZ0WgwUfPcsYu4SV5w7TY/fcGY2V0v476D0xnroQAwnW/fq9d37BTqbBrGTdC # t2nYV26HtHcyLhPUb+lFvd5Pza/50DujXygDKU4vPXmUHpY48umHIyGa74rGuLD8 # T7prtnuFOVXvW8aMGRbvclIo3HdenIS9IibhOI2fA8Q03GGQ # SIG # End signature block ================================================ FILE: source/internal/functions/Get-Version.ps1 ================================================ function Get-Version { Param($SqlInstance) (Connect-DbaInstance -SqlInstance $SqlInstance).Version.Major } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUm9sIEtob9SkkRtUi83s7yTMm # L3SgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBS6fKrcKP+7fxnJLgaZqVDLRcQt # vDANBgkqhkiG9w0BAQEFAASCAQAZrvT+IkervQNoDplFf/cBFjoitqN9jo8jw0n1 # 10YsmGFi330nd4/MDiLO6oeoQhVdyGsdG1M1YwAAz2ockHBBZ+nsXHzYvCciW+jH # U+YXmMe+Y5QgjBm/N7CalRs7SJZ4YwXi+CeKn2kehPrAqvcgsGUtEJYRmJqaHyD9 # tMZUjIpbwjfNOAMSs3orM5deTn3HOMHF9GtOQcciEB7dEbM650HIoAHwkZBhoJuK # MjVwnE3+HTxJ8UkfNKzYBuaTo4AguNhGVsSf/C7DtX1fcuL8W8tE7aqM7kuxCNzc # WaYyGbdtUMZiCo/3QGsL6B8f5SbPKfJJBWnYijXXCU4vmdgb # SIG # End signature block ================================================ FILE: source/internal/functions/Get-v5Checks.ps1 ================================================ function Get-v5Checks { $v5files = Get-ChildItem -Path $v5Path -Recurse -Filter *.ps1 -Exclude *-v5.ps1 [Management.Automation.Language.Parser]::ParseInput($GroupContent, [ref]$tokens, [ref]$errors). FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast.CommandElements -and $ast.CommandElements[0].Value -eq 'describe' }, $true) | ForEach-Object { $CE = $PSItem.CommandElements $secondString = ($CE | Where-Object { $PSItem.StaticType.name -eq 'string' })[1] $tagIdx = $CE.IndexOf(($CE | Where-Object ParameterName -EQ 'Tags')) + 1 $tags = if ($tagIdx -and $tagIdx -lt $CE.Count) { $CE[$tagIdx].Extent } New-Object PSCustomObject -Property @{ GroupName = $GroupName CheckTitle = $secondString CheckTags = $tags } } } ================================================ FILE: source/internal/functions/Invoke-ConfigurationScript.ps1 ================================================ function Invoke-ConfigurationScript { <# .SYNOPSIS Invokes the configurations/configuration.ps1 script .DESCRIPTION This function is necessary to be able to do integration tests of Reset-DbcConfig without affecting the real configuration values It is important to be able to validate, that Reset-DbcConfig does not reset too much without affecting live configuration values. #> [CmdletBinding()] param() . $script:ModuleRoot\internal\configurations\configuration.ps1 } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUNH31mcI/oInNRfghcUFAcl0K # WPmgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQbFj6/yXdVxiTmHw5YkzwjOsCB # XTANBgkqhkiG9w0BAQEFAASCAQBrlavxDvPOguKF9IIsa/WEVJkpA7g67SRDN2x8 # wBEN8B4JDJxzdPLJZB8NItog+7IuMa5Yc4dzyRFGGL3I3k5MqTSr1AN3yd/POJRy # 5X0tL/QWf28rdGJHqa8JuzUgjeTjP8pWOB+PHbm0m/P52YiZAXSAQ2ZBewAwHXNn # BdaI37q19RG4MtniG0th/kYe+R2yjypS8o1hK92qnrFU/T7mH8UMu60KhuK17vUP # +inuDEBdDm3US8pqWFRvmkrXMcd6fs7usfBUcvG5pXw8F+svVNLOErAWGtBixvga # 3yN0hYqrpmJ5u5OObWFUHbs5n70lU+2aGwVXs5nQ2XQYvBdI # SIG # End signature block ================================================ FILE: source/internal/functions/Invoke-DbcCheckv4.ps1 ================================================ function Invoke-DbcCheckv4 { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '', Justification='Because scoping is hard')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification='Because its set to the global var')] [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Alias('Path', 'relative_path')] [object[]]$Script, [Alias("Name")] [string[]]$TestName, [switch]$EnableExit, [Parameter(Position = 0)] [Alias("Tags", "Tag", "Checks")] [string[]]$Check, [AllowEmptyCollection()] [Alias("ExcludeTags", "ExcludeTag", "ExcludeChecks")] [string[]]$ExcludeCheck = (Get-PSFConfigValue -FullName 'dbachecks.command.invokedbccheck.excludecheck' -Fallback @()), [switch]$PassThru, [DbaInstance[]]$SqlInstance, [DbaInstance[]]$ComputerName, [PSCredential]$SqlCredential, [PSCredential]$Credential, [object[]]$Database, [object[]]$ExcludeDatabase = (Get-PSFConfigValue -FullName 'dbachecks.command.invokedbccheck.excludedatabase' -Fallback @()), [string[]]$Value, [string]$ConfigFile, [object[]]$CodeCoverage = @(), [string]$CodeCoverageOutputFile, [ValidateSet('JaCoCo')] [string]$CodeCoverageOutputFileFormat = "JaCoCo", [switch]$Strict, [Parameter(Mandatory = $true, ParameterSetName = 'NewOutputSet')] [string]$OutputFile, [ValidateSet('NUnitXml')] [string]$OutputFormat, [switch]$AllChecks, [switch]$Quiet, [object]$PesterOption, [string]$Show = 'All' ) dynamicparam { $config = Get-PSFConfig -Module dbachecks $RuntimeParamDic = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary foreach ($setting in $config) { $name = $setting.Name $name = "Config" + (($name.Split(".") | ForEach-Object { $_.SubString(0, 1).ToUpper() + $_.SubString(1) }) -join '') $ParamAttrib = New-Object System.Management.Automation.ParameterAttribute $ParamAttrib.ParameterSetName = '__AllParameterSets' $AttribColl = New-Object System.Collections.ObjectModel.Collection[System.Attribute] $AttribColl.Add($ParamAttrib) $RuntimeParam = New-Object System.Management.Automation.RuntimeDefinedParameter($name, [object], $AttribColl) $RuntimeParamDic.Add($name, $RuntimeParam) } return $RuntimeParamDic } begin { } process { if (Test-PSFFunctionInterrupt) { return } #get the output config for dbatools and store it to set it back at the end $dbatoolsoutputconfig = Get-DbatoolsConfigValue -FullName message.consoleoutput.disable if (!$dbatoolsoutputconfig) { Set-DbatoolsConfig -FullName message.consoleoutput.disable -Value $true } if (-not $Script -and -not $TestName -and -not $Check -and -not $ExcludeCheck -and -not $AllChecks) { Stop-PSFFunction -Message "Please specify Check, ExcludeCheck, Script, TestName or AllChecks" return } if (-not $SqlInstance.InputObject -and -not $ComputerName.InputObject -and -not (Get-PSFConfigValue -FullName dbachecks.app.sqlinstance) -and -not (Get-PSFConfigValue -FullName dbachecks.app.computername) -and -not (Get-PSFConfigValue -FullName dbachecks.app.cluster)) { Stop-PSFFunction -Message "No servers set to run against. Use Get/Set-DbcConfig to setup your servers or Get-Help Invoke-DbcCheck for additional options." return } $customparam = 'SqlInstance', 'ComputerName', 'SqlCredential', 'Credential', 'Database', 'ExcludeDatabase', 'Value' foreach ($param in $customparam) { if (Test-PSFParameterBinding -ParameterName $param) { $value = Get-Variable -Name $param if ($value.InputObject) { Set-Variable -Scope 0 -Name $param -Value $value.InputObject -ErrorAction SilentlyContinue $PSDefaultParameterValues.Add( { "*-Dba*:$param", $value.InputObject }) } } else { $PSDefaultParameterValues.Remove( { "*-Dba*:$param" }) } $null = $PSBoundParameters.Remove($param) } # Lil bit of cleanup here, for a switcharoo $null = $PSBoundParameters.Remove('AllChecks') $null = $PSBoundParameters.Remove('Check') $null = $PSBoundParameters.Remove('ExcludeCheck') $null = $PSBoundParameters.Remove('ConfigFile') $null = $PSBoundParameters.Add('Tag', $Check) $null = $PSBoundParameters.Add('ExcludeTag', $ExcludeCheck) $globalexcludedchecks = Get-PSFConfigValue -FullName dbachecks.command.invokedbccheck.excludecheck $global:ChecksToExclude = $ExcludeCheck + $globalexcludedchecks [string[]]$Script:ExcludedDatabases = Get-PSFConfigValue -FullName dbachecks.command.invokedbccheck.excludedatabases $Script:ExcludedDatabases += $ExcludeDatabase foreach ($singlecheck in $check) { if ($singlecheck -in $globalexcludedchecks) { Write-PSFMessage -Level Warning -Message "$singlecheck is excluded in command.invokedbccheck.excludecheck and will be skipped " } } if ($AllChecks -and $globalexcludedchecks) { Write-PSFMessage -Level Warning -Message "$globalexcludedchecks will be skipped" } if ($ExcludedDatabases) { Write-PSFMessage -Level Warning -Message "$ExcludedDatabases databases will be skipped for all checks" } # Then we'll need a generic param passer that doesn't require global params # cuz global params are hard $finishedAllTheChecks = $false try { $repos = Get-CheckRepo foreach ($repo in $repos) { if ((Test-Path $repo -ErrorAction SilentlyContinue)) { if ($OutputFormat -eq "NUnitXml" -and -not $OutputFile) { $number = $repos.IndexOf($repo) $timestamp = Get-Date -format "yyyyMMddHHmmss" $PSBoundParameters['OutputFile'] = "$script:maildirectory\report-$number-$pid-$timestamp.xml" } if ($Check.Count -gt 0) { # specific checks were listed. find the necessary script files. $PSBoundParameters['Script'] = (Get-CheckFile -Repo $repo -Check $check) } Push-Location -Path $repo ## remove any previous entries ready for this run Set-PSFConfig -Module dbachecks -Name global.notcontactable -Value @() Write-PSFMessage -Message ($PSBoundParameters | Out-String) -Level Significant Invoke-Pester @PSBoundParameters Pop-Location } } $finishedAllTheChecks = $true } catch { Stop-PSFFunction -Message "There was a problem executing Invoke-Pester" -ErrorRecord $psitem } finally { # reset the config to original value Set-DbatoolsConfig -FullName message.consoleoutput.disable -Value $dbatoolsoutputconfig if (!($finishedAllTheChecks)) { Write-PSFMessage -Level Warning -Message "Execution was cancelled!" Pop-Location } } } } <# .SYNOPSIS Invoke-DbcCheck is a SQL-centric Invoke-Pester wrapper .DESCRIPTION The Invoke-DbcCheck function runs Pester tests, including *.Tests.ps1 files and Pester tests in PowerShell scripts. Extended description about Pester: Get-Help -Name Invoke-Pester .PARAMETER Check Runs only tests in Describe blocks with the specified Tag parameter values. Wildcard characters and Tag values that include spaces or whitespace characters are not supported. When you specify multiple Tag values, Invoke-DbcCheck runs tests that have any of the listed tags (it ORs the tags). However, when you specify TestName and Tag values, Invoke-DbcCheck runs only describe blocks that have one of the specified TestName values and one of the specified Tag values. If you use both Tag and ExcludeTag, ExcludeTag takes precedence. .PARAMETER ExcludeCheck Omits tests in Describe blocks with the specified Tag parameter values. Wildcard characters and Tag values that include spaces or whitespace characters are not supported. When you specify multiple ExcludeTag values, Invoke-DbcCheck omits tests that have any of the listed tags (it ORs the tags). However, when you specify TestName and ExcludeTag values, Invoke-DbcCheck omits only describe blocks that have one of the specified TestName values and one of the specified Tag values. If you use both Tag and ExcludeTag, ExcludeTag takes precedence .PARAMETER SqlInstance A list of SQL Servers to run the tests against. If this is not provided, it will be gathered from: Get-DbatoolsConfig -Name app.sqlinstance .PARAMETER ComputerName A list of computers to run the tests against. If this is not provided, it will be gathered from: Get-DbatoolsConfig -Name app.computername .PARAMETER SqlCredential Alternate SQL Server-based credential. .PARAMETER Credential Alternate Windows credential. .PARAMETER Database A list of databases to include if your check is database centric. .PARAMETER ExcludeDatabase A list of databases to exclude if your check is database centric. .PARAMETER PassThru Returns a custom object (PSCustomObject) that contains the test results. By default, Invoke-DbcCheck writes to the host program, not to the output stream (stdout). If you try to save the result in a variable, the variable is empty unless you use the PassThru parameter. To suppress the host output, use the Quiet parameter. .PARAMETER ConfigFile The path to the exported dbachecks config file. .PARAMETER OutputFormat The format of output. Currently, only NUnitXML is supported. .PARAMETER Strict Makes Pending and Skipped tests to Failed tests. Useful for continuous integration where you need to make sure all tests passed. .PARAMETER AllChecks In the unlikely event that you'd like to run all checks, specify -AllChecks. These checks still confirm to the skip settings in Get-DbcConfig. .PARAMETER Quiet The parameter Quiet is deprecated since Pester v. 4.0 and will be deleted in the next major version of Pester. Please use the parameter Show with value 'None' instead. .PARAMETER Show Customizes the output Pester writes to the screen. Available options are None Default Passed Failed Pending Skipped Inconclusive Describe Context Summary Header All Fails The options can be combined to define presets. Common use cases are: None - to write no output to the screen. All - to write all available information (this is default option). Fails - to write everything except Passed (but including Describes etc.). A common setting is also Failed, Summary, to write only failed tests and test summary. This parameter does not affect the PassThru custom object or the XML output that is written when you use the Output parameters. .PARAMETER Value A value.. it's hard to explain .PARAMETER Script Get-Help -Name Invoke-Pester -Parameter Script .PARAMETER TestName Get-Help -Name Invoke-Pester -Parameter TestName .PARAMETER EnableExit Get-Help -Name Invoke-Pester -Parameter EnableExit .PARAMETER OutputFile Get-Help -Name Invoke-Pester -Parameter OutputFile .PARAMETER CodeCoverage Get-Help -Name Invoke-Pester -Parameter CodeCoverage .PARAMETER PesterOption Get-Help -Name Invoke-Pester -Parameter PesterOption .PARAMETER CodeCoverageOutputFile Get-Help -Name Invoke-Pester -Parameter CodeCoverageOutputFile .PARAMETER CodeCoverageOutputFileFormat Get-Help -Name Invoke-Pester -Parameter CodeCoverageOutputFileFormat .LINK https://dbachecks.readthedocs.io/en/latest/functions/Invoke-DbcCheck/ .EXAMPLE Invoke-DbcCheck -Tag Backup -SqlInstance sql2016 Runs all of the checks tagged Backup against the sql2016 instance .EXAMPLE Invoke-DbcCheck -Tag RecoveryModel -SqlInstance sql2017, sqlcluster -SqlCredential (Get-Credential sqladmin) Runs the Recovery model check against the SQL instances sql2017, sqlcluster using the sqladmin SQL login with the password provided interactively .EXAMPLE Invoke-DbcCheck -Check Database -ExcludeCheck AutoShrink -ConfigFile \\share\repo\prod.json Runs all of the checks tagged Database except for the AutoShrink check against the SQL Instances set in the config under app.sqlinstance Imports configuration file, \\share\repo\prod.json, prior to executing checks. .EXAMPLE # Set the servers you'll be working with Set-DbcConfig -Name app.sqlinstance -Value sql2016, sql2017, sql2008, sql2008\express Set-DbcConfig -Name app.computername -Value sql2016, sql2017, sql2008 # Look at the current configs Get-DbcConfig # Invoke a few tests Invoke-DbcCheck -Tags SuspectPage, LastBackup Runs the Suspect Pages and Last Backup checks against the SQL Instances sql2016, sql2017, sql2008, sql2008\express after setting them in the configuration .EXAMPLE Invoke-DbcCheck -SqlInstance sql2017 -Tags SuspectPage, LastBackup -Show Summary -PassThru | Update-DbcPowerBiDataSource Start-DbcPowerBi Runs the Suspect Page and Last Backup checks against the SQL Instances set in the config under app.sqlinstance only showing the summary of the results of the checks. It then updates the source json for the XML which is stored at C:\Windows\temp\dbachecks\ and then opens the PowerBi report in PowerBi Desktop .EXAMPLE Get-Help -Name Invoke-Pester -Examples Want to get super deep? You can look at Invoke-Pester's example's and run them against Invoke-DbcCheck since it's a wrapper. https://github.com/pester/Pester/wiki/Invoke-Pester Describe about_Pester #> ================================================ FILE: source/internal/functions/Invoke-DbcCheckv5.ps1 ================================================ function Invoke-DbcCheckv5 { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '', Justification = 'Because scoping is hard')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Because its set to the global var')] [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Alias('Path', 'relative_path')] [object[]]$Script, [Alias("Name")] [string[]]$TestName, [switch]$EnableExit, [Parameter(Position = 0)] [Alias("Tags", "Tag", "Checks")] [string[]]$Check, [AllowEmptyCollection()] [Alias("ExcludeTags", "ExcludeTag", "ExcludeChecks")] [string[]]$ExcludeCheck = (Get-PSFConfigValue -FullName 'dbachecks.command.invokedbccheck.excludecheck' -Fallback @()), [switch]$PassThru, [DbaInstance[]]$SqlInstance, [DbaInstance[]]$ComputerName, [PSCredential]$SqlCredential, [PSCredential]$Credential, [object[]]$Database, [object[]]$ExcludeDatabase = (Get-PSFConfigValue -FullName 'dbachecks.command.invokedbccheck.excludedatabase' -Fallback @()), [string[]]$Value, [string]$ConfigFile, [object[]]$CodeCoverage = @(), [string]$CodeCoverageOutputFile, [ValidateSet('JaCoCo')] [string]$CodeCoverageOutputFileFormat = "JaCoCo", [switch]$Strict, [Parameter(Mandatory = $true, ParameterSetName = 'NewOutputSet')] [string]$OutputFile, [ValidateSet('NUnitXml')] [string]$OutputFormat, [switch]$AllChecks, [object]$Configuration ) dynamicparam { $config = Get-PSFConfig -Module dbachecks $RuntimeParamDic = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary foreach ($setting in $config) { $name = $setting.Name $name = "Config" + (($name.Split(".") | ForEach-Object { $_.SubString(0, 1).ToUpper() + $_.SubString(1) }) -join '') $ParamAttrib = New-Object System.Management.Automation.ParameterAttribute $ParamAttrib.ParameterSetName = '__AllParameterSets' $AttribColl = New-Object System.Collections.ObjectModel.Collection[System.Attribute] $AttribColl.Add($ParamAttrib) $RuntimeParam = New-Object System.Management.Automation.RuntimeDefinedParameter($name, [object], $AttribColl) $RuntimeParamDic.Add($name, $RuntimeParam) } return $RuntimeParamDic } begin { } process { if (Test-PSFFunctionInterrupt) { return } #get the output config for dbatools and store it to set it back at the end $dbatoolsoutputconfig = Get-DbatoolsConfigValue -FullName message.consoleoutput.disable if (!$dbatoolsoutputconfig) { Set-DbatoolsConfig -FullName message.consoleoutput.disable -Value $true } # validation (could this be done only in Invoke-DbcCheck ?) if (-not $Script -and -not $TestName -and -not $Check -and -not $ExcludeCheck -and -not $AllChecks) { Stop-PSFFunction -Message "Please specify Check, ExcludeCheck, Script, TestName or AllChecks" return } # validition (could this be done only in Invoke-DbcCheck ?) if (-not $SqlInstance.InputObject -and -not $ComputerName.InputObject -and -not (Get-PSFConfigValue -FullName dbachecks.app.sqlinstance) -and -not (Get-PSFConfigValue -FullName dbachecks.app.computername) -and -not (Get-PSFConfigValue -FullName dbachecks.app.cluster)) { Stop-PSFFunction -Message "No servers set to run against. Use Get/Set-DbcConfig to setup your servers or Get-Help Invoke-DbcCheck for additional options." return } # set these parameters as default parameters to make less writing (and more troubleshooting ;-) ) $customparam = 'SqlInstance', 'ComputerName', 'SqlCredential', 'Credential', 'Database', 'ExcludeDatabase', 'Value' foreach ($param in $customparam) { if (Test-PSFParameterBinding -ParameterName $param) { $value = Get-Variable -Name $param if ($value.InputObject) { Set-Variable -Scope 0 -Name $param -Value $value.InputObject -ErrorAction SilentlyContinue $PSDefaultParameterValues.Add( { "*-Dba*:$param", $value.InputObject }) } } else { $PSDefaultParameterValues.Remove( { "*-Dba*:$param" }) } $null = $PSBoundParameters.Remove($param) } # Another bit of validation here that could be in Invoke-DbcCheck I think # Lil bit of cleanup here, for a switcharoo $null = $PSBoundParameters.Remove('AllChecks') $null = $PSBoundParameters.Remove('Check') $null = $PSBoundParameters.Remove('ExcludeCheck') $null = $PSBoundParameters.Remove('ConfigFile') $globalexcludedchecks = Get-PSFConfigValue -FullName dbachecks.command.invokedbccheck.excludecheck $global:ChecksToExclude = $ExcludeCheck + $globalexcludedchecks [string[]]$Script:ExcludedDatabases = Get-PSFConfigValue -FullName dbachecks.command.invokedbccheck.excludedatabases $Script:ExcludedDatabases += $ExcludeDatabase foreach ($singlecheck in $check) { if ($singlecheck -in $globalexcludedchecks) { Write-PSFMessage -Level Warning -Message "$singlecheck is excluded in command.invokedbccheck.excludecheck and will be skipped " } } if ($AllChecks -and $globalexcludedchecks) { Write-PSFMessage -Level Warning -Message "$globalexcludedchecks will be skipped" } if ($ExcludedDatabases) { Write-PSFMessage -Level Warning -Message "$ExcludedDatabases databases will be skipped for all checks" } # Then we'll need a generic param passer that doesn't require global params # cuz global params are hard # We so shuld have done this :-) $finishedAllTheChecks = $false try { $repos = Get-CheckRepo foreach ($repo in $repos) { if ((Test-Path $repo -ErrorAction SilentlyContinue)) { if ($OutputFormat -eq "NUnitXml" -and -not $OutputFile) { $number = $repos.IndexOf($repo) $timestamp = Get-Date -Format "yyyyMMddHHmmss" $PSBoundParameters['OutputFile'] = "$script:maildirectory\report-$number-$pid-$timestamp.xml" } if ($Check.Count -gt 0) { # specific checks were listed. find the necessary script files. # We are only going to check the files named v5 here is this a good idea? # Anyone have any better ideas here ? - Remember we need to be able to run under both conditions $Configuration.Run.Path = (Get-CheckFile -Repo $repo -Check $check -v5) } Push-Location -Path $repo ## remove any previous entries ready for this run Set-PSFConfig -Module dbachecks -Name global.notcontactable -Value @() $config = $Configuration | ConvertTo-Json -Depth 5 Write-PSFMessage -Message "Config = $Config" -Level Verbose Write-PSFMessage -Message ($PSBoundParameters | Out-String) -Level Verbose Write-PSFMessage -Message "SqlInstance is $SqlInstance" -Level Verbose # Because we have all these bound params :-( $null = $PSBoundParameters.Remove('configuration') Invoke-Pester -Configuration $configuration Pop-Location } } $finishedAllTheChecks = $true } catch { Stop-PSFFunction -Message "There was a problem executing Invoke-Pester" -ErrorRecord $psitem } finally { # reset the config to original value Set-DbatoolsConfig -FullName message.consoleoutput.disable -Value $dbatoolsoutputconfig if (!($finishedAllTheChecks)) { Write-PSFMessage -Level Warning -Message "Execution was cancelled!" Pop-Location } } } } <# .SYNOPSIS Invoke-DbcCheck is a SQL-centric Invoke-Pester wrapper .DESCRIPTION The Invoke-DbcCheck function runs Pester tests, including *.Tests.ps1 files and Pester tests in PowerShell scripts. Extended description about Pester: Get-Help -Name Invoke-Pester .PARAMETER Check Runs only tests in Describe blocks with the specified Tag parameter values. Wildcard characters and Tag values that include spaces or whitespace characters are not supported. When you specify multiple Tag values, Invoke-DbcCheck runs tests that have any of the listed tags (it ORs the tags). However, when you specify TestName and Tag values, Invoke-DbcCheck runs only describe blocks that have one of the specified TestName values and one of the specified Tag values. If you use both Tag and ExcludeTag, ExcludeTag takes precedence. .PARAMETER ExcludeCheck Omits tests in Describe blocks with the specified Tag parameter values. Wildcard characters and Tag values that include spaces or whitespace characters are not supported. When you specify multiple ExcludeTag values, Invoke-DbcCheck omits tests that have any of the listed tags (it ORs the tags). However, when you specify TestName and ExcludeTag values, Invoke-DbcCheck omits only describe blocks that have one of the specified TestName values and one of the specified Tag values. If you use both Tag and ExcludeTag, ExcludeTag takes precedence .PARAMETER SqlInstance A list of SQL Servers to run the tests against. If this is not provided, it will be gathered from: Get-DbatoolsConfig -Name app.sqlinstance .PARAMETER ComputerName A list of computers to run the tests against. If this is not provided, it will be gathered from: Get-DbatoolsConfig -Name app.computername .PARAMETER SqlCredential Alternate SQL Server-based credential. .PARAMETER Credential Alternate Windows credential. .PARAMETER Database A list of databases to include if your check is database centric. .PARAMETER ExcludeDatabase A list of databases to exclude if your check is database centric. .PARAMETER PassThru Returns a custom object (PSCustomObject) that contains the test results. By default, Invoke-DbcCheck writes to the host program, not to the output stream (stdout). If you try to save the result in a variable, the variable is empty unless you use the PassThru parameter. To suppress the host output, use the Quiet parameter. .PARAMETER ConfigFile The path to the exported dbachecks config file. .PARAMETER OutputFormat The format of output. Currently, only NUnitXML is supported. .PARAMETER Strict Makes Pending and Skipped tests to Failed tests. Useful for continuous integration where you need to make sure all tests passed. .PARAMETER AllChecks In the unlikely event that you'd like to run all checks, specify -AllChecks. These checks still confirm to the skip settings in Get-DbcConfig. .PARAMETER Quiet The parameter Quiet is deprecated since Pester v. 4.0 and will be deleted in the next major version of Pester. Please use the parameter Show with value 'None' instead. .PARAMETER Show Customizes the output Pester writes to the screen. Available options are None Default Passed Failed Pending Skipped Inconclusive Describe Context Summary Header All Fails The options can be combined to define presets. Common use cases are: None - to write no output to the screen. All - to write all available information (this is default option). Fails - to write everything except Passed (but including Describes etc.). A common setting is also Failed, Summary, to write only failed tests and test summary. This parameter does not affect the PassThru custom object or the XML output that is written when you use the Output parameters. .PARAMETER Value A value.. it's hard to explain .PARAMETER Script Get-Help -Name Invoke-Pester -Parameter Script .PARAMETER TestName Get-Help -Name Invoke-Pester -Parameter TestName .PARAMETER EnableExit Get-Help -Name Invoke-Pester -Parameter EnableExit .PARAMETER OutputFile Get-Help -Name Invoke-Pester -Parameter OutputFile .PARAMETER CodeCoverage Get-Help -Name Invoke-Pester -Parameter CodeCoverage .PARAMETER PesterOption Get-Help -Name Invoke-Pester -Parameter PesterOption .PARAMETER CodeCoverageOutputFile Get-Help -Name Invoke-Pester -Parameter CodeCoverageOutputFile .PARAMETER CodeCoverageOutputFileFormat Get-Help -Name Invoke-Pester -Parameter CodeCoverageOutputFileFormat .LINK https://dbachecks.readthedocs.io/en/latest/functions/Invoke-DbcCheck/ .EXAMPLE Invoke-DbcCheck -Tag Backup -SqlInstance sql2016 Runs all of the checks tagged Backup against the sql2016 instance .EXAMPLE Invoke-DbcCheck -Tag RecoveryModel -SqlInstance sql2017, sqlcluster -SqlCredential (Get-Credential sqladmin) Runs the Recovery model check against the SQL instances sql2017, sqlcluster using the sqladmin SQL login with the password provided interactively .EXAMPLE Invoke-DbcCheck -Check Database -ExcludeCheck AutoShrink -ConfigFile \\share\repo\prod.json Runs all of the checks tagged Database except for the AutoShrink check against the SQL Instances set in the config under app.sqlinstance Imports configuration file, \\share\repo\prod.json, prior to executing checks. .EXAMPLE # Set the servers you'll be working with Set-DbcConfig -Name app.sqlinstance -Value sql2016, sql2017, sql2008, sql2008\express Set-DbcConfig -Name app.computername -Value sql2016, sql2017, sql2008 # Look at the current configs Get-DbcConfig # Invoke a few tests Invoke-DbcCheck -Tags SuspectPage, LastBackup Runs the Suspect Pages and Last Backup checks against the SQL Instances sql2016, sql2017, sql2008, sql2008\express after setting them in the configuration .EXAMPLE Invoke-DbcCheck -SqlInstance sql2017 -Tags SuspectPage, LastBackup -Show Summary -PassThru | Update-DbcPowerBiDataSource Start-DbcPowerBi Runs the Suspect Page and Last Backup checks against the SQL Instances set in the config under app.sqlinstance only showing the summary of the results of the checks. It then updates the source json for the XML which is stored at C:\Windows\temp\dbachecks\ and then opens the PowerBi report in PowerBi Desktop .EXAMPLE Get-Help -Name Invoke-Pester -Examples Want to get super deep? You can look at Invoke-Pester's example's and run them against Invoke-DbcCheck since it's a wrapper. https://github.com/pester/Pester/wiki/Invoke-Pester Describe about_Pester #> ================================================ FILE: source/internal/functions/New-Json.ps1 ================================================ function New-Json { [CmdletBinding(SupportsShouldProcess)] Param() # Parse repo for tags and descriptions then write json $script:localapp = Get-DbcConfigValue -Name app.localapp $repos = Get-CheckRepo $collection = $groups = $repofiles = @() foreach ($repo in $repos) { $folders = Join-Path -Path $repo -ChildPath '*.Tests.ps1' $repofiles += (Get-ChildItem $folders ) } $tokens = $null $errors = $null foreach ($file in $repofiles) { $Check = $null # We dont want to mess with v5 files - although we will need to write the json for them if ($file.Name -notmatch 'v5') { $message = "We are going to look at this file {0}" -f $file.Name Write-PSFMessage -Message $message -Level Verbose $filename = $file.Name.Replace(".Tests.ps1", "") # Write-Verbose "Processing $FileName" # Write-Verbose "Getting Content of File" $Check = [System.IO.File]::ReadAllText($file) # because custom checks if they are not coded correctly will break this json creation # and they wont get added nicely so that they can be targetted with tags (checks) # this part will check all of the files and ensure that they have the filename variabel at the top and that # each describe is using Tags not Tag and the last tag is the $filename if ($Filename -notin ('Agent', 'Database', 'Domain', 'HADR', 'Instance', 'LogShipping', 'MaintenanceSolution', 'Server')) { #all checks files MUST have this at the top if ($Check -notmatch '\$filename = \$MyInvocation\.MyCommand\.Name\.Replace\("\.Tests\.ps1", ""\)') { Write-Verbose "$Filename does not have the correct value at the top so we will add it" $filecontent = @" `$filename = `$MyInvocation.MyCommand.Name.Replace(".Tests.ps1", "") "@ $filecontent = $filecontent + $Check if ($PSCmdlet.ShouldProcess("$($File.Name)" , "Adding the filename variable to the file")) { $Check = $null Set-Content -Path $file -Value $filecontent Write-Verbose "Getting Content of File again" $Check = [System.IO.File]::ReadAllText($file) } } ## Parse the file with AST $CheckFileAST = [Management.Automation.Language.Parser]::ParseInput($check, [ref]$tokens, [ref]$errors) #Check that the tags are set correctly otherwise the json doesnt get properly created $Statements = $CheckFileAST.EndBlock.statements.Extent ## Ignore the filename line @($Statements.Where{ $PSItem.StartLineNumber -ne 1 }).ForEach{ # Write-Verbose "Checking the Describe Tag $($PSItem.Text.SubString(0,50) )" if ($PSItem.Text -notmatch 'Describe ".*" -Tags .*,.*\$filename \{') { $RogueDescribe = $PSItem.Text.SubString(0, $PSitem.Text.IndexOf('{')) Write-Warning "The Describe Tag $RogueDescribe in $($File.Name) is not set up correctly - we will try to fix it for you" $replace = $RogueDescribe + ', $Filename ' $Check = $Check -replace $RogueDescribe , $replace $Check = $Check -replace '-Tag ', '-Tags ' if ($PSCmdlet.ShouldProcess("$($File.Name)" , "Fixing the tags on the files")) { Set-Content $file -Value $Check $Check = $null } # Write-Verbose "Getting Content of File again" $Check = [System.IO.File]::ReadAllText($file) } } } ## Parse the file with AST $CheckFileAST = [Management.Automation.Language.Parser]::ParseInput($check, [ref]$tokens, [ref]$errors) ## New code uses a Computer Name loop to speed up execution so need to find that as well $ComputerNameForEach = $CheckFileAST.FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast -is [System.Management.Automation.Language.InvokeMemberExpressionAst] -and $ast.expression.Subexpression.Extent.Text -eq 'Get-ComputerName' }, $true).Extent ## New code uses a Computer Name loop to speed up execution so need to find that as well $InstanceNameForEach = $CheckFileAST.FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast -is [System.Management.Automation.Language.InvokeMemberExpressionAst] -and $ast.expression.Subexpression.Extent.Text -eq 'Get-Instance' }, $true).Extent ## Old code we can use the describes $Describes = $CheckFileAST.FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast.CommandElements -and $ast.CommandElements[0].Value -eq 'Describe' }, $true) @($describes).ForEach{ $groups += $filename $Describe = $_.CommandElements.Where{ $PSItem.StaticType.name -eq 'string' }[1] $title = $Describe.Value $Tags = $PSItem.CommandElements.Where{ $PSItem.StaticType.name -eq 'Object[]' -and $null -eq $psitem.Value }.Extent.Text.ToString().Replace(', $filename', '') # CHoose the type if ($Describe.Parent -match "Get-Instance") { $type = "Sqlinstance" } elseif ($Describe.Parent -match "Get-ComputerName" -or $Describe.Parent -match "AllServerInfo") { $type = "ComputerName" } elseif ($Describe.Parent -match "Get-ClusterObject") { $Type = "ClusterNode" } else { #Choose the type from the new way from inside the foreach if ($ComputerNameForEach -match $title) { $type = "ComputerName" } elseif ($InstanceNameForEach -match $title) { $type = "Sqlinstance" } else { $type = $null } } if ($filename -eq 'HADR') { ## HADR configs are outside of describe $configs = [regex]::matches($check, "Get-DbcConfigValue\s([a-zA-Z\d]*.[a-zA-Z\d]*.[a-zA-Z\d]*.[a-zA-Z\d]*\b)").groups.Where{ $_.Name -eq 1 }.Value } else { $configs = [regex]::matches($describe.Parent.Extent.Text, "Get-DbcConfigValue\s([a-zA-Z\d]*.[a-zA-Z\d]*.[a-zA-Z\d]*.[a-zA-Z\d]*\b)").groups.Where{ $_.Name -eq 1 }.Value } $Config = '' foreach ($c in $Configs) { $config += "$c " } # DON't DELETE THE SPACE in "$c " if ($filename -eq 'MaintenanceSolution') { # The Maintenance Solution needs a bit of faffing as the configs for the jobnames are used to create the titles switch ($tags -match $PSItem) { { $Tags.Contains('SystemFull') } { $config = 'ola.JobName.SystemFull ' + $config $title = 'Ola - ' + (Get-DbcConfigValue -Name ola.jobname.systemfull) } { $Tags.Contains('UserFull') } { $config = 'ola.JobName.UserFull ' + $config $title = 'Ola - ' + (Get-DbcConfigValue -Name ola.jobname.userfull) } { $Tags.Contains('UserDiff') } { $config = 'ola.JobName.UserDiff ' + $config $title = 'Ola - ' + (Get-DbcConfigValue -Name ola.jobname.userdiff) } { $Tags.Contains('UserLog') } { $config = 'ola.JobName.UserLog ' + $config $title = 'Ola - ' + (Get-DbcConfigValue -Name ola.jobname.userlog) } { $Tags.Contains('CommandLog') } { $config = 'ola.JobName.CommandLogCleanup ' + $config $title = 'Ola - ' + (Get-DbcConfigValue -Name ola.jobname.commandlogcleanup) } { $Tags.Contains('SystemIntegrityCheck') } { $config = 'ola.JobName.SystemIntegrity ' + $config $title = 'Ola - ' + (Get-DbcConfigValue -Name ola.jobname.systemintegrity) } { $Tags.Contains('UserIntegrityCheck') } { $config = 'ola.JobName.UserIntegrity ' + $config $title = 'Ola - ' + (Get-DbcConfigValue -Name ola.jobname.userintegrity) } { $Tags.Contains('UserIndexOptimize') } { $config = 'ola.JobName.UserIndex ' + $config $title = 'Ola - ' + (Get-DbcConfigValue -Name ola.jobname.userindex) } { $Tags.Contains('OutputFileCleanup') } { $config = 'ola.JobName.OutputFileCleanup ' + $config $title = 'Ola - ' + (Get-DbcConfigValue -Name ola.jobname.outputfilecleanup) } { $Tags.Contains('DeleteBackupHistory') } { $config = 'ola.JobName.DeleteBackupHistory ' + $config $title = 'Ola - ' + (Get-DbcConfigValue -Name ola.jobname.deletebackuphistory) } { $Tags.Contains('PurgeJobHistory') } { $config = 'ola.JobName.PurgeBackupHistory ' + $config $title = 'Ola - ' + (Get-DbcConfigValue -Name ola.jobname.purgebackuphistory) } Default {} } } # add the config for the type switch ($type) { SqlInstance { $config = 'app.sqlinstance ' + $config } ComputerName { $config = 'app.computername ' + $config } ClusterNode { $config = 'app.sqlinstance ' + $config } Default {} } if (-not $config) { $config = "None" } $collection += [pscustomobject]@{ Group = $filename Type = $type UniqueTag = $null AllTags = "$tags, $filename" Config = $config Description = $null Describe = $title } } } } $singletags = (($collection.AllTags -split ",").Trim() | Group-Object | Where-Object { $_.Count -eq 1 -and $_.Name -notin $groups }) $descriptionsFile = Join-Path -Path $script:ModuleRoot -ChildPath 'internal\configurations\DbcCheckDescriptions.json' $descriptions = [System.IO.File]::ReadAllText($descriptionsFile) | ConvertFrom-Json foreach ($check in $collection) { $unique = $singletags | Where-Object { $_.Name -in ($check.AllTags -split ",").Trim() } $check.UniqueTag = $unique.Name $Check.Description = $Descriptions.Where{ $_.UniqueTag -eq $Check.UniqueTag }.Description } try { $checksfile = Join-Path -Path $script:localapp -ChildPath 'checks.json' if ($PSCmdlet.ShouldProcess($checksfile , "Convert Json and write to file")) { ConvertTo-Json -InputObject $collection | Out-File $checksfile } } catch { Write-PSFMessage "Failed to create the json, something weird might happen now with tags and things" -Level Significant } } ================================================ FILE: source/internal/functions/NewGet-AllInstanceInfo.ps1 ================================================ function NewGet-AllInstanceInfo { # Using the unique tags gather the information required Param($Instance, $Tags) #clear out the default initialised fields $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Login], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.StoredProcedure], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Information], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Settings], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.LogFile], $false) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.DataFile], $false) # set the default init fields for all the tags # Server Initial fields $ServerInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server]) $ServerInitFields.Add("VersionMajor") | Out-Null # so we can check versions $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server], $ServerInitFields) # Database Initial Fields $DatabaseInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database]) # Stored Procedure Initial Fields $StoredProcedureInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.StoredProcedure]) # Information Initial Fields # Settings Initial Fields $SettingsInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Settings]) # Login Initial Fields $LoginInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Login]) # Log File Initial Fields $LogFileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.LogFile]) # Data File Initial Fields $DataFileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.DataFile]) # Configuration cannot have default init fields :-) $configurations = $false # Set up blank ConfigValues object for any config we need to use in the checks $ConfigValues = [PSCustomObject]@{} # Using there so that if the instance is not contactable, no point carrying on with gathering more information switch ($tags) { 'DefaultTrace' { $configurations = $true } 'OleAutomationProceduresDisabled' { $configurations = $true } 'CrossDBOwnershipChaining' { $configurations = $true } 'ScanForStartupProceduresDisabled' { # we have to check the spconfigure and we have to check that any stored procedurees in master have startup set to true $configurations = $true $ScanForStartupProceduresDisabled = $true $StoredProcedureInitFields.Add("Startup") | Out-Null # So we can check SPs start up for the CIS checks $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.StoredProcedure], $StoredProcedureInitFields) $StoredProcedureInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.StoredProcedure]) # I think we need to re-initialise here $ConfigValues | Add-Member -MemberType NoteProperty -Name 'scanforstartupproceduresdisabled' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.security.scanforstartupproceduresdisabled' }).Value) } 'RemoteAccessDisabled' { $configurations = $true } 'SQLMailXPsDisabled' { $configurations = $true } 'DAC' { $configurations = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'dacallowed' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.dacallowed' }).Value) } 'OLEAutomation' { $configurations = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'OLEAutomation' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.oleautomation' }).Value) } 'AdHocWorkload' { $configurations = $true } 'AdHocDistributedQueriesEnabled' { $configurations = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AdHocDistributedQueriesEnabled' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.security.AdHocDistributedQueriesEnabled' }).Value) } 'DefaultBackupCompression' { $configurations = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'DefaultBackupCompression' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.backup.defaultbackupcompression' }).Value) } 'DefaultFilePath' { $SettingsInitFields.Add("DefaultFile") | Out-Null # so we can check file paths $SettingsInitFields.Add("DefaultLog") | Out-Null # so we can check file paths $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Settings], $SettingsInitFields) } 'SaRenamed' { } 'SaDisabled' { $LoginInitFields.Add("IsDisabled") | Out-Null # so we can check if sa is disabled $LoginInitFields.Add("ID") | Out-Null # so we can check if sa is disabled even if it has been renamed $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Settings], $LoginInitFields) } 'ModelDbGrowth' { $LogFileInitFields.Add("Growth") | Out-Null # So we can check the model file growth settings $LogFileInitFields.Add("GrowthType") | Out-Null # So we can check the model file growth settings $LogFileInitFields.Add("Name") | Out-Null # So we can check the model file growth settings $DataFileInitFields.Add("Growth") | Out-Null # So we can check the model file growth settings $DataFileInitFields.Add("GrowthType") | Out-Null # So we can check the model file growth settings $DataFileInitFields.Add("Name") | Out-Null # So we can check the model file growth settings $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.LogFile], $LogFileInitFields) $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.DataFile], $DataFileInitFields) $LogFileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.LogFile]) # I think we need to re-initialise here $DataFileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.DataFile]) # I think we need to re-initialise here } 'ErrorlogCount' { $ServerInitFields.Add("NumberOfLogFiles") | Out-Null # so we can check versions $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server], $ServerInitFields) $ServerInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server]) # I think we need to re-initialise here $ConfigValues | Add-Member -MemberType NoteProperty -Name 'errorLogCount' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.errorlog.logcount' }).Value) } 'MaxDopInstance' { #Test-DbaMaxDop needs these because it checks every database as well $DatabaseInitFields.Add("IsAccessible") | Out-Null # so we can check if its accessible $DatabaseInitFields.Add("IsSystemObject ") | Out-Null # so we can check if its accessible $DatabaseInitFields.Add("MaxDop ") | Out-Null # so we can check if its accessible $DatabaseInitFields.Add("Name ") | Out-Null # so we can check if its accessible $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database], $DatabaseInitFields) $DatabaseInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database]) # I think we need to re-initialise here $ConfigValues | Add-Member -MemberType NoteProperty -Name 'UseRecommendedMaxDop' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.instancemaxdop.userecommended' }).Value) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'InstanceMaxDop' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.instancemaxdop.maxdop' }).Value) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'ExcludeInstanceMaxDop' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.instancemaxdop.excludeinstance' }).Value) if ($Instance.Name -notin $ConfigValues.ExcludeInstanceMaxDop) { $MaxDopSettings = (Test-DbaMaxDop -SqlInstance $Instance)[0] # because we dont care about the database maxdops here - potentially we could store it and use it for DatabaseMaxDop ? } } 'TwoDigitYearCutoff' { $configurations = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'TwoDigitYearCutoff' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.twodigityearcutoff' }).Value) } 'TraceFlagsExpected' { $TraceFlagsExpected = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.traceflags.expected' }).Value $TraceFlagsActual = $Instance.EnumActiveGlobalTraceFlags() if (-not $ConfigValues.TraceFlagsExpected) { $ConfigValues | Add-Member -MemberType NoteProperty -Name 'TraceFlagsExpected' -Value $TraceFlagsExpected -Force } $ExpectedTraceFlags = $TraceFlagsExpected.Foreach{ [PSCustomObject]@{ InstanceName = $Instance.Name ExpectedTraceFlag = $PSItem ActualTraceFlags = $TraceFlagsActual } } $ExpectedTraceFlags += [PSCustomObject]@{ InstanceName = $Instance.Name ExpectedTraceFlag = 'null' ActualTraceFlags = $TraceFlagsActual } } 'TraceFlagsNotExpected' { $TraceFlagsNotExpected = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.traceflags.notexpected' }).Value $TraceFlagsExpected = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.traceflags.expected' }).Value if ($null -eq $TraceFlagsExpected) { $TraceFlagsExpected = 'none expected' } $TraceFlagsActual = $Instance.EnumActiveGlobalTraceFlags() $ConfigValues | Add-Member -MemberType NoteProperty -Name 'TraceFlagsNotExpected' -Value $TraceFlagsNotExpected if (-not $ConfigValues.TraceFlagsExpected) { $ConfigValues | Add-Member -MemberType NoteProperty -Name 'TraceFlagsExpected' -Value $TraceFlagsExpected -Force } $NotExpectedTraceFlags = $TraceFlagsNotExpected.Where{ $_ -notin $TraceFlagsExpected }.Foreach{ [PSCustomObject]@{ InstanceName = $Instance.Name NotExpectedTraceFlag = $PSItem TraceFlagsExpected = $TraceFlagsExpected ActualTraceFlags = $TraceFlagsActual } } $NotExpectedTraceFlags += [PSCustomObject]@{ InstanceName = $Instance.Name TraceFlagsExpected = $TraceFlagsExpected NotExpectedTraceFlag = 'null' ActualTraceFlags = $TraceFlagsActual } } 'CLREnabled' { $configurations = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'CLREnabled' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.security.clrenabled' }).Value) } 'WhoIsActiveInstalled' { $configurations = $true $WhoIsActiveInstalled = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'whoisactivedatabase' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.whoisactive.database' }).Value) } 'XpCmdShellDisabled' { $configurations = $true $ConfigValues | Add-Member -MemberType NoteProperty -Name 'XpCmdShellDisabled' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.security.XpCmdShellDisabled' }).Value) } 'XESessionStopped' { if (-not $xeSessions) { $xeSessions = Get-DbaXESession -SqlInstance $Instance } $RequiredStopped = (($__dbcconfig | Where-Object { $_.Name -eq 'policy.xevent.requiredstoppedsession' }).Value) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'requiredstoppedsession' -Value $RequiredStopped if (-not $xeSessions) { $RunningSessions = $xeSessions.Where{ $_.Status -eq 'Running' }.Name } if (-not $Sessions) { $Sessions = $xeSessions.Name } } 'XESessionExists' { if (-not $xeSessions) { $xeSessions = Get-DbaXESession -SqlInstance $Instance } $RequiredExists = (($__dbcconfig | Where-Object { $_.Name -eq 'policy.xevent.requiredexists' }).Value) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'requiredexistssessions' -Value $RequiredExists if (-not $RunningSessions) { $RunningSessions = $xeSessions.Where{ $_.Status -eq 'Running' }.Name } if (-not $Sessions) { $Sessions = $xeSessions.Name } } 'XESessionRunning' { if (-not $xeSessions) { $xeSessions = Get-DbaXESession -SqlInstance $Instance } $RequiredRunning = (($__dbcconfig | Where-Object { $_.Name -eq 'policy.xevent.requiredrunningsession' }).Value) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'requiredrunningsession' -Value $RequiredRunning if (-not $RunningSessions) { $RunningSessions = $xeSessions.Where{ $_.Status -eq 'Running' }.Name } if (-not $Sessions) { $Sessions = $xeSessions.Name } } 'XESessionRunningAllowed' { if (-not $xeSessions) { $xeSessions = Get-DbaXESession -SqlInstance $Instance } $RunningAllowed = (($__dbcconfig | Where-Object { $_.Name -eq 'policy.xevent.validrunningsession' }).Value) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'validrunningsession' -Value $RunningAllowed if (-not $RunningSessions) { $RunningSessions = $xeSessions.Where{ $_.Status -eq 'Running' }.Name } if (-not $Sessions) { $Sessions = $xeSessions.Name } } 'ErrorLog' { $logWindow = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.errorlog.warningwindow' }).Value # so that it can be mocked function Get-ErrorLogEntry { # get the number of the first error log that was created after the log window config $OldestErrorLogNumber = ($InstanceSMO.EnumErrorLogs() | Where-Object { $psitem.CreateDate -gt (Get-Date).AddDays( - $LogWindow) } | Sort-Object ArchiveNo -Descending | Select-Object -First 1).ArchiveNo + 1 # Get the Error Log entries for each one (0..$OldestErrorLogNumber).ForEach{ $InstanceSMO.ReadErrorLog($psitem).Where{ $_.Text -match "Severity: 1[7-9]|Severity: 2[0-4]" } } } # It is not enough to check the CreateDate on the log, you must check the LogDate on every error record as well. $ErrorLogCount = (Get-ErrorLogEntry | Where-Object { $psitem.LogDate -gt (Get-Date).AddDays( - $LogWindow) }).Count } 'TempDbConfiguration' { $TempDBTest = Test-DbaTempDbConfig -SqlInstance $Instance } 'InstanceConnection' { #local is always NTLM except when its a container ;-) if ($Instance.ComputerNamePhysicalNetBIOS -eq $ENV:COMPUTERNAME -and ($instance.Name -notlike '*,*')) { $authscheme = 'skipped-local' } else { if (-not(($__dbcconfig | Where-Object { $_.Name -eq 'skip.connection.auth' }).Value)) { $authscheme = $instance.Query("Select auth_scheme as AuthScheme FROM sys.dm_exec_connections WHERE session_id = @@SPID").AuthScheme } else { $authscheme = 'skipped' } } if ($IsWindows) { if (-not(($__dbcconfig | Where-Object { $_.Name -eq 'skip.connection.ping' }).Value)) { $pingu = New-Object System.Net.NetworkInformation.Ping $timeout = 1000 #milliseconds $ping = ($pingu.Send($instance.ComputerName, $timeout)).Status } else { $ping = 'skipped' } } else { $ping = 'skipped' } if (-not(($__dbcconfig | Where-Object { $_.Name -eq 'skip.connection.remote' }).Value)) { #simple remoting check try { $null = Invoke-Command -ComputerName $instance.ComputerName -ScriptBlock { Get-ChildItem } -ErrorAction Stop $remote = $true } catch { $remote = $false } } else { $remote = 'skipped' } $InstanceConnection = @{ Connect = $true # because we wouldnt get here otherwise AuthScheme = $authscheme Ping = $ping Remote = $remote } } 'BackUpPathAccess' { # get value from config or from default setting $BackupPath = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.storage.backuppath' }).Value if (-not $BackupPath) { $BackupPath = $Instance.BackupDirectory } $BackupPathAccess = Test-DbaPath -SqlInstance $Instance -Path $BackupPath } 'LatestBuild' { $LatestBuild = Test-DbaBuild -SqlInstance $Instance -Latest } 'NetworkLatency' { $NetworkThreshold = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.network.latencymaxms' }).Value $Latency = (Test-DbaNetworkLatency -SqlInstance $Instance).NetworkOnlyTotal.TotalMilliseconds } 'LinkedServerConnection' { $LinkedServerResults = Test-DbaLinkedServerConnection -SqlInstance $Instance } 'MaxMemory' { if ($isLinux -or $isMacOS) { $totalMemory = $Instance.PhysicalMemory # Some servers under-report by 1. if (($totalMemory % 1024) -ne 0) { $totalMemory = $totalMemory + 1 } $MaxMemory = [PSCustomObject]@{ MaxValue = $Instance.Configuration.MaxServerMemory.ConfigValue + 379 RecommendedValue = $totalMemory # because we added 379 before and I have zero idea why } } else { $MemoryValues = Test-DbaMaxMemory -SqlInstance $Instance $MaxMemory = [PSCustomObject]@{ MaxValue = $MemoryValues.MaxValue RecommendedValue = $MemoryValues.RecommendedValue } } } 'OrphanedFile' { $FileCount = @(Find-DbaOrphanedFile -SqlInstance $Instance).Count } 'ServerNameMatch' { $ServerNameMatchconfiguredServerName = $Instance.Query("SELECT @@servername AS ServerName").ServerName $ServerNameMatchnetName = $Instance.NetName $ServerNameMatchrenamerequired = $ServerNameMatchnetName -ne $ServerNameMatchconfiguredServerName } 'MemoryDump' { $maxdumps = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.dump.maxcount' }).Value $daystocheck = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.instance.memorydumpsdaystocheck' }).Value if ($null -eq $daystocheck) { $datetocheckfrom = '0001-01-01' } else { $datetocheckfrom = (Get-Date).ToUniversalTime().AddDays( - $daystocheck ) } if (($InstanceSMO.Version.Major -lt 11 -and (-not ($InstanceSMO.Version.Major -eq 10 -and $InstanceSMO.Version.Minor -eq 50)))) { $MemoryDumpCount = 0 } else { # Warning Action removes dbatools output for version too low from test results # Skip on the it will show in the results $MemoryDumpCount = (@(Get-DbaDump -SqlInstance $Instance -WarningAction SilentlyContinue).Where{ $_.CreationTime -gt $datetocheckfrom }).Count } $Dump = [pscustomobject] @{ DumpCount = $MemoryDumpCount MaxDumps = $maxdumps DumpDateCheckFrom = $datetocheckfrom Result = $MemoryDumpCount -le $maxdumps } } 'HideInstance' { try { $HideInstance = [pscustomobject] @{ Result = (Get-DbaHideInstance -SqlInstance $InstanceSMO).HideInstance } } catch { $HideInstance = [pscustomobject] @{ Result = 'We Could not Connect to $Instance' } } } 'LoginAuditFailed' { $SettingsInitFields.Add("AuditLevel") | Out-Null # so we can check auditlevel $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Settings], $SettingsInitFields) } 'LoginAuditSuccessful' { $SettingsInitFields.Add("AuditLevel") | Out-Null # so we can check auditlevel $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Settings], $SettingsInitFields) } 'LoginCheckPolicy' { $LoginInitFields.Add("IsDisabled") | Out-Null # so we can check login check policy $LoginInitFields.Add("PasswordPolicyEnforced") | Out-Null # so we can check login check policy $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Settings], $LoginInitFields) } { 'PublicRolePermissions' -or 'PublicPermission' } { #This needs to be done in query just in case the account had already been renamed $query = " SELECT Count(*) AS [RowCount] FROM master.sys.server_permissions WHERE (grantee_principal_id = SUSER_SID(N'public') and state_desc LIKE 'GRANT%') AND NOT (state_desc = 'GRANT' and [permission_name] = 'VIEW ANY DATABASE' and class_desc = 'SERVER') AND NOT (state_desc = 'GRANT' and [permission_name] = 'CONNECT' and class_desc = 'ENDPOINT' and major_id = 2) AND NOT (state_desc = 'GRANT' and [permission_name] = 'CONNECT' and class_desc = 'ENDPOINT' and major_id = 3) AND NOT (state_desc = 'GRANT' and [permission_name] = 'CONNECT' and class_desc = 'ENDPOINT' and major_id = 4) AND NOT (state_desc = 'GRANT' and [permission_name] = 'CONNECT' and class_desc = 'ENDPOINT' and major_id = 5); " $PublicRolePermsCount = $Instance.Query($query).RowCount } 'SuspectPageLimit' { $sql = "Select COUNT(file_id) as 'SuspectPageCount' from msdb.dbo.suspect_pages" $SuspectPageCountResult = (($Instance.Query($sql).SuspectPageCount / 1000) * 100 ) -lt ($__dbcconfig | Where-Object { $_.Name -eq 'policy.suspectpage.threshold' }).Value } 'SupportedBuild' { $BuildWarning = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.build.warningwindow' }).Value $BuildBehind = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.build.behind' }).Value $Date = Get-Date #If $BuildBehind check against SP/CU parameter to determine validity of the build if ($BuildBehind) { $buildBehindResults = Test-DbaBuild -SqlInstance $Instance -SqlCredential $sqlcredential -MaxBehind $BuildBehind $Compliant = $buildBehindResults.Compliant #If no $BuildBehind only check against support dates } else { $Compliant = $true } $Results = Test-DbaBuild -SqlInstance $Instance -SqlCredential $sqlcredential -Latest [DateTime]$SupportedUntil = Get-Date $results.SupportedUntil -Format O $Build = $results.build #If $BuildWarning, check for support date within the warning window if ($BuildWarning) { [DateTime]$expected = Get-Date ($Date).AddMonths($BuildWarning) -Format O $SupportedUntil | Should -BeGreaterThan $expected -Because "this build $Build will be unsupported by Microsoft on $(Get-Date $SupportedUntil -Format O) which is less than $BuildWarning months away" } else { #If neither, check for Microsoft support date $SupportedUntil | Should -BeGreaterThan $Date -Because "this build $Build is now unsupported by Microsoft" } $SupportedBuild = [pscustomobject]@{ BuildBehind = $BuildBehind Compliant = $Compliant Build = $Build SupportedUntil = $SupportedUntil Expected = $expected BuildWarning = $BuildWarning InsideBuildWarning = $SupportedUntil -gt $expected InsideMicrosoftSupport = $SupportedUntil -gt $Date } } 'LoginMustChange' { $loginTimeSql = "SELECT login_name, MAX(login_time) AS login_time FROM sys.dm_exec_sessions GROUP BY login_name" $loginTimes = $instance.ConnectionContext.ExecuteWithResults($loginTimeSql).Tables[0] $lastlogin = @{Name = 'LastLogin' ; Expression = { $Name = $_.name; ($loginTimes | Where-Object { $_.login_name -eq $name }).login_time } } $LoginMustChangeCount = ($Instance.Logins | Where-Object { $_.LoginType -eq 'SqlLogin' } | Where-Object { $_.Name -in $Instance.Roles['sysadmin'].EnumMemberNames() } | Select-Object Name, $lastlogin, MustChangePassword, IsDisabled | Where-Object { $_.MustChangePassword -eq $false -and $_.IsDisabled -eq $false -and $null -eq $_.LastLogin }).Count } 'LoginPasswordExpiration' { $LoginPasswordExpirationCount = ($Instance.Logins | Where-Object { $_.Name -in $Instance.Roles['sysadmin'].EnumMemberNames() } | Where-Object { $_.LoginType -eq 'SqlLogin' -and $_.PasswordExpirationEnabled -EQ $false -and $_.IsDisabled -EQ $false }).Count } 'AgentServiceAdmin' { try { $SqlAgentService = Get-DbaService -ComputerName $Instance.ComputerName -InstanceName $Instance.DbaInstanceName -Type Agent -ErrorAction SilentlyContinue $LocalAdmins = Invoke-Command -ComputerName $ComputerName -ScriptBlock { Get-LocalGroupMember -Group "Administrators" } -ErrorAction SilentlyContinue $AgentServiceAdminExist = $localAdmins.Name.Contains($SqlAgentService.StartName) } catch [System.Exception] { if ($_.Exception.Message -like '*No services found in relevant namespaces*') { $AgentServiceAdminExist = $false } else { $AgentServiceAdminExist = 'Some sort of failure' } } catch { $AgentServiceAdminExist = 'We Could not Connect to $Instance $ComputerName , $InstanceName from catch' } } 'SqlEngineServiceAccount' { $starttype = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.instance.sqlenginestart' }).Value $state = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.instance.sqlenginestate' }).Value try { $EngineAccounts = Get-DbaService -ComputerName $psitem -Type Engine -ErrorAction Stop } catch [System.Exception] { if ($_.Exception.Message -like '*No services found in relevant namespaces*') { $EngineAccounts = [PSCustomObject]@{ InstanceName = $Instance.Name State = 'unknown' ExpectedState = $state StartType = 'unknown' ExpectedStartType = $starttype because = 'Some sort of failure - No services found in relevant namespaces' } } else { $EngineAccounts = [PSCustomObject]@{ InstanceName = $Instance.Name State = 'unknown' ExpectedState = $state StartType = 'unknown' ExpectedStartType = $starttype because = 'Some sort of failure' } } } catch { $EngineAccounts = [PSCustomObject]@{ InstanceName = $Instance.Name State = 'unknown' ExpectedState = $state StartType = 'unknown' ExpectedStartType = $starttype because = 'We Could not Connect to $Instance $ComputerName , $InstanceName from catch' } } if ($Instance.IsClustered) { $starttype = 'Manual' $because = 'This is a clustered instance and Clustered Instances required that the SQL engine service is set to manual' } else { $because = "The SQL Service Start Type was expected to be $starttype" } $SqlEngineServiceAccount = foreach ($EngineAccount in $EngineAccounts) { [PSCustomObject]@{ InstanceName = $Instance.Name State = $EngineAccount.State ExpectedState = $state StartType = $EngineAccount.StartType ExpectedStartType = $starttype because = $because } } } Default { } } #build the object $testInstanceObject = [PSCustomObject]@{ ComputerName = $Instance.ComputerName InstanceName = $Instance.DbaInstanceName Name = $Instance.Name ConfigValues = $ConfigValues VersionMajor = $Instance.VersionMajor Configuration = if ($configurations) { $Instance.Configuration } else { $null } Settings = $Instance.Settings Logins = $Instance.Logins Databases = $Instance.Databases NumberOfLogFiles = $Instance.NumberOfLogFiles MaxDopSettings = $MaxDopSettings ExpectedTraceFlags = $ExpectedTraceFlags NotExpectedTraceFlags = $NotExpectedTraceFlags XESessions = [pscustomobject]@{ RequiredStopped = $RequiredStopped.ForEach{ [pscustomobject]@{ Name = $Instance.Name SessionName = $PSItem Running = $RunningSessions } } RequiredExists = $RequiredExists.ForEach{ [pscustomobject]@{ Name = $Instance.Name SessionName = $PSItem Sessions = $Sessions } } RequiredRunning = $RequiredRunning.ForEach{ [pscustomobject]@{ Name = $Instance.Name SessionName = $PSItem Sessions = $Sessions Running = $RunningSessions } } RunningAllowed = $RunningSessions.ForEach{ [pscustomobject]@{ Name = $Instance.Name SessionName = $PSItem Sessions = $Sessions Allowed = $RunningAllowed } } Name = $Instance.Name Sessions = $Sessions Running = $RunningSessions } ErrorLogEntries = [pscustomobject]@{ errorLogCount = $ErrorLogCount logWindow = $logWindow } InstanceConnection = $InstanceConnection BackupPathAccess = [pscustomobject]@{ Result = $BackupPathAccess BackupPath = $BackupPath } LatestBuild = [PSCustomObject]@{ Compliant = $LatestBuild.Compliant } NetworkLatency = [PSCustomObject]@{ Latency = $Latency Threshold = $NetworkThreshold } LinkedServerResults = if ($LinkedServerResults) { $LinkedServerResults.ForEach{ [pscustomobject]@{ InstanceName = $Instance.Name LinkedServerName = $PSItem.LinkedServerName RemoteServer = $PSItem.RemoteServer Connectivity = $PSItem.Connectivity Result = $PSItem.Result } } } else { [pscustomobject]@{ InstanceName = $Instance.Name LinkedServerName = 'None found' RemoteServer = 'None' Connectivity = $true Result = 'None' } } MaxMemory = $MaxMemory OrphanedFile = [pscustomobject]@{ FileCount = $FileCount } ServerNameMatch = [pscustomobject]@{ configuredServerName = $ServerNameMatchconfiguredServerName netName = $ServerNameMatchnetName renamerequired = $ServerNameMatchrenamerequired } MemoryDump = $Dump HideInstance = $HideInstance SuspectPageCountResult = $SuspectPageCountResult SupportedBuild = $SupportedBuild LoginMustChangeCount = $LoginMustChangeCount LoginPasswordExpirationCount = $LoginPasswordExpirationCount AgentServiceAdminExist = $AgentServiceAdminExist SqlEngineServiceAccount = $SqlEngineServiceAccount PublicRolePermissions = $PublicRolePermsCount # TempDbConfig = [PSCustomObject]@{ # TF118EnabledCurrent = $tempDBTest[0].CurrentSetting # TF118EnabledRecommended = $tempDBTest[0].Recommended # TempDBFilesCurrent = $tempDBTest[1].CurrentSetting # TempDBFilesRecommended = $tempDBTest[1].Recommended # } } if ($ScanForStartupProceduresDisabled) { $StartUpSPs = $Instance.Databases['master'].StoredProcedures.Where{ $_. Name -ne 'sp_MSrepl_startup' -and $_.StartUp -eq $true }.count if ($StartUpSPs -eq 0) { $testInstanceObject.Configuration.ScanForStartupProcedures.ConfigValue = 0 } } if ($WhoIsActiveInstalled) { $whoisdatabase = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.whoisactive.database' }).Value $WhoIsActiveInstalled = $Instance.Databases[$whoisdatabase].StoredProcedures.Where{ $_.Name -eq 'sp_WhoIsActive' }.count $testInstanceObject.ConfigValues | Add-Member -MemberType NoteProperty -Name 'WhoIsActiveInstalled' -Value $whoIsActiveInstalled } return $testInstanceObject } ================================================ FILE: source/internal/functions/Select-DefaultView.ps1 ================================================ function Select-DefaultView { <# This command enables us to send full on objects to the pipeline without the user seeing it See it in action in Get-DbaSnapshot and Remove-DbaDbSnapshot a lot of this is from boe, thanks boe! https://learn-powershell.net/2013/08/03/quick-hits-set-the-default-property-display-in-powershell-on-custom-objects/ TypeName creates a new type so that we can use ps1xml to modify the output #> [CmdletBinding()] param ( [parameter(ValueFromPipeline = $true)] [object]$InputObject, [string[]]$Property, [string[]]$ExcludeProperty, [string]$TypeName ) process { #if ($null -eq $InputObject) { return } if ($TypeName) { $InputObject.PSObject.TypeNames.Insert(0, "dbachecks.$TypeName") } if ($ExcludeProperty) { if ($InputObject.GetType().Name.ToString() -eq 'DataRow') { $ExcludeProperty += 'Item', 'RowError', 'RowState', 'Table', 'ItemArray', 'HasErrors' } $properties = ($InputObject.PsObject.Members | Where-Object MemberType -ne 'Method' | Where-Object { $_.Name -notin $ExcludeProperty }).Name $defaultset = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet', [string[]]$properties) } else { # property needs to be string if ("$property" -like "* as *") { $newproperty = @() foreach ($p in $property) { if ($p -like "* as *") { $old, $new = $p -isplit " as " # Do not be tempted to not pipe here $inputobject | Add-Member -Force -MemberType AliasProperty -Name $new -Value $old -ErrorAction SilentlyContinue $newproperty += $new } else { $newproperty += $p } } $property = $newproperty } $defaultset = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet', [string[]]$Property) } $standardmembers = [System.Management.Automation.PSMemberInfo[]]@($defaultset) # Do not be tempted to not pipe here $inputobject | Add-Member -Force -MemberType MemberSet -Name PSStandardMembers -Value $standardmembers -ErrorAction SilentlyContinue $inputobject } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUhgrq4r+vWdkSy71AQize8SXx # tQ6gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQP2A4ycR+17K3nh4JHESq3urkk # bDANBgkqhkiG9w0BAQEFAASCAQACfk+ri4MHdwxCscxPaPI39K22xXo/psfOxFvE # KeWMgCD0k1QMh0O3VY0vivpIMq7YmCg09bXErYH3PS7ELCOfOQHSv3Da7svtelPO # 4OnM9GRnjjqShhIqiOXI9CqKM0gU/ZdNoqLPMNdB6NZgO3dl5ahyIHofBSp8AvQW # 3sCWJMy/IyUiga0wChSn9KbCF/GyvTEjmcb61wDjLS+Ib1vW78cxVIfhlG2N8TrJ # r/RiIANktqP0gQF2JfLjizx/6zM/NkELTCv47VfnrNOrhNUqXd7l7D0Gaeorr8Fs # 0iKgGtqipPFGZltJadcw1wLsS/X3KCfyNVhfCgnfxh2s1bFw # SIG # End signature block ================================================ FILE: source/internal/functions/Set-DatabaseForIntegrationTesting.ps1 ================================================ <# This function is intended for use in integration testing. It ensures the test database exists and the test instnace. #> function Set-DatabaseForIntegrationTesting { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "","","", "Because it isnt changing state")] [CmdletBinding()] Param ( [DbaInstanceParameter]$SqlInstance, [string]$DatabaseName ) process { $db = Get-DbaDatabase -SqlInstance $SqlInstance -SqlCredential $sqlcredential -Database $DatabaseName if ($null -eq $db) { $server = Connect-DbaInstance -SqlInstance $SqlInstance -SqlCredential $sqlcredential $server.Query("create database $DatabaseName") } } } # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUVx8312WVatpbP6qmSPrmczJE # YBSgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBSqZPDeycfmaU1pmTFrR9wMZByj # TDANBgkqhkiG9w0BAQEFAASCAQBewugm6AxORbDvnmu8sHo73nALzeKBC9fKTzpG # OaetYx4817nult50n/0epInKoJqayH5elLf7d16LsmuINLm6TigdE9ZS/kfd86ve # XfVAsPdCY/9zmli2hS7tbwFawUKobHO1qnV+7ZtMi86FAIHun4mwujRtSO+2FFEp # aNuyB3kPnfJ9PivF+ypJdcv8PrKQU6g1B111tKiKASnrXBusmQYeOB+iRy0mJxRa # srUVDc9UNMxwjlCatSRK+NDWB9T/EcnXzCNNZe5ldOjvZ76u4HIzcH1v4ZND9Lz1 # R9g4c0+yznMKyFFl8UkWiDIjOTsutX/XSKMasPk6jYkIQ3un # SIG # End signature block ================================================ FILE: source/internal/scripts/postimport.ps1 ================================================ # Add all things you want to run after importing the main code # Load Configurations foreach ($file in (Get-ChildItem "$ModuleRoot\internal\configurations\*.ps1")) { . Import-ModuleFile -Path $file.FullName } $script:__dbcconfig = Get-DbcConfig # load app stuff and create files if needed $script:localapp = ($__dbcconfig | Where-Object {$_.Name -eq 'app.localapp' }).Value $script:maildirectory = ($__dbcconfig | Where-Object {$_.Name -eq 'app.maildirectory' }).Value if (-not (Test-Path -Path $script:localapp)) { New-Item -ItemType Directory -Path $script:localapp } if (-not (Test-Path -Path $script:maildirectory)) { New-Item -ItemType Directory -Path $script:maildirectory } # Parse repo for tags and descriptions then write json try{ New-Json } catch{ Write-Warning "Failed creating JSON" $errmessage = $_ | Select-Object * | Out-String Write-Warning "Error message is $errmessage" } # Load Tab Expansion foreach ($file in (Get-ChildItem "$ModuleRoot\internal\tepp\*.ps1")) { . Import-ModuleFile -Path $file.FullName } # Importing PSDefaultParameterValues $PSDefaultParameterValues = $global:PSDefaultParameterValues # Set default param values if it exists if ($credential = (Get-DbcConfigValue -Name app.sqlcredential1)) { if ($PSDefaultParameterValues) { $newvalue = $PSDefaultParameterValues += @{ '*:SqlCredential' = $credential } Set-Variable -Scope 0 -Name PSDefaultParameterValues -Value $newvalue } else { Set-Variable -Scope 0 -Name PSDefaultParameterValues -Value @{ '*:SqlCredential' = $credential } } } # EnableException so that failed commands cause failures $PSDefaultParameterValues += @{ '*-Dba*:EnableException' = $true } # Fred magic # Set-PSFTaskEngineCache -Module dbachecks -Name module-imported -Value $true # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU0O3gDy6dPPYex5t5xuY0b+DK # BSWgggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRCHOFSpPFijfysrtOz3I7HnAD7 # ajANBgkqhkiG9w0BAQEFAASCAQAU38tJN2GnCUtaSGgkyrBTsoDuW0MwNhHt++6D # +NgE/4eIlSmI54/YmupgRcjWbV0U0Mmnjai1iNXN+aitCzGehsEDT/zSaOuuSbCk # L0/DTRrVZH5KI8pxcMhPga5f0IFaWUaocMF8E2RhZlcdhQX/hQFuWpTN6aqpGj+X # W0WORT50FxbLSKbAe0etZ2RI8oTac7nL+SC/d9JAHd54BECJDIes46V7p66HuUqx # 1UHwtycC/ThEDx9NA6p2NLuS7oXHrn1rXU0Kgeh8fcoMOrQrtbT4mlwzaIthi/MF # YE6E2iwPXPxOOrBo7yNT2hcSmok58HmzkwYjX3QcM/lhWQ/X # SIG # End signature block ================================================ FILE: source/internal/scripts/preimport.ps1 ================================================ # Add all things you want to run before importing the main code # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUhpH05OLZf7fOBcgMYy+o9FW/ # oBigggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRtJ+RpDowsgO7HzpQ+5t/284xQ # 2TANBgkqhkiG9w0BAQEFAASCAQAcIOV4CQUNCOoTass8B25sNqA/GEw03s4r4WBk # i7W+pn8bRJykLDC/QcxalWjjwfGSVqV5g06wxKjDxytdBtgmOHcPPrXvSqGwT3Fh # 9NdUDKqFtCMp9T3eBHzBzl1H5SOjQm1uwMwCaW/IMKmmoNOPm8Ilh5+PeTSb4rvD # gzWUuUUIpY3aXZEfuhrYbWI/tNVTRNzjc19L340NkhpsNg92FVqPMrUomf84IxMz # kdH5ea6mqUFfXT4w6YsMzQD7MbxWwEVllhfjHok+HWXwLfi8D+8gG+ZWux9hVUIy # cFLQuharHCIP18udOhO0CfERhNoRpxJ6lkKQl72vjnc2UEhd # SIG # End signature block ================================================ FILE: source/internal/tepp/autocomplete.ps1 ================================================ # Register that script block Register-PSFTeppScriptblock -Name SqlInstance -ScriptBlock { Get-PSFConfig -Module dbachecks -Name SqlInstance } Register-PSFTeppScriptblock -Name ComputerName -ScriptBlock { Get-PSFConfig -Module dbachecks -Name ComputerName } Register-PSFTeppScriptblock -Name confignames -ScriptBlock { (Get-PSFConfig -Module dbachecks).Name } Register-PSFTeppScriptblock -Name tags -ScriptBlock { Get-DbcTagCollection } Register-PSFTeppScriptblock -Name environments -ScriptBlock { "Production", "Development", "Test" } Register-PSFTeppScriptblock -Name policy.database.filegrowthtype -ScriptBlock { "kb", "percent" } # Register the actual auto completer Register-PSFTeppArgumentCompleter -Command Update-DbcPowerBiDataSource -Parameter Environment -Name environments Register-PSFTeppArgumentCompleter -Command Clear-DbcPowerBiDataSource -Parameter Environment -Name environments Register-PSFTeppArgumentCompleter -Command Invoke-DbcCheck -Parameter Check -Name tags Register-PSFTeppArgumentCompleter -Command Invoke-DbcCheck -Parameter ExcludeCheck -Name tags Register-PSFTeppArgumentCompleter -Command Get-DbcConfig -Parameter Name -Name confignames Register-PSFTeppArgumentCompleter -Command Get-DbcConfigValue -Parameter Name -Name confignames Register-PSFTeppArgumentCompleter -Command Set-DbcConfig -Parameter Name -Name confignames Register-PSFTeppArgumentCompleter -Command Get-DbcTagCollection -Parameter Name -Name tags Register-PSFTeppArgumentCompleter -Command Set-DbcConfig -Parameter Value -Name policy.database.filegrowthtype # SIG # Begin signature block # MIINEAYJKoZIhvcNAQcCoIINATCCDP0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUmbtyTr3u5UTJbgtJkFIVnHOd # mb2gggpSMIIFGjCCBAKgAwIBAgIQAsF1KHTVwoQxhSrYoGRpyjANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDUwOTAwMDAwMFoXDTIwMDUx # MzEyMDAwMFowVzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMQ8wDQYD # VQQHEwZWaWVubmExETAPBgNVBAoTCGRiYXRvb2xzMREwDwYDVQQDEwhkYmF0b29s # czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI8ng7JxnekL0AO4qQgt # Kr6p3q3SNOPh+SUZH+SyY8EA2I3wR7BMoT7rnZNolTwGjUXn7bRC6vISWg16N202 # 1RBWdTGW2rVPBVLF4HA46jle4hcpEVquXdj3yGYa99ko1w2FOWzLjKvtLqj4tzOh # K7wa/Gbmv0Si/FU6oOmctzYMI0QXtEG7lR1HsJT5kywwmgcjyuiN28iBIhT6man0 # Ib6xKDv40PblKq5c9AFVldXUGVeBJbLhcEAA1nSPSLGdc7j4J2SulGISYY7ocuX3 # tkv01te72Mv2KkqqpfkLEAQjXgtM0hlgwuc8/A4if+I0YtboCMkVQuwBpbR9/6ys # Z+sCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB0GA1UdDgQWBBRcxSkFqeA3vvHU0aq2mVpFRSOdmjAOBgNVHQ8BAf8EBAMCB4Aw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG # A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC # aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ # RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD # ggEBANuBGTbzCRhgG0Th09J0m/qDqohWMx6ZOFKhMoKl8f/l6IwyDrkG48JBkWOA # QYXNAzvp3Ro7aGCNJKRAOcIjNKYef/PFRfFQvMe07nQIj78G8x0q44ZpOVCp9uVj # sLmIvsmF1dcYhOWs9BOG/Zp9augJUtlYpo4JW+iuZHCqjhKzIc74rEEiZd0hSm8M # asshvBUSB9e8do/7RhaKezvlciDaFBQvg5s0fICsEhULBRhoyVOiUKUcemprPiTD # xh3buBLuN0bBayjWmOMlkG1Z6i8DUvWlPGz9jiBT3ONBqxXfghXLL6n8PhfppBhn # daPQO8+SqF5rqrlyBPmRRaTz2GQwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv # lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw # MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI # QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx # 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj # lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN # YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2 # DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9 # hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV # HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF # BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp # Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig # NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v # dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo # BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB # hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi # 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l # jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k # riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P # QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d # 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm # oecYpJpkUe8xggIoMIICJAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhACwXUo # dNXChDGFKtigZGnKMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBSZdMCXS/GsO4mPCImevge0EHeI # yDANBgkqhkiG9w0BAQEFAASCAQAQgWrbgGi5Tu8lxvEHYreKkqu6bjuwmWHfkXJw # QnFEpMUrO2YgLXSC0yJYpH7dlBcDGxTCtsPfqkpWuS5ZegCIWWtj5v9nMdb9ruxR # kI9SzjgBBiYVhb/IfQ2KFzkAiif29hkSDqO4tXOIQfVQ5vK/4YXKlNdpXUxZZlFk # fH/JfAXV86LiVmhKe5EhTy2tB44f06kLGyICG5ROsQhVbn2/cfC48BMnxqNAlxua # PR2Ph2Ript7e+OhzheTkGqNUnWMfRr+7P+aAq/mYbIoeHwy8O8aPlQ/aZR0tzSYP # MthFrtZVItplLT1hzOFoVZG90aI5E+6nmOgH8QjQwJZnaBs5 # SIG # End signature block ================================================ FILE: source/xml/dbachecks.Format.ps1xml ================================================  dbachecks.Check dbachecks.Check Group Type UniqueTag AllTags Config Description ================================================ FILE: tests/Project.Tests.ps1 ================================================ BeforeDiscovery { $script:ModuleName = 'dbachecks' $ModuleBase = (Get-Module -Name $ModuleName -ListAvailable).ModuleBase $commands = Get-Command -Module $ModuleName -CommandType Cmdlet, Function } Describe 'PSScriptAnalyzer rule-sets' -Tag Build , ScriptAnalyzer { BeforeDiscovery { $script:ModuleName = 'dbachecks' $ModuleBase = (Get-Module -Name $ModuleName -ListAvailable).ModuleBase $Rules = Get-ScriptAnalyzerRule $scripts = Get-ChildItem $ModuleBase -Include *.ps1, *.psm1, *.psd1 -Recurse | Where-Object fullname -NotMatch 'classes' # Get last commit that was merged from main $lastCommit = git log --grep="Updated Version Number and docs from master" -1 --format='%H' # Get the files that have been altered in since the last merge from master $scripts = git diff --name-only $lastCommit HEAD | Where-Object { $psitem.EndsWith('ps1') } # only the ones in these folders $scripts = $scripts | Where-Object { ($_ -like 'internal*') -or ($_ -like 'functions*') -or ( $_ -like 'checks*') } } Context 'Checking PSScriptAnalyzer on Script <_>' -ForEach $scripts { BeforeDiscovery { $PsScriptAnalyzerSettings = 'PSScriptAnalyzerSettings.psd1' $scriptpath = Join-Path -Path $ModuleBase -ChildPath $PsItem $Tests = $rules.ForEach{ @{ scriptpath = $scriptpath RuleName = $_.RuleName PsScriptAnalyzerSettings = $PsScriptAnalyzerSettings } } } It 'The Script Analyzer Rule <_.RuleName> Should not fail' -ForEach $Tests { $rulefailures = Invoke-ScriptAnalyzer -Path $PsItem.scriptpath -IncludeRule $PsItem.RuleName -Settings $PsItem.PsScriptAnalyzerSettings $message = ($rulefailures | Select-Object Message -Unique).Message $lines = $rulefailures.Line -join ',' $Because = 'Script Analyzer says the rules have been broken on lines {3} with Message {0} Check in VSCode Problems tab or Run Invoke-ScriptAnalyzer -Script {1} -Settings {2}' -f $message, $scriptpath, $PsScriptAnalyzerSettings, $lines $rulefailures.Count | Should -Be 0 -Because $Because } } } Describe 'Testing help for <_.Name>' -Tag Help -ForEach $commands { BeforeAll { $Help = Get-Help $PsItem.Name -ErrorAction SilentlyContinue } Context 'General help' { It 'Synopsis should not be auto-generated or empty' { $Because = 'We are good citizens and write good help' $Help.Synopsis | Should -Not -BeLike 'Short description*' -Because $Because $Help.Synopsis[0] | Should -Not -Match '\n' -Because $Because } It 'Description should not be auto-generated or empty' { $Because = 'We are good citizens and write good help' $Help.Description | Should -Not -BeLike '*Long description*' -Because $Because $Help.Description | Should -Not -BeNullOrEmpty -Because $Because } } Context 'Examples help' { It 'There should be more than one example' { $Because = 'Most commands should have more than one example to explain and we are good citizens and write good help' $Help.Examples.example.Count | Should -BeGreaterThan 1 -Because $Because } It 'There should be code for <_.title>' -ForEach $Help.Examples.Example { $Because = 'All examples should have code otherwise what is the point? and we are good citizens and write good help' $PsItem.Code | Should -Not -BeNullOrEmpty -Because $Because $PsItem.Code | Should -Not -BeLike '*An example*' -Because $Because } It 'There should be remarks for <_.title>' -ForEach $Help.Examples.Example { $Because = 'All examples should have explanations otherwise what is the point? and we are good citizens and write good help' $PsItem.remarks[0] | Should -Not -Be '@{Text=}' -Because $Because } } Context 'Parameters help' { It 'Parameter <_.name> should have help' -ForEach ($command.ParameterSets.Parameters | Where-Object Name -NotIn 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable', 'Confirm', 'WhatIf') { $Because = 'Every parameter should have help and we are good citizens and write good help' $_.Description.Text | Should -Not -BeNullOrEmpty -Because $Because $_.Description.Text | Should -Not -Be 'Parameter description' -Because $Because } } } ================================================ FILE: tests/QA/module.tests.ps1 ================================================ BeforeDiscovery { $script:moduleName = $ProjectName Remove-Module -Name $script:moduleName -Force -ErrorAction SilentlyContinue $mut = Get-Module -Name $script:moduleName -ListAvailable | Select-Object -First 1 | Import-Module -Force -ErrorAction Stop -PassThru } BeforeAll { $script:moduleName = $ProjectName # Convert-Path required for PS7 or Join-Path fails $projectPath = "$($PSScriptRoot)\..\.." | Convert-Path $sourcePath = ( Get-ChildItem -Path $projectPath\*\*.psd1 | Where-Object -FilterScript { ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) ` -and $( try { Test-ModuleManifest -Path $_.FullName -ErrorAction Stop } catch { $false } ) } ).Directory.FullName } Describe 'Changelog Management' -Tag 'Changelog' { It 'Changelog has been updated' -Skip:( -not ([bool](Get-Command git -ErrorAction SilentlyContinue) -and [bool](&(Get-Process -Id $PID).Path -NoProfile -Command 'git rev-parse --is-inside-work-tree 2>$null')) ) { # Get the list of changed files compared with branch main $headCommit = &git rev-parse HEAD $defaultBranchCommit = &git rev-parse origin/main $filesChanged = &git @('diff', "$defaultBranchCommit...$headCommit", '--name-only') $filesStagedAndUnstaged = &git @('diff', 'HEAD', '--name-only') $filesChanged += $filesStagedAndUnstaged # Only check if there are any changed files. if ($filesChanged) { $filesChanged | Should -Contain 'CHANGELOG.md' -Because 'the CHANGELOG.md must be updated with at least one entry in the Unreleased section for each PR' } } It 'Changelog format compliant with keepachangelog format' -Skip:(![bool](Get-Command git -EA SilentlyContinue)) { { Get-ChangelogData -Path (Join-Path $ProjectPath 'CHANGELOG.md') -ErrorAction Stop } | Should -Not -Throw } It 'Changelog should have an Unreleased header' -Skip:$skipTest { (Get-ChangelogData -Path (Join-Path -Path $ProjectPath -ChildPath 'CHANGELOG.md') -ErrorAction Stop).Unreleased.RawData | Should -Not -BeNullOrEmpty } } Describe 'General module control' -Tags 'FunctionalQuality' { It 'Should import without errors' { { Import-Module -Name $script:moduleName -Force -ErrorAction Stop } | Should -Not -Throw Get-Module -Name $script:moduleName | Should -Not -BeNullOrEmpty } It 'Should remove without error' { { Remove-Module -Name $script:moduleName -ErrorAction Stop } | Should -Not -Throw Get-Module $script:moduleName | Should -BeNullOrEmpty } } BeforeDiscovery { # Must use the imported module to build test cases. $allModuleFunctions = & $mut { Get-Command -Module $args[0] -CommandType Function } $script:moduleName # Build test cases. $testCases = @() foreach ($function in $allModuleFunctions) { $testCases += @{ Name = $function.Name } } } <# Describe 'Quality for module' -Tags 'TestQuality' { BeforeDiscovery { if (Get-Command -Name Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue) { $scriptAnalyzerRules = Get-ScriptAnalyzerRule } else { if ($ErrorActionPreference -ne 'Stop') { Write-Warning -Message 'ScriptAnalyzer not found!' } else { throw 'ScriptAnalyzer not found!' } } } It 'Should have a unit test for ' -ForEach $testCases { Get-ChildItem -Path 'tests\' -Recurse -Include "$Name.Tests.ps1" | Should -Not -BeNullOrEmpty } It 'Should pass Script Analyzer for ' -ForEach $testCases -Skip:(-not $scriptAnalyzerRules) { $functionFile = Get-ChildItem -Path $sourcePath -Recurse -Include "$Name.ps1" $pssaResult = (Invoke-ScriptAnalyzer -Path $functionFile.FullName) $report = $pssaResult | Format-Table -AutoSize | Out-String -Width 110 $pssaResult | Should -BeNullOrEmpty -Because ` "some rule triggered.`r`n`r`n $report" } } Describe 'Help for module' -Tags 'helpQuality' { It 'Should have .SYNOPSIS for ' -ForEach $testCases { $functionFile = Get-ChildItem -Path $sourcePath -Recurse -Include "$Name.ps1" $scriptFileRawContent = Get-Content -Raw -Path $functionFile.FullName $abstractSyntaxTree = [System.Management.Automation.Language.Parser]::ParseInput($scriptFileRawContent, [ref] $null, [ref] $null) $astSearchDelegate = { $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] } $parsedFunction = $abstractSyntaxTree.FindAll( $astSearchDelegate, $true ) | Where-Object -FilterScript { $_.Name -eq $Name } $functionHelp = $parsedFunction.GetHelpContent() $functionHelp.Synopsis | Should -Not -BeNullOrEmpty } It 'Should have a .DESCRIPTION with length greater than 40 characters for ' -ForEach $testCases { $functionFile = Get-ChildItem -Path $sourcePath -Recurse -Include "$Name.ps1" $scriptFileRawContent = Get-Content -Raw -Path $functionFile.FullName $abstractSyntaxTree = [System.Management.Automation.Language.Parser]::ParseInput($scriptFileRawContent, [ref] $null, [ref] $null) $astSearchDelegate = { $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] } $parsedFunction = $abstractSyntaxTree.FindAll($astSearchDelegate, $true) | Where-Object -FilterScript { $_.Name -eq $Name } $functionHelp = $parsedFunction.GetHelpContent() $functionHelp.Description.Length | Should -BeGreaterThan 40 } It 'Should have at least one (1) example for ' -ForEach $testCases { $functionFile = Get-ChildItem -Path $sourcePath -Recurse -Include "$Name.ps1" $scriptFileRawContent = Get-Content -Raw -Path $functionFile.FullName $abstractSyntaxTree = [System.Management.Automation.Language.Parser]::ParseInput($scriptFileRawContent, [ref] $null, [ref] $null) $astSearchDelegate = { $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] } $parsedFunction = $abstractSyntaxTree.FindAll( $astSearchDelegate, $true ) | Where-Object -FilterScript { $_.Name -eq $Name } $functionHelp = $parsedFunction.GetHelpContent() $functionHelp.Examples.Count | Should -BeGreaterThan 0 $functionHelp.Examples[0] | Should -Match ([regex]::Escape($function.Name)) $functionHelp.Examples[0].Length | Should -BeGreaterThan ($function.Name.Length + 10) } It 'Should have described all parameters for ' -ForEach $testCases { $functionFile = Get-ChildItem -Path $sourcePath -Recurse -Include "$Name.ps1" $scriptFileRawContent = Get-Content -Raw -Path $functionFile.FullName $abstractSyntaxTree = [System.Management.Automation.Language.Parser]::ParseInput($scriptFileRawContent, [ref] $null, [ref] $null) $astSearchDelegate = { $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] } $parsedFunction = $abstractSyntaxTree.FindAll( $astSearchDelegate, $true ) | Where-Object -FilterScript { $_.Name -eq $Name } $functionHelp = $parsedFunction.GetHelpContent() $parameters = $parsedFunction.Body.ParamBlock.Parameters.Name.VariablePath.ForEach({ $_.ToString() }) foreach ($parameter in $parameters) { $functionHelp.Parameters.($parameter.ToUpper()) | Should -Not -BeNullOrEmpty -Because ('the parameter {0} must have a description' -f $parameter) $functionHelp.Parameters.($parameter.ToUpper()).Length | Should -BeGreaterThan 25 -Because ('the parameter {0} must have descriptive description' -f $parameter) } } } #> ================================================ FILE: tests/Unit/Private/Get-PrivateFunction.tests.ps1 ================================================ <# $ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path $ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and $(try { Test-ModuleManifest $_.FullName -ErrorAction Stop } catch { $false } ) }).BaseName Import-Module $ProjectName InModuleScope $ProjectName { Describe Get-PrivateFunction { Context 'Default' { BeforeEach { $return = Get-PrivateFunction -PrivateData 'string' } It 'Returns a single object' { ($return | Measure-Object).Count | Should -Be 1 } It 'Returns a string based on the parameter PrivateData' { $return | Should -Be 'string' } } } } #> ================================================ FILE: tests/Unit/Public/Export-DbcConfig.Tests.ps1 ================================================  Describe "Export-DbcConfig Unit Tests" -Tags "IntegrationTests" { Context "Command executes properly and returns proper info" { BeforeAll { $localapp = Get-DbcConfigValue -Name 'app.localapp' Remove-Item "$localapp\config.json" -ErrorAction SilentlyContinue Export-DbcConfig -Path 'TestDrive:\config.json' } AfterAll { Remove-Item "$localapp\config.json" -ErrorAction SilentlyContinue } It "Should not throw" { { Export-DbcConfig } | Should -Not -Throw } It "outputs default file without errors" { (Get-ChildItem "$localapp\config.json" -ErrorAction SilentlyContinue) -ne $null | Should -BeTrue } It "outputs a named file without errors" { Test-Path 'TestDrive:\config.json' | Should -BeTrue } It "outputs an object" { $o = Export-DbcConfig -Force $o | Get-Member -Name Open | Should -Not -BeNullOrEmpty } } } ================================================ FILE: tests/Unit/Public/Get-Something.tests.ps1 ================================================ <# $ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path $ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{ ($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and $(try { Test-ModuleManifest $_.FullName -ErrorAction Stop } catch { $false } ) }).BaseName Import-Module $ProjectName InModuleScope $ProjectName { Describe Get-Something { Mock Get-PrivateFunction { $PrivateData } Context 'Return values' { BeforeEach { $return = Get-Something -Data 'value' } It 'Returns a single object' { ($return | Measure-Object).Count | Should -Be 1 } It 'Returns a string from Get-PrivateFunction' { Assert-MockCalled Get-PrivateFunction -Times 1 -Exactly -Scope It $return | Should -Be 'value' } } Context 'Pipeline' { It 'Accepts values from the pipeline by value' { $return = 'value1', 'value2' | Get-Something Assert-MockCalled Get-PrivateFunction -Times 2 -Exactly -Scope It $return[0] | Should -Be 'value1' $return[1] | Should -Be 'value2' } It 'Accepts value from the pipeline by property name' { $return = 'value1', 'value2' | ForEach-Object { [PSCustomObject]@{ Data = $_ OtherProperty = 'other' } } | Get-Something Assert-MockCalled Get-PrivateFunction -Times 2 -Exactly -Scope It $return[0] | Should -Be 'value1' $return[1] | Should -Be 'value2' } } Context 'ShouldProcess' { It 'Supports WhatIf' { (Get-Command Get-Something).Parameters.ContainsKey('WhatIf') | Should -Be $true { Get-Something -Data 'value' -WhatIf } | Should -Not -Throw } It 'Does not call Get-PrivateFunction if WhatIf is set' { $return = Get-Something -Data 'value' -WhatIf $return | Should -BeNullOrEmpty Assert-MockCalled Get-PrivateFunction -Times 0 -Scope It } } } } #> ================================================ FILE: tests/Unit.Tests.ps1 ================================================ # This should stop people making breaking changes to the tests without first altering the test BeforeDiscovery { Remove-Module dbachecks -Force -ErrorAction SilentlyContinue Import-Module dbachecks $ModuleBase = (Get-Module dbachecks).ModuleBase $v4Groups = (Get-ChildItem $ModuleBase\checks).Where{ $PSItem.Name -notlike '*v5*' } } Describe "Group <_.Name.Replace('.Tests.ps1','')> that each v4 dbachecks Pester test is correctly formatted for Power Bi and Coded correctly" -Tags UnitTest -ForEach $v4Groups { BeforeDiscovery { $tokens = $null $errors = $null $GroupName = $Psitem.Name -replace '.Tests.ps1', '' $GroupContent = Get-Content $Psitem.FullName -Raw $v4Describes = [Management.Automation.Language.Parser]::ParseInput($GroupContent, [ref]$tokens, [ref]$errors). FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast.CommandElements -and $ast.CommandElements[0].Value -eq 'describe' }, $true) | ForEach-Object { $CE = $PSItem.CommandElements $secondString = ($CE | Where-Object { $PSItem.StaticType.name -eq 'string' })[1] $tagIdx = $CE.IndexOf(($CE | Where-Object ParameterName -EQ 'Tags')) + 1 $tags = if ($tagIdx -and $tagIdx -lt $CE.Count) { $CE[$tagIdx].Extent } New-Object PSCustomObject -Property @{ GroupName = $GroupName CheckTitle = $secondString CheckTags = $tags Extent = $secondString.Parent.Extent.Text } } ## Find the Contexts $tokens = $null $errors = $null $v4Contexts = [Management.Automation.Language.Parser]::ParseInput($GroupContent, [ref]$tokens, [ref]$errors). FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast.CommandElements -and $ast.CommandElements[0].Value -eq 'Context' }, $true) | ForEach-Object { $CE = $PSItem.CommandElements $secondString = ($CE | Where-Object { $PSItem.StaticType.name -eq 'string' })[1] New-Object PSCustomObject -Property @{ GroupName = $GroupName Name = $secondString } } ## Find the Its $tokens = $null $errors = $null $v4Its = [Management.Automation.Language.Parser]::ParseInput($GroupContent, [ref]$tokens, [ref]$errors). FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast.CommandElements -and $ast.CommandElements[0].Value -eq 'It' }, $true) | ForEach-Object { $CE = $PSItem.CommandElements $secondString = ($CE | Where-Object { $PSItem.StaticType.name -eq 'string' })[1] New-Object PSCustomObject -Property @{ GroupName = $GroupName Name = $secondString } } ## This just grabs all the code $AST = [System.Management.Automation.Language.Parser]::ParseInput($GroupContent, [ref]$null, [ref]$null) $v4Code = New-Object PSCustomObject -Property @{ GroupName = $GroupName Statement = $AST.EndBlock.statements.Extent.Where{ $PSItem.StartLineNumber -ne 1 }.Where{ $PSItem.Text -match 'Describe' } ## Ignore the filename line and only if the title contains a describe } } BeforeAll { $UniqueTags = (Get-DbcCheck).UniqueTag } Context "Validating the group $GroupName - Check's Describes titles and tags" -ForEach $v4Describes { BeforeDiscovery { $CheckTitle = $PsItem.CheckTitle.Value $CheckTagsList = $PSItem.CheckTags.Text.Split(',').Trim().Where{ ($PSItem -ne '$filename') -and ($PSItem -notlike '*statistics*') -and ($PSItem -notlike '*BackupPathAccess*') -and ($PSItem -notlike '*OlaJobs*') -and ($PSItem -notlike '*status*') -and ($PSItem -notlike '*exists') -and ($PSItem -notlike '*Ops') } } It "The Describe Title - <_.CheckTitle.Value> - Should Use a double quote after the Describe" { $PSItem.CheckTitle.StringConstantType | Should -Be 'DoubleQuoted' -Because 'You need to alter the title of the Describe - We need use double quotes for titles' } It "The Describe Title - <_.CheckTitle.Value> - should use a plural for tags" { $PSItem.CheckTags | Should -Not -BeNullOrEmpty -Because 'You need to alter the tags parameter of the Describe - We use the plural of Tags' } It "The Describe Title - $CheckTitle - Tags parameter <_> should be Singular" -ForEach $CheckTagsList { $PSItem.ToString().Endswith('s') | Should -BeFalse -Because 'You need to alter the tags for this Describe OR alter this test if the tag makes sense - Our coding standards say tags should be singular' } It "The Describe Title - $CheckTitle - The first Tag <_> should be in the unique Tags returned from Get-DbcCheck" -ForEach $CheckTagsList[0].Where{ $PsItem -notin ('Low', 'High', 'Storage', 'DISA') } { $UniqueTags | Should -Contain $Psitem -Because 'We need a unique tag for each test - Format should be -Tags space UniqueTag comma - Also if you are running this on a machine where dbachecks has already been imported previously try running reset-dbcconfig, which will create a new checks.json for Get-DbcCheck' } It "The Describe Title - <_.CheckTitle.Value> - should reference the global exclude configuration" -ForEach $Psitem.Where{ $Psitem.GroupName -eq 'Database' } { $psitem.Extent -like "*`$ExcludedDatabases*" | Should -BeTrue -Because 'We need to exclude the databases specified in the config command.invokedbccheck.excludedatabases' } } Context "Validating the group $GroupName - Checking Contexts" { It "The Context Title - <_.Name> - Should end with `$PSItem (or `$clustername) So that the PowerBi will work correctly" -ForEach $v4Contexts { $PSItem.Name.ToString().Endswith('psitem"') -or $PSItem.Name.ToString().Endswith('clustername"') -or $PSItem.Name.ToString().Endswith('SqlInstance"') | Should -BeTrue -Because 'You need to alter the title of the Context - This helps the PowerBi to parse the data' } } Context "Validating the group $GroupName - Checking Its" { It "The It - <_.Name> - Should end with the right ending so that the PowerBi will work correctly" -ForEach $v4its { $Lower = $PSItem.Name.ToString().ToLower() $Lower.Endswith('psitem"') -or $Lower.Endswith('clustername"') -or $Lower.EndsWith('server)"') -or $Lower.EndsWith('name)"') -or $Lower.EndsWith('name"') -or $Lower.EndsWith('instance"') -or $Lower.EndsWith('instance)"') -or $Lower.EndsWith('domain)"') -or $Lower.EndsWith('domain"') -or $Lower.EndsWith('replica)"') | Should -BeTrue -Because 'You need to alter the title of the It, it should end with the instance name or computername - This helps the PowerBi to parse the data' } It "The Database It - <_.Name> - Should begin with - Database" -ForEach $v4its.Where{ $Psitem.GroupName -eq 'Database' } { $PSItem.Name.ToString().StartsWith('"Database') -or $PSItem.Name.ToString().StartsWith('"Can') | Should -BeTrue -Because 'You need to alter the It Title to start with Database (or Can t Connect) - For the database checks we can parse them and make magic' } } Context "Validating the group $GroupName - Checking Code Quality" -ForEach $v4Code { It "Should Use Get-Instance or Get-ComputerName" -ForEach $psitem.Statement { ($PSItem.text -Match 'Get-Instance') -or ($PSItem.text -match 'Get-ComputerName') -or ($PSItem.text -match 'clustervm' ) | Should -BeTrue -Because 'These are the commands to use to get Instances or Computers or clusters' } It "Should use the ForEach Method" -ForEach $psitem.Where{ $PsItem.GroupName -notlike '*HADR*' }.Statement { ($PSItem.text -match 'Get-Instance\).ForEach{' ) -or ($Psitem.text -match 'Get-ComputerName\).ForEach{' ) | Should -BeTrue # use the \ to escape the ) -Because 'We use the ForEach method in our coding standards' } It "Should not use `$_" -ForEach $psitem.Statement { ($PSItem.text -match '$_' ) | Should -BeFalse -Because '¬$psitem is the correct one to use' } It "Should Contain a Context Block" -ForEach ($psitem.Where{ $PsItem.GroupName -ne 'Agent' }.Statement) { $PSItem.text -match 'Context' | Should -BeTrue -Because 'This helps the Power BI' } It "Agent Should Contain a Context Block" -ForEach ($psitem.Where{ $PsItem.GroupName -eq 'Agent' }.Statement) { $PSItem.text -match 'Context' | Should -BeTrue -Because 'This helps the Power BI' } } } Describe 'Each Config referenced in a check should exist' -Tags UnitTest { BeforeDiscovery { $dbcCheck = Get-DbcCheck } BeforeAll { $dbcConfig = Get-DbcConfig } It "Config Value <_> Should exist in Get-DbcConfig" -ForEach ($dbcCheck.Config.Split(' ') | Sort-Object -Unique).Where{ $Psitem -ne '' } { $Psitem | Should -BeIn $dbcConfig.Name -Because 'You need to look at the configurations as there appears to not be a unique tag' } } <# Describe 'Checking that each dbachecks Pester test is correctly formatted for Power Bi and Coded correctly' -Tags UnitTest { $Checks.ForEach{ $CheckName = $psitem.Name $Check = Get-Content $PSItem.FullName -Raw Context "$($PSItem.Name) - Checking Describes titles and tags" { $UniqueTags = (Get-DbcCheck).UniqueTag ## This gets all of the code with a describe $Describes = [Management.Automation.Language.Parser]::ParseInput($check, [ref]$tokens, [ref]$errors). FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast.CommandElements -and $ast.CommandElements[0].Value -eq 'describe' }, $true) | ForEach-Object { $CE = $PSItem.CommandElements $secondString = ($CE | Where-Object { $PSItem.StaticType.name -eq 'string' })[1] $tagIdx = $CE.IndexOf(($CE | Where-Object ParameterName -EQ 'Tags')) + 1 $tags = if ($tagIdx -and $tagIdx -lt $CE.Count) { $CE[$tagIdx].Extent } New-Object PSCustomObject -Property @{ Name = $secondString Tags = $tags } } @($describes).ForEach{ $title = $PSItem.Name.ToString().Trim('"').Trim('''') It "The Describe Title - $title - Should Use a double quote after the Describe" { $PSItem.Name.ToString().Startswith('"') | Should -BeTrue -Because 'You need to alter the title of the Describe - We need use double quotes for titles' $PSItem.Name.ToString().Endswith('"') | Should -BeTrue -Because 'You need to alter the title of the Describe - We need use double quotes for titles' } It "The Describe Title - $title - should use a plural for tags" { $PSItem.Tags | Should -Not -BeNullOrEmpty -Because 'You need to alter the tags parameter of the Describe - We use the plural of Tags' } # a simple test for no esses apart from statistics and Access!! if ($null -ne $PSItem.Tags) { $PSItem.Tags.Text.Split(',').Trim().Where{ ($PSItem -ne '$filename') -and ($PSItem -notlike '*statistics*') -and ($PSItem -notlike '*BackupPathAccess*') -and ($PSItem -notlike '*OlaJobs*') -and ($PSItem -notlike '*status*') -and ($PSItem -notlike '*exists') -and ($PSItem -notlike '*Ops') }.ForEach{ It "The Describe Title - $title - Tags parameter $PSItem should be Singular" { $PSItem.ToString().Endswith('s') | Should -BeFalse -Because 'You need to alter the tags for this Describe OR alter this test if the tag makes sense - Our coding standards say tags should be singular' } } It "The Describe Title - $title - The first Tag $($PSItem.Tags.Text.Split(',')[0]) should be in the unique Tags returned from Get-DbcCheck" { $UniqueTags | Should -Contain $PSItem.Tags.Text.Split(',')[0].ToString() -Because 'We need a unique tag for each test - Format should be -Tags space UniqueTag comma - Also if you are running this on a machine where dbachecks has already been imported previously try running reset-dbcconfig, which will create a new checks.json for Get-DbcCheck' } } else { It "The Describe Title - $title - You haven't used the Tags Parameter so we can't check the tags" { $false | Should -BeTrue -Because 'You need to alter the Describe - We use the Tags parameter' } } } } Context "$($PSItem.Name) - Checking Contexts" { ## Find the Contexts $Contexts = [Management.Automation.Language.Parser]::ParseInput($check, [ref]$tokens, [ref]$errors). FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast.CommandElements -and $ast.CommandElements[0].Value -eq 'Context' }, $true) | ForEach-Object { $CE = $PSItem.CommandElements $secondString = ($CE | Where-Object { $PSItem.StaticType.name -eq 'string' })[1] New-Object PSCustomObject -Property @{ Name = $secondString } } @($Contexts).ForEach{ $title = $PSItem.Name.ToString().Trim('"').Trim('''') It "The Context Title - $Title - Should end with `$PSItem (or `$clustername) So that the PowerBi will work correctly" { $PSItem.Name.ToString().Endswith('psitem"') -or $PSItem.Name.ToString().Endswith('clustername"') -or $PSItem.Name.ToString().Endswith('SqlInstance"') | Should -BeTrue -Because 'You need to alter the title of the Context - This helps the PowerBi to parse the data' } } } Context "$($PSItem.Name) - Checking the Its" { $CheckName = $psitem.Name ## Find the Its $Its = [Management.Automation.Language.Parser]::ParseInput($check, [ref]$tokens, [ref]$errors). FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast.CommandElements -and $ast.CommandElements[0].Value -eq 'It' }, $true) | ForEach-Object { $CE = $PSItem.CommandElements $secondString = ($CE | Where-Object { $PSItem.StaticType.name -eq 'string' })[1] New-Object PSCustomObject -Property @{ Name = $secondString } } @($Its).ForEach{ $title = $PSItem.Name.ToString().Trim('"').Trim('''') It "The It Title - $Title - Should end with the right ending so that the PowerBi will work correctly" { $Lower = $PSItem.Name.ToString().ToLower() $Lower.Endswith('psitem"') -or $Lower.Endswith('clustername"') -or $Lower.EndsWith('server)"') -or $Lower.EndsWith('name)"') -or $Lower.EndsWith('name"') -or $Lower.EndsWith('instance"') -or $Lower.EndsWith('instance)"') -or $Lower.EndsWith('domain)"') -or $Lower.EndsWith('domain"') -or $Lower.EndsWith('replica)"') | Should -BeTrue -Because 'You need to alter the title of the It, it should end with the instance name or computername - This helps the PowerBi to parse the data' } if ($CheckName -eq 'Database.Tests.ps1') { It "The It Title - $Title - Should begin with - Database" { $PSItem.Name.ToString().StartsWith('"Database') -or $PSItem.Name.ToString().StartsWith('"Can') | Should -BeTrue -Because 'You need to alter the It Title to start with Database (or Can t Connect) - For the database checks we can parse them and make magic' } } } } Context "$($PSItem.Name) - Checking Code" { $CheckName = $psitem.Name ## This just grabs all the code $AST = [System.Management.Automation.Language.Parser]::ParseInput($Check, [ref]$null, [ref]$null) $Statements = $AST.EndBlock.statements.Extent ## Ignore the filename line @($Statements.Where{ $PSItem.StartLineNumber -ne 1 }).ForEach{ # make sure we only regex if the title contains a describe if ($PSItem.Text -match 'Describe') { $title = [regex]::matches($PSItem.text, 'Describe(.*)-Tag').groups[1].value.Replace('"', '').Replace('''', '').trim() if ($title -ne 'Cluster $clustername Health using Node $clustervm') { It "Describe - $title - Should Use Get-Instance or Get-ComputerName" { ($PSItem.text -Match 'Get-Instance') -or ($PSItem.text -match 'Get-ComputerName') | Should -BeTrue -Because 'These are the commands to use to get Instances or Computers' } } if ($title -ne 'Cluster $clustername Health using Node $clustervm') { It "Describe - $title Should use the ForEach Method" { ($PSItem.text -match 'Get-Instance\).ForEach{' ) -or ($Psitem.text -match 'Get-ComputerName\).ForEach{' ) | Should -BeTrue # use the \ to escape the ) -Because 'We use the ForEach method in our coding standards' } } It "Describe - $title Should not use `$_" { ($PSItem.text -match '$_' ) | Should -BeFalse -Because '¬$psitem is the correct one to use' } if ($CheckName -ne 'Agent.Tests.ps1') { It "Describe - $title Should Contain a Context Block" { $PSItem.text -match 'Context' | Should -BeTrue -Because 'This helps the Power BI' } } else { $Contexts = [Management.Automation.Language.Parser]::ParseInput($check, [ref]$tokens, [ref]$errors). FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast.CommandElements -and $ast.CommandElements[0].Value -eq 'Context' }, $true) | ForEach-Object { $CE = $PSItem.CommandElements $secondString = ($CE | Where-Object { $PSItem.StaticType.name -eq 'string' })[1] New-Object PSCustomObject -Property @{ Name = $secondString } } It "$CheckName should have the right number of Context blocks as the AST doesnt parse how I like and I cant be bothered to fix it right now" { $Contexts.Count | Should -Be 27 -Because 'There should be 27 context blocks in the Agent checks file' } } } } } } (Get-DbcCheck).ForEach{ It 'Should have one Unique Tag for each check' { $psitem.UniqueTag.Count | Should -Be 1 -Because "You need to check that the tags for this check - We want to only have one Unique Tag per test and we got $($psitem.UniqueTag) instead" } } } Describe 'Checking that there is a description for each check' -Tags UnitTest { (Get-DbcCheck).ForEach{ It "$($psitem.UniqueTag) Should have a description in the DbcCheckDescriptions.json" { $psitem.description | Should -Not -BeNullOrEmpty -Because "We need a description in the .\internal\configurations\DbcCheckDescriptions.json for $($psitem.uniquetag) so that Get-DbcCheck shows it" } } } Describe 'Each Config referenced in a check should exist' -Tags UnitTest { $dbcConfig = (Get-DbcConfig).Name ((Get-DbcCheck).Config.Split(' ') | Sort-Object -Unique).Where{ $Psitem -ne '' }.ForEach{ It "Config Value $psitem Should exist in Get-DbcConfig" { $Psitem | Should -BeIn $dbcConfig -Because 'You need to look at the configurations as there appears to not be a unique tag' } } } Describe 'Database Tests Exclusions' { $DbChecks = (Get-ChildItem $ModuleBase\checks).Where{ $PSItem.Name -eq 'Database.Tests.ps1' } $Check = Get-Content $DbChecks.FullName -Raw $Describes = [Management.Automation.Language.Parser]::ParseInput($check, [ref]$tokens, [ref]$errors). FindAll([Func[Management.Automation.Language.Ast, bool]] { param ($ast) $ast.CommandElements -and $ast.CommandElements[0].Value -eq 'describe' }, $true) | ForEach-Object { $CE = $PSItem.CommandElements $secondString = ($CE | Where-Object { $PSItem.StaticType.name -eq 'string' })[1] [PSCustomObject] @{ Name = $secondString.Value Extent = $secondString.Parent.Extent.Text } } $Describes.ForEach{ It "$($Psitem.Name) should reference the global exclude configuration" { $psitem.Extent -like "*`$ExcludedDatabases*" | Should -BeTrue -Because 'We need to exclude the databases specified in the config command.invokedbccheck.excludedatabases' } } } $Describes.ForEach{ It "$($Psitem.Name) should reference the global exclude configuration" { $psitem.Extent -like "*`$ExcludedDatabases*" | Should -BeTrue -Because 'We need to exclude the databases specified in the config command.invokedbccheck.excludedatabases' } } #> ================================================ FILE: tests/readme.md ================================================ # Tests Folder ## Description This folder holds the Unit and integration tests for the dbachecks module ## assertions This holds the functions to be able to run the unit tests for the checks ## checks This holds the Pester Tests for the checks ## functions This holds the Pester Tests for the external adn internal functions ## This folder holds the generic tests for the module, the help, the script analyzer, the generic unit tests for the checks layout ================================================ FILE: xml/dbachecks.Format.ps1xml ================================================  dbachecks.Check dbachecks.Check Group Type UniqueTag AllTags Config Description