This is the single source for repository-wide PowerShell style and workflow conventions. It applies to every PowerShell file under public/, private/, tests/, and the repository scripts, regardless of which agent or contributor makes the change.
ABSOLUTE RULE: NEVER suggest or use backticks (`) for line continuation. Backticks are an anti-pattern in modern PowerShell development.
MODERN RULE: Do NOT use Mandatory = $true or similar boolean attribute assignments.
# CORRECT - Modern attribute syntax (no = $true)
param(
[Parameter(Mandatory)]
[string]$SqlInstance,
[Parameter(ValueFromPipeline)]
[object[]]$InputObject,
[switch]$EnableException
)
# WRONG - Outdated PSv2 syntax
param(
[Parameter(Mandatory = $true)]
[string]$SqlInstance
)Guidelines:
- Use
[Parameter(Mandatory)]not[Parameter(Mandatory = $true)] - Use
[switch]for boolean flags, not[bool]parameters - Avoid ParameterSets - use Test-Bound instead with useful error messages
- No extra line breaks between parameter declarations
CRITICAL RULE: dbatools must support PowerShell v3. NEVER use ::new() or other PowerShell v5+ syntax.
# CORRECT - PowerShell v3 compatible
$object = New-Object -TypeName System.Collections.Hashtable
# WRONG - PowerShell v5+ only
$object = [System.Collections.Hashtable]::new()- 1-2 parameters: Use direct parameter syntax
- 3+ parameters: Use splatted hashtables with
$splat<Purpose>naming
# CORRECT - 2 parameters, direct syntax
$database = Get-DbaDatabase -SqlInstance $instance -Name "master"
# CORRECT - 5 parameters, must use splat
$splatConnection = @{
SqlInstance = $instance
SqlCredential = $credential
Database = $dbName
EnableException = $true
Confirm = $false
}
$result = New-DbaDatabase @splatConnectionSupport SQL Server 2000 when feasible. Skip gracefully when feature requires SQL 2005+. Never be dismissive about users running old versions.
For detailed version patterns and examples, read .github/prompts/sql-version-support.md.
Quick reference:
- SQL 2000 = Version 8, SQL 2005 = Version 9, SQL 2012 = Version 11, etc.
- Use
Connect-DbaInstance -MinimumVersion 9for SQL 2005+ requirements - Use conditional logic when SQL 2000 support is straightforward
Default to SMO for object manipulation, scripting, and property access. Use T-SQL for system views, DMVs, stored procedures, and version-specific logic.
For detailed guidance and examples, read .github/prompts/smo-vs-tsql.md.
CRITICAL RULE: Output objects immediately to the pipeline. Never collect in ArrayList or array.
For detailed patterns, read .github/prompts/pipeline-output.md.
# CORRECT - Output immediately
foreach ($db in $server.Databases) {
[PSCustomObject]@{
ComputerName = $server.ComputerName
Database = $db.Name
}
}
# WRONG - Collecting results
$results = New-Object System.Collections.ArrayList
# ... add to results ...
$resultsABSOLUTE MANDATE: ALL COMMENTS MUST BE PRESERVED EXACTLY as they appear in the original code including:
- Development notes and temporary comments
- CI/CD system comments (especially AppVeyor)
- Do not delete anything that says
#$TestConfig.instance...or similar metadata
- Always use double quotes for strings (SQL Server module standard)
- Properly escape quotes when needed
# CORRECT
$database = "master"
$message = "Database `"$dbName`" created successfully"
# WRONG
$database = 'master'Format multi-line arrays with one value per line:
$expectedParameters = @(
"SqlInstance",
"SqlCredential",
"Database",
"EnableException"
)Use here-strings for multi-line strings instead of concatenation:
$query = @"
SELECT name, database_id
FROM sys.databases
WHERE name = 'master'
"@CRITICAL FORMATTING REQUIREMENT: ALL hashtable assignments must be perfectly aligned:
# REQUIRED FORMAT - Aligned = signs
$splatConnection = @{
SqlInstance = $instance
SqlCredential = $credential
Database = $dbName
EnableException = $true
}
# FORBIDDEN - Misaligned hashtables
$splat = @{
SqlInstance = $instance
Database = $db
}- Use
$splat<Purpose>for 3+ parameters (never plain$splat) - Create unique variable names across all scopes to prevent collisions
Prefer direct property comparison for simple filters. Use a script block only for complex boolean logic, unsupported operators, or nested property and method access.
$master = $databases | Where-Object Name -eq "master"
$systemDbs = $databases | Where-Object Name -in "master", "model", "msdb", "tempdb"
$hasParameters = (Get-Command $CommandName).Parameters.Values.Name | Where-Object { $PSItem -notin ("WhatIf", "Confirm") }- Apply OTBS (One True Brace Style) formatting to all code blocks
- No trailing spaces anywhere
- 4-space indentation for consistency
- Use singular nouns -
Get-DbaDatabase, notGet-DbaDatabases - Use approved verbs - Get, Set, New, Remove, Invoke, etc.
- Follow
<Verb>-Dba<Noun>pattern - Include Claude as author - List "the dbatools team + Claude" in .NOTES when creating commands
When adding a new command, register it in TWO places:
- dbatools.psd1 - In the
FunctionsToExportarray - dbatools.psm1 - In the explicit command export section
CRITICAL: Always include the (do ...) pattern in the commit message to limit CI test runs:
Get-DbaDatabase - Add support for filtering by recovery model
(do Get-DbaDatabase)
For multiple commands: (do *Login*) or (do *Backup*, *Restore*)
Do NOT put the (do ...) pattern in pull request titles. On a pull request, CI derives the tests to run from the files the branch changed, so the marker adds nothing and only makes the title hard to read. Keep the title plain and descriptive:
Sync-DbaAvailabilityGroup - Open one shared dedicated admin connection instead of three
ABSOLUTE RULE: Always squash and merge pull requests that target development.
Never use a merge commit or rebase merge when integrating a PR into development.
All commands should have proper .OUTPUTS documentation. Use the prompt at .github/prompts/typesncolumns.md to generate proper documentation.
When adding a -Pattern parameter, it MUST use regular expressions (regex), not SQL LIKE or PowerShell wildcards.
The dbatools.library version used by CI and local development is pinned in .github/dbatools-library-version.json - a single JSON file with version and notes fields. Never hardcode a library version or release URL in a workflow; change this file instead.
{
"version": "2026.8.2-preview-main-20260802114210",
"notes": "Version of dbatools.library to use for CI/CD and development"
}.github/scripts/install-dbatools-library.ps1 reads it and installs from PowerShell Gallery, falling back to GitHub releases at https://github.com/dataplat/dbatools.library/releases/download/v{version}/dbatools.library.zip. Preview versions (anything with a prerelease suffix) skip the Gallery and go straight to GitHub releases.
This pin is repo-wide, so verify the release exists before committing a change to it. It is consumed through install-dbatools-library.ps1 by gallery.yml, integration-tests.yml, integration-tests-external-table.yml, integration-tests-s3.yml, xplat-import.yml, and tests/appveyor.prep.ps1 (which the self-hosted Azure matrix runs). Pinning a preview build points all of these at that build; if the preview asset is later deleted, they all fail until the pin moves.
tests/ps3-smoke.ps1 is a deliberate exception: it reads the same file for a version, but skips installing entirely if any dbatools.library is already present, and otherwise downloads from the PowerShell Gallery rather than the GitHub release. A preview pin therefore does not reach it, since previews are not published to the Gallery.
For full details, read .github/DBATOOLS_LIBRARY_VERSION_MANAGEMENT.md.
tests/CLAUDE.md is the single source for ongoing test policy, including Pester structure, real-boundary behavioral and integration coverage, regression tests, instance selection, fixtures, cleanup, and assertions. Read it before changing command behavior or any test file.
Syntax and Style:
- No backticks for line continuation
- No
= $truein parameter attributes - No
::new()syntax (PowerShell v3 compatible) - Splats for 3+ parameters with
$splat<Purpose>naming - Hashtables perfectly aligned
- Double quotes for strings
- All comments preserved
dbatools Patterns:
- SMO used first, T-SQL only when appropriate
- Pipeline output emitted immediately
- No
-Detailed/-Simpleoutput mode switches - Command names use singular nouns
Command Registration (if adding new commands):
- Added to dbatools.psd1 FunctionsToExport
- Added to dbatools.psm1 Export-ModuleMember
- Author includes "the dbatools team + Claude"
- NEVER use backticks - Use splats for 3+ parameters
- NEVER use
= $truein attributes - Use[Parameter(Mandatory)] - NEVER use
::new()- UseNew-Objectfor PowerShell v3 - NEVER collect pipeline output - Emit objects immediately
- ALWAYS prefer SMO first - T-SQL only when needed
- ALWAYS align hashtables - Equals signs line up vertically
- ALWAYS preserve comments - Every comment stays exactly as written
- ALWAYS use double quotes - SQL Server module standard
- ALWAYS register new commands - Both dbatools.psd1 and dbatools.psm1