From f1e589fd2469877370a8a5997a34962fe722d3b8 Mon Sep 17 00:00:00 2001 From: Brian Lalonde Date: Sun, 6 Sep 2026 17:17:45 -0700 Subject: [PATCH] =?UTF-8?q?=EF=BB=BF=F0=9F=94=A5=20Remove=20Databaseline?= =?UTF-8?q?=20cmdlets?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Add-GitHubMetadata.ps1 | 539 ---------------------- Export-MermaidER.ps1 | 202 -------- Export-TableMerge.ps1 | 122 ----- Find-DatabaseValue.ps1 | 283 ------------ Find-DbColumn.ps1 | 150 ------ Find-DbIndexes.ps1 | 80 ---- Get-ConfigConnectionStringBuilders.ps1 | 40 -- Measure-DbColumn.ps1 | 374 --------------- Measure-DbColumnValues.ps1 | 72 --- Measure-DbTable.ps1 | 133 ------ New-DbProviderObject.ps1 | 108 ----- Repair-DatabaseConstraintNames.ps1 | 134 ------ Repair-DatabaseUntrustedConstraints.ps1 | 106 ----- Send-SqlReport.ps1 | 175 ------- Test-ConnectionString.ps1 | 87 ---- Use-DbInstance.ps1 | 23 - test/Add-GitHubMetadata.Tests.ps1 | 135 ------ test/Convert-ChocolateyToWinget.Tests.ps1 | 5 +- test/Export-DatabaseScripts.Tests.ps1 | 27 -- test/Export-MermaidER.Tests.ps1 | 52 --- test/Export-TableMerge.Tests.ps1 | 31 -- test/Find-DatabaseValue.Tests.ps1 | 44 -- test/Find-DbColumn.Tests.ps1 | 22 - test/Find-DbIndexes.Tests.ps1 | 22 - 24 files changed, 3 insertions(+), 2963 deletions(-) delete mode 100644 Add-GitHubMetadata.ps1 delete mode 100644 Export-MermaidER.ps1 delete mode 100644 Export-TableMerge.ps1 delete mode 100644 Find-DatabaseValue.ps1 delete mode 100644 Find-DbColumn.ps1 delete mode 100644 Find-DbIndexes.ps1 delete mode 100644 Get-ConfigConnectionStringBuilders.ps1 delete mode 100644 Measure-DbColumn.ps1 delete mode 100644 Measure-DbColumnValues.ps1 delete mode 100644 Measure-DbTable.ps1 delete mode 100644 New-DbProviderObject.ps1 delete mode 100644 Repair-DatabaseConstraintNames.ps1 delete mode 100644 Repair-DatabaseUntrustedConstraints.ps1 delete mode 100644 Send-SqlReport.ps1 delete mode 100644 Test-ConnectionString.ps1 delete mode 100644 Use-DbInstance.ps1 delete mode 100644 test/Add-GitHubMetadata.Tests.ps1 delete mode 100644 test/Export-DatabaseScripts.Tests.ps1 delete mode 100644 test/Export-MermaidER.Tests.ps1 delete mode 100644 test/Export-TableMerge.Tests.ps1 delete mode 100644 test/Find-DatabaseValue.Tests.ps1 delete mode 100644 test/Find-DbColumn.Tests.ps1 delete mode 100644 test/Find-DbIndexes.Tests.ps1 diff --git a/Add-GitHubMetadata.ps1 b/Add-GitHubMetadata.ps1 deleted file mode 100644 index 5e4dd295..00000000 --- a/Add-GitHubMetadata.ps1 +++ /dev/null @@ -1,539 +0,0 @@ -<# -.SYNOPSIS -Adds GitHub Linguist overrides to a repo's .gitattributes. - -.DESCRIPTION -There is a lot of metadata that should be added to a good repo. -This script simplifies adding much of that metadata. - -.FUNCTIONALITY -Git and GitHub - -.LINK -https://github.com/blog/2392-introducing-code-owners - -.LINK -https://github.com/github/linguist#overrides - -.LINK -https://github.com/blog/2111-issue-and-pull-request-templates - -.LINK -https://help.github.com/articles/setting-guidelines-for-repository-contributors/ - -.LINK -https://help.github.com/articles/adding-a-license-to-a-repository/ - -.LINK -http://editorconfig.org/ - -.LINK -https://github.com/brianary/ModernConveniences/ - -.LINK -https://github.com/brianary/Detextive/ - -.LINK -Get-VSCodeSetting.ps1 - -.LINK -Set-VSCodeSetting.ps1 - -.LINK -Measure-StandardDeviation.ps1 - -.LINK -Use-Command.ps1 - -.EXAMPLE -Add-GitHubMetadata.ps1 -DefaultOwner arthurd@example.com -DefaultUsesTabs - -Sets up the CODEOWNERS file and assigns a user, and sets the indent default. -#> - -#Requires -Version 3 -#Requires -Modules Detextive,ModernConveniences -using module Detextive -using module ModernConveniences -[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns','', -Justification='These plural nouns work with groups.')] -[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter','', -Justification='Parameters are not tracked accurately.')] -[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')][OutputType([void])] Param( -<# -Sets the code owner(s) by @username or email address to use when no more specific -code owners are provided. By default, any authors within a standard deviation of -the most commits will be included. -#> -[string[]] $DefaultOwner, -<# -Maps .gitattribute-style globbing syntax for file matching to @username or email -address of owners of any matching files. -#> -[hashtable] $Owners = @{}, -<# -A list of .gitattribute-style globbing syntax matches for files that should be -considered vendor code, for files not covered by the default behavior of -the default Linguist vendor code file glob patterns: -https://github.com/github/linguist/blob/master/lib/linguist/vendor.yml -#> -[string[]] $VendorCode = @('**/packages/**','**/lib/**'), -<# -A list of .gitattribute-style globbing syntax matches for files that should be -considered documentation, for files not covered by the default behavior of -the default Linguist documentation file glob patterns: -https://github.com/github/linguist/blob/master/lib/linguist/documentation.yml -#> -[string[]] $DocumentationCode, -<# -A list of .gitattribute-style globbing syntax matches for files that should be -considered generated code, for files not covered by the default behavior of -the default Linguist generated code file glob patterns and contents matching: -https://github.com/github/linguist/blob/master/lib/linguist/generated.rb -#> -[string[]] $GeneratedCode = @('"**/Service References/**"','"**/Web References/**"'), -<# -A Markdown string containing a template for creating issues. -https://github.com/blog/2111-issue-and-pull-request-templates -#> -[string] $IssueTemplate, -<# -A Markdown string containing a template for creating pull requests. -https://github.com/blog/2111-issue-and-pull-request-templates -#> -[string] $PullRequestTemplate, -<# -The file path or URL containing guidelines for contributors in Markdown format. -https://help.github.com/articles/setting-guidelines-for-repository-contributors/ -#> -[string] $ContributingFile, -<# -The file path or URL containing open source licensing for contributors in -Markdown format. -https://help.github.com/articles/adding-a-license-to-a-repository/ -#> -[string] $LicenseFile, -<# -If no EditorConfig file exists, a simple default charset for text files in the -repo. By default this is set to the system default, which is often terrible. -#> -[string] $DefaultCharset = $OutputEncoding.WebName, -<# -If no EditorConfig file exists, a simple default line endings value for text files -in the repo. By default this is set to the system default, which is recommended. -#> -[string] $DefaultLineEndings = $(switch([Environment]::NewLine){"`n"{'lf'}"`r"{'cr'}default{'crlf'}}), -<# -If no EditorConfig file exists, a simple default number of characters to indent -lines for spaces (soft tabs) and tab display (hard tabs) for text files in the -repo. -#> -[int] $DefaultIndentSize = 4, -<# -If no EditorConfig file exists, this switch indicates a simple default for text -files in the repo to use tabs. Otherwise, spaces will be used for indentation. -#> -[switch] $DefaultUsesTabs, -<# -If no EditorConfig file exists, this switch indicates a simple default for text -files in the repo to preserve trailing spaces. Otherwise, trailing spaces will -be trimmed. -#> -[switch] $DefaultKeepTrailingSpace, -<# -If no EditorConfig file exists, this switch indicates a simple default for text -files in the repo not to add a final line ending at the end. Otherwise, a final -line ending will be added automatically if it is missing. -#> -[switch] $DefaultNoFinalNewLine, -# Indicates warnings about new content should be skipped. -[switch] $NoWarnings, -# Configure VSCode settings to recommend relevant extensions based on repo content. -[Alias('Recommendations')][switch] $VsCodeExtensionRecommendations, -<# -Configure VSCode settings to disable the Prettier extension for Markdown files, -since Prettier's formatting settings are not configurable, and some break Markdown -for some interpreters (e.g. lower-casing footnote links is incompatible with GitHub Pages), -and some formatting choices may not be desirable or may conflict with organizational -standards. -#> -[Alias('DisablePrettierMarkdown','NoPrettierMarkdown')][switch] $VSCodeDisablePrettierForMarkdown, -# Configure settings for Dev Containers, used for Codespaces. -[Alias('Codespaces')][switch] $DevContainer, -# Disables adding or updating the CODEOWNERS file. -[switch] $NoOwners, -# Do not prompt to append Linguist settings. -[switch] $Force -) - -function Resolve-RepoPath -{ - [CmdletBinding()] Param([Parameter(ValueFromPipelineByPropertyName=$true)][Alias('FullName')][string] $Path) - Process { (Resolve-Path $Path -Relative) -replace '^.\\','' -replace '\\','/' } -} - -function Test-KeepFile -{ - [CmdletBinding(SupportsShouldProcess=$true)][OutputType([bool])] Param( - [Parameter(Position=0)][string] $Filename, - [switch] $Keep - ) - $exists = Test-Path $Filename -Type Leaf - if($exists -and $Keep) { Write-Verbose "Keeping existing $Filename"; return $true } - if(!$exists) { return $false } - Write-Verbose "$Filename exists" - return !$PSCmdlet.ShouldProcess($Filename,'overwrite') -} - -function Copy-GitHubFile -{ - [CmdletBinding()] Param( - [Parameter(Position=0,Mandatory=$true)][string] $Filename, - [Parameter(Position=1,Mandatory=$true)][Alias('Path','Url')][uri] $Source - ) - if(Test-KeepFile $Filename){return} - if($Source.IsFile){Copy-Item $Source.LocalPath $Filename} - else{Invoke-WebRequest $Source -OutFile $Filename} #TODO: authentication for private repos? -} - -function Add-GitHubDirectory -{ - if(!(Test-Path .github -PathType Container)) {mkdir .github |Out-Null} -} - -function Add-File -{ - [CmdletBinding()] Param( - [Parameter(Position=0,Mandatory=$true)][string] $Filename, - [Parameter(Position=1,Mandatory=$true)][string] $Contents, - [Parameter(Position=2)][ValidateSet('utf8','ASCII')][string] $Encoding = 'utf8', - [switch] $Warn, - [switch] $Keep, - [switch] $Force - ) - if($Keep -and (Test-Path $Filename -Type Leaf)) { return } - if(!$Contents){Write-Verbose "No contents to add to $Filename."; return } - if(!$Force -and (Test-KeepFile $Filename)){ Write-Verbose "File $Filename exists!"; return } - $Contents |Out-File $Filename -Encoding $Encoding - git add -N $Filename |Out-Null - if($Warn){ Write-Warning "The file $Filename has been added, be sure to review it and customize as needed." } - Write-Verbose "Added $Filename" -} - -function Add-Readme([string] $name = (git rev-parse --show-toplevel |Split-Path -Leaf), [switch] $NoWarnings) -{ - if(Test-Path README.md -PathType Leaf){return} - Add-File README.md @" -$name -$('='*$name.Length) - -TODO: Summarize purpose of repo contents here. - -Sections --------- - -TODO: Add sections for additional details, special instructions, prerequisites, &c. -"@ -Warn:$(!$NoWarnings) -} - -function Add-CodeOwners -{ - Param( - [string[]] $DefaultOwner, - [hashtable] $Owners, - [switch] $NoWarnings - ) - if(Test-KeepFile .github/CODEOWNERS -Keep:(!$DefaultOwner -and !$Owners)) - { - if(ModernConveniences\Test-FileTypeMagicNumber utf8 .github/CODEOWNERS){Remove-Utf8Signature .github/CODEOWNERS} - return - } - if(!$DefaultOwner) - { - Write-Verbose 'Determining default code owner(s).' - $authors = git shortlog -nes HEAD | - Select-String '^\s*(?\d+)\s+(?\b[^>]+\b)\s+<(?[^>]+)>$' | - ModernConveniences\Add-CapturesToMatches - $authors |Out-String |Write-Verbose - [int] $max = ($authors |Measure-Object Commits -Maximum).Maximum - [int] $oneSigmaFromTop = $max - ($authors.Commits |Measure-StandardDeviation.ps1) - Write-Verbose "Authors with $oneSigmaFromTop or more commits will be included as default code owners." - $DefaultOwner = $authors |Where-Object {[int] $_.Commits -ge $oneSigmaFromTop} |Select-Object -ExpandProperty Email - Write-Verbose "Default code owners determined to be $DefaultOwner." - } - $Local:OFS = [Environment]::NewLine - Add-File -Filename .github/CODEOWNERS -Contents @" - -# Code Owners file https://github.com/blog/2392-introducing-code-owners -# .gitattributes selection syntax mapping to GitHub @usernames or email addresses. - -# default owner(s) -* $DefaultOwner -$(if($Owners){"$OFS# targeted owners"}) -$($Owners.Keys |ForEach-Object {"$_ $($Owners[$_] -join ' ')"}) -"@ -Encoding ASCII -Warn:$(!$NoWarnings) -Force -} - -function Add-LinguistOverrides -{ - [CmdletBinding(SupportsShouldProcess=$true)] Param( - [string[]] $VendorCode, - [string[]] $DocumentationCode, - [string[]] $GeneratedCode, - [switch] $Force - ) - if(!(Test-Path .gitattributes -PathType Leaf)) - { - Write-Verbose 'Creating .gitattributes file.' - '','# Linguist overrides https://github.com/github/linguist#overrides' |Out-File .gitattributes ascii - } - else - { - if(ModernConveniences\Test-FileTypeMagicNumber utf8 .gitattributes){Remove-Utf8Signature .gitattributes} - if(Select-String '^# Linguist overrides' .gitattributes) - { - Select-String '^# Linguist overrides|\blinguist-\w+' .gitattributes |Out-String |Write-Verbose - if(!$Force -and !$PSCmdlet.ShouldContinue('.gitattributes','append Linguist overrides')) - { - Write-Verbose 'The .gitattributes file already contains a "Linguist overrides" section.' - return - } - } - else - { - '','# Linguist overrides https://github.com/github/linguist#overrides' |Add-Content .gitattributes -Encoding UTF8 - } - } - if($VendorCode) {$VendorCode |ForEach-Object {"$_ linguist-vendored"} |Add-Content .gitattributes -Encoding UTF8} - if($DocumentationCode) {$DocumentationCode |ForEach-Object {"$_ linguist-documentation"} |Add-Content .gitattributes -Encoding UTF8} - if($GeneratedCode) {$GeneratedCode |ForEach-Object {"$_ linguist-generated=true"} |Add-Content .gitattributes -Encoding UTF8} - #TODO: linguist-language entries? - git add -N .gitattributes |Out-Null - Write-Verbose 'Added Linguist overrides section to .gitattributes.' - Select-String '^# Linguist overrides|\blinguist-\w+' .gitattributes |Out-String |Write-Verbose -} - -function Add-IssueTemplate([string] $IssueTemplate) -{ - if(!$IssueTemplate){Write-Verbose 'No issue template.'; return} - Add-File .github/ISSUE_TEMPLATE.md $IssueTemplate -} - -function Add-PullRequestTemplate([string] $PullRequestTemplate) -{ - if(!$PullRequestTemplate){Write-Verbose 'No pull request template.'; return} - Add-File .github/PULL_REQUEST_TEMPLATE.md $PullRequestTemplate -} - -function Add-ContributingGuidelines([string] $ContributingFile) -{ - if(!$ContributingFile){Write-Verbose 'No contributing file.'; return} - Copy-GitHubFile .github/CONTRIBUTING.md $ContributingFile -} - -function Add-License([string] $LicenseFile) -{ - if(!$LicenseFile){Write-Verbose 'No license.'; return} - Copy-GitHubFile LICENSE.md $LicenseFile -} - -function Add-EditorConfig -{ - Param( - [string] $DefaultCharset, - [string] $DefaultLineEndings, - [int] $DefaultIndentSize, - [switch] $DefaultUsesTabs, - [switch] $DefaultKeepTrailingSpace, - [switch] $DefaultNoFinalNewLine, - [switch] $NoWarnings - ) - Add-File .editorconfig @" -# EditorConfig is awesome: http://EditorConfig.org - -# last word for the project -root = true - -# defaults -[*] -indent_style = $(if($DefaultUsesTabs){'tab'}else{'space'}) -indent_size = $DefaultIndentSize -tab_width = $DefaultIndentSize -end_of_line = $DefaultLineEndings -charset = $DefaultCharset -trim_trailing_whitespace = $(if($DefaultKeepTrailingSpace){'false'}else{'true'}) -insert_final_newline = $(if($DefaultNoFinalNewLine){'false'}else{'true'}) - -# git -[{.gitattributes,CODEOWNERS}] -charset = utf-8 - -# CSS -# https://www.w3.org/International/questions/qa-utf8-bom.en#bytheway -[*.css] -charset = utf-8 - -"@ -Warn:$(!$NoWarnings) -Keep -} - -function Add-VsCodeExtensionRecommendations -{ - if(!(Test-Path .vscode -PathType Container)) {mkdir .vscode |Out-Null} - $recommendations = New-Object Collections.Generic.HashSet[string] - [string[]] $previous = Get-VSCodeSetting.ps1 /recommendations -Workspace - if($previous) {$previous |ForEach-Object {[void]$recommendations.Add($_)}} - if((Test-Path .github -Type Container) -and (Test-Path .github/workflows -Type Container) -and - (Get-ChildItem .github/workflows -Filter *.yml |Select-Object -First 1)) - { - [void]$recommendations.Add('GitHub.vscode-github-actions') - } - [void]$recommendations.Add('yzhang.markdown-all-in-one') - [void]$recommendations.Add('EditorConfig.EditorConfig') - if(Get-ChildItem -Recurse -Filter *.md |Select-String '```mermaid' |Select-Object -First 1) - { - [void]$recommendations.Add('bierner.markdown-mermaid') - [void]$recommendations.Add('bpruitt-goddard.mermaid-markdown-syntax-highlighting') - } - if(Get-ChildItem -Recurse -Filter *.adoc |Select-Object -First 1) - { - [void]$recommendations.Add('asciidoctor.asciidoctor-vscode') - } - if(Get-ChildItem -Recurse -Filter *.http |Select-Object -First 1) - { - [void]$recommendations.Add('humao.rest-client') - } - if(Get-ChildItem -Recurse -Filter *.ps1 |Select-Object -First 1) - { - [void]$recommendations.Add('ms-vscode.powershell') - } - if(Get-ChildItem -Recurse -Filter *.sql |Select-Object -First 1) - { - [void]$recommendations.Add('ms-mssql.mssql') - } - Set-VSCodeSetting.ps1 /recommendations $recommendations -Workspace -} - -function Add-DevContainerSettings -{ - if(Test-Path .devcontainer/devcontainer.json -Type Leaf) - { - ${devcontainer.json} = '.devcontainer/devcontainer.json' - $settings = Get-Content ${devcontainer.json} |ConvertFrom-Json - } - elseif(Test-Path .devcontainer.json -Type Leaf) - { - ${devcontainer.json} = '.devcontainer.json' - $settings = Get-Content ${devcontainer.json} |ConvertFrom-Json - } - else - { - ${devcontainer.json} = '.devcontainer.json' - $settings = [pscustomobject]@{ - customizations = [pscustomobject]@{ - vscode = [pscustomobject]@{ - settings=[pscustomobject]@{} - extensions=@() - } - } - } - } - if(!$settings.PSObject.Properties.Match('customizations').Count) - { - $settings |Add-Member -NotePropertyName customizations -NotePropertyValue ([pscustomobject]@{ - vscode = @{ - settings=[pscustomobject]@{} - extensions=@() - } - }) - } - elseif(!$settings.customizations.PSObject.Properties.Match('vscode').Count) - { - $settings.customizations |Add-Member -NotePropertyName vscode -NotePropertyValue ([pscustomobject]@{ - settings=[pscustomobject]@{} - extensions=@() - }) - } - elseif(!$settings.customizations.vscode.PSObject.Properties.Match('extensions').Count) - { - $settings.customizations.vscode |Add-Member -NotePropertyName extensions -NotePropertyValue @() - } - $extensions = $settings.customizations.vscode.extensions -isnot [array] ? - $settings.customizations.vscode.extensions : @() - if(Get-ChildItem .github/workflows -Filter *.yml |Select-Object -First 1) - { - $extensions += 'GitHub.vscode-github-actions' - } - if(Get-ChildItem -Recurse -Filter *.md |Select-Object -First 1) - { - $extensions += 'DavidAnson.vscode-markdownlint' - } - if(Get-ChildItem -Recurse -Filter *.md |Select-String '```mermaid' |Select-Object -First 1) - { - $extensions += 'bierner.markdown-mermaid' - $extensions += 'bpruitt-goddard.mermaid-markdown-syntax-highlighting' - } - if(Get-ChildItem -Recurse -Filter *.adoc |Select-Object -First 1) - { - $extensions += 'asciidoctor.asciidoctor-vscode' - } - $settings.customizations.vscode.extensions = @($extensions |Select-Object -Unique) - $settings |ConvertTo-Json -Depth 5 |Out-File ${devcontainer.json} utf8 -} - -function Disable-VsCodePrettier -{ - if(!(Test-Path .vscode -PathType Container)) {mkdir .vscode |Out-Null} - Set-VSCodeSetting.ps1 /prettier.disableLanguages @('markdown') -Workspace - Set-VSCodeSetting.ps1 '/[markdown]' @{ - 'editor.defaultFormatter' = 'yzhang.markdown-all-in-one' - } -Workspace -} - -function Add-Metadata -{ - Param( - [string[]] $DefaultOwner, - [hashtable] $Owners, - [string[]] $VendorCode, - [string[]] $DocumentationCode, - [string[]] $GeneratedCode, - [string] $IssueTemplate, - [string] $PullRequestTemplate, - [string] $ContributingFile, - [string] $LicenseFile, - [string] $DefaultCharset, - [string] $DefaultLineEndings, - [int] $DefaultIndentSize, - [switch] $DefaultUsesTabs, - [switch] $DefaultKeepTrailingSpace, - [switch] $DefaultNoFinalNewLine, - [switch] $NoWarnings, - [switch] $Force - ) - Use-Command.ps1 git "$env:ProgramFiles\Git\cmd\git.exe" -choco git - Push-Location $(git rev-parse --show-toplevel) - Add-GitHubDirectory - Add-Readme -NoWarnings:$NoWarnings - if(!$NoOwners) {Add-CodeOwners -DefaultOwner $DefaultOwner -Owners $Owners -NoWarnings:$NoWarnings} - Add-LinguistOverrides -VendorCode $VendorCode -DocumentationCode $DocumentationCode ` - -GeneratedCode $GeneratedCode -Force:$Force - Add-IssueTemplate -IssueTemplate $IssueTemplate - Add-PullRequestTemplate -PullRequestTemplate $PullRequestTemplate - Add-ContributingGuidelines -ContributingFile $ContributingFile - Add-License -LicenseFile $LicenseFile - Add-EditorConfig -DefaultCharset $DefaultCharset -DefaultLineEndings $DefaultLineEndings ` - -DefaultIndentSize $DefaultIndentSize -DefaultUsesTabs:$DefaultUsesTabs ` - -DefaultKeepTrailingSpace:$DefaultKeepTrailingSpace -DefaultNoFinalNewLine:$DefaultNoFinalNewLine ` - -NoWarnings:$NoWarnings - if($VsCodeExtensionRecommendations) {Add-VsCodeExtensionRecommendations} - if($VSCodeDisablePrettierForMarkdown) {Disable-VsCodePrettier} - if($DevContainer) {Add-DevContainerSettings} - Pop-Location -} - -Add-Metadata -DefaultOwner $DefaultOwner -Owners $Owners -VendorCode $VendorCode ` - -DocumentationCode $DocumentationCode -GeneratedCode $GeneratedCode -IssueTemplate $IssueTemplate ` - -PullRequestTemplate $PullRequestTemplate -ContributingFile $ContributingFile -LicenseFile $LicenseFile ` - -DefaultCharset $DefaultCharset -DefaultLineEndings $DefaultLineEndings -DefaultIndentSize $DefaultIndentSize ` - -DefaultUsesTabs:$DefaultUsesTabs -DefaultKeepTrailingSpace:$DefaultKeepTrailingSpace ` - -DefaultNoFinalNewLine:$DefaultNoFinalNewLine -NoWarnings:$NoWarnings -Force:$Force diff --git a/Export-MermaidER.ps1 b/Export-MermaidER.ps1 deleted file mode 100644 index 3d85b493..00000000 --- a/Export-MermaidER.ps1 +++ /dev/null @@ -1,202 +0,0 @@ -<# -.SYNOPSIS -Generates a Mermaid entity relation diagram for database tables. - -.FUNCTIONALITY -Mermaid Diagrams - -.NOTES -All tables in the pipeline must exist in the same database. - -.LINK -https://mermaid.js.org/syntax/entityRelationshipDiagram.html - -.LINK -https://learn.microsoft.com/dotnet/api/table - -.LINK -https://dbatools.io/ - -.EXAMPLE -Get-DbaDbTable -SqlInstance '(localdb)\ProjectsV13' -Database AdventureWorks2016 -Table Production.Product |Export-MermaidER.ps1 - -erDiagram -Product { - int ProductID PK "identity(1,1); Primary key for Product records." - Name Name "Name of the product." - nvarchar ProductNumber "Unique product identification number." - Flag MakeFlag "0 = Product is purchased, 1 = Product is manufactured in-house." - Flag FinishedGoodsFlag "0 = Product is not a salable item. 1 = Product is salable." - nvarchar Color "nullable; Product color." - smallint SafetyStockLevel "Minimum inventory quantity. " - smallint ReorderPoint "Inventory level that triggers a purchase order or work order. " - money StandardCost "Standard cost of the product." - money ListPrice "Selling price." - nvarchar Size "nullable; Product size." - nchar SizeUnitMeasureCode FK "nullable; Unit of measure for Size column." - nchar WeightUnitMeasureCode FK "nullable; Unit of measure for Weight column." - decimal Weight "nullable; Product weight." - int DaysToManufacture "Number of days required to manufacture the product." - nchar ProductLine "nullable; R = Road, M = Mountain, T = Touring, S = Standard" - nchar Class "nullable; H = High, M = Medium, L = Low" - nchar Style "nullable; W = Womens, M = Mens, U = Universal" - int ProductSubcategoryID FK "nullable; Product is a member of this product subcategory. Foreign key to ProductSubCategory.ProductSubCategoryID. " - int ProductModelID FK "nullable; Product is a member of this product model. Foreign key to ProductModel.ProductModelID." - datetime SellStartDate "Date the product was available for sale." - datetime SellEndDate "nullable; Date the product was no longer available for sale." - datetime DiscontinuedDate "nullable; Date the product was discontinued." - uniqueidentifier rowguid "ROWGUIDCOL number uniquely identifying the record. Used to support a merge replication sample." - datetime ModifiedDate "Date and time the record was last updated." -} - -.EXAMPLE -Get-DbaDbTable -SqlInstance '(localdb)\ProjectsV13' -Database AdventureWorks2016 -Schema Purchasing |Export-MermaidER.ps1 - -erDiagram -ProductVendor { - int ProductID PK "Primary key. Foreign key to Product.ProductID." - int BusinessEntityID PK "Primary key. Foreign key to Vendor.BusinessEntityID." - int AverageLeadTime "The average span of time (in days) between placing an order with the vendor and receiving the purchased product." - money StandardPrice "The vendor's usual selling price." - money LastReceiptCost "nullable; The selling price when last purchased." - datetime LastReceiptDate "nullable; Date the product was last received by the vendor." - int MinOrderQty "The maximum quantity that should be ordered." - int MaxOrderQty "The minimum quantity that should be ordered." - int OnOrderQty "nullable; The quantity currently on order." - nchar UnitMeasureCode FK "The product's unit of measure." - datetime ModifiedDate "Date and time the record was last updated." -} -PurchaseOrderDetail { - int PurchaseOrderID PK "Primary key. Foreign key to PurchaseOrderHeader.PurchaseOrderID." - int PurchaseOrderDetailID PK "identity(1,1); Primary key. One line number per purchased product." - datetime DueDate "Date the product is expected to be received." - smallint OrderQty "Quantity ordered." - int ProductID FK "Product identification number. Foreign key to Product.ProductID." - money UnitPrice "Vendor's selling price of a single product." - money LineTotal "Per product subtotal. Computed as OrderQty * UnitPrice." - decimal ReceivedQty "Quantity actually received from the vendor." - decimal RejectedQty "Quantity rejected during inspection." - decimal StockedQty "Quantity accepted into inventory. Computed as ReceivedQty - RejectedQty." - datetime ModifiedDate "Date and time the record was last updated." -} -PurchaseOrderHeader { - int PurchaseOrderID PK "identity(1,1); Primary key." - tinyint RevisionNumber "Incremental number to track changes to the purchase order over time." - tinyint Status "Order current status. 1 = Pending; 2 = Approved; 3 = Rejected; 4 = Complete" - int EmployeeID FK "Employee who created the purchase order. Foreign key to Employee.BusinessEntityID." - int VendorID FK "Vendor with whom the purchase order is placed. Foreign key to Vendor.BusinessEntityID." - int ShipMethodID FK "Shipping method. Foreign key to ShipMethod.ShipMethodID." - datetime OrderDate "Purchase order creation date." - datetime ShipDate "nullable; Estimated shipment date from the vendor." - money SubTotal "Purchase order subtotal. Computed as SUM(PurchaseOrderDetail.LineTotal)for the appropriate PurchaseOrderID." - money TaxAmt "Tax amount." - money Freight "Shipping cost." - money TotalDue "Total due to vendor. Computed as Subtotal + TaxAmt + Freight." - datetime ModifiedDate "Date and time the record was last updated." -} -ShipMethod { - int ShipMethodID PK "identity(1,1); Primary key for ShipMethod records." - Name Name "Shipping company name." - money ShipBase "Minimum shipping charge." - money ShipRate "Shipping charge per pound." - uniqueidentifier rowguid "ROWGUIDCOL number uniquely identifying the record. Used to support a merge replication sample." - datetime ModifiedDate "Date and time the record was last updated." -} -Vendor { - int BusinessEntityID PK "Primary key for Vendor records. Foreign key to BusinessEntity.BusinessEntityID" - AccountNumber AccountNumber "Vendor account (identification) number." - Name Name "Company name." - tinyint CreditRating "1 = Superior, 2 = Excellent, 3 = Above average, 4 = Average, 5 = Below average" - Flag PreferredVendorStatus "0 = Do not use if another vendor is available. 1 = Preferred over other vendors supplying the same product." - Flag ActiveFlag "0 = Vendor no longer used. 1 = Vendor is actively used." - nvarchar PurchasingWebServiceURL "nullable; Vendor URL." - datetime ModifiedDate "Date and time the record was last updated." -} -ProductVendor }|--|| Vendor : "BusinessEntityID: Foreign key constraint referencing Vendor.BusinessEntityID." -PurchaseOrderDetail }|--|| PurchaseOrderHeader : "PurchaseOrderID: Foreign key constraint referencing PurchaseOrderHeader.PurchaseOrderID." -PurchaseOrderHeader }|--|| ShipMethod : "ShipMethodID: Foreign key constraint referencing ShipMethod.ShipMethodID." -PurchaseOrderHeader }|--|| Vendor : "VendorID: Foreign key constraint referencing Vendor.VendorID." -#> - -#Requires -Version 3 -using namespace Microsoft.SqlServer.Management.Smo -[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseProcessBlockForPipelineCommand','', -Justification='This script uses $input within an End block.')] -[CmdletBinding()][OutputType([string])] Param( -# An SMO table object to include in the diagram. -[Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$true)] -[Table] $Table -) -Begin -{ - Unicodery\Import-CharConstants NL - - filter Format-ColumnAsMermaid - { - Param( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)][DataType] $DataType, - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)][ExtendedPropertyCollection] $ExtendedProperties, - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)][string] $Name, - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)][bool] $InPrimaryKey, - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)][bool] $IsForeignKey, - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)][bool] $Nullable, - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)][bool] $Identity, - [Parameter(ValueFromPipelineByPropertyName=$true)][long] $IdentitySeed, - [Parameter(ValueFromPipelineByPropertyName=$true)][long] $IdentityIncrement, - [Parameter(ValueFromPipelineByPropertyName=$true)][string] $Default - ) - $key = if($InPrimaryKey){' PK'}elseif($IsForeignKey){' FK'} - [string[]] $details = @() - if($Nullable) {$details += 'nullable'} - if($Identity) {$details += "identity($IdentitySeed,$IdentityIncrement)"} - if($ExtendedProperties['MS_Description']) {$details += $ExtendedProperties['MS_Description'].Value -replace '"',"'"} - if($details) {$details = ' "{0}"' -f ($details -join '; ')} - return "$DataType $Name$key$details" - } - - filter Format-TableAsMermaid - { - Param( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)][string] $Name, - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)][ColumnCollection] $Columns - ) - $Local:OFS = "$NL`t" - return @" -$Name { - $($Columns |Format-ColumnAsMermaid) -} -"@ - } - - filter Format-ForeignKeyAsMermaid - { - Param( - [Parameter(Position=0,Mandatory=$true)][TableCollection] $AllDatabaseTables, - [Parameter(Position=1,Mandatory=$true)][string[]] $SelectedTableUrns, - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)][string] $Name, - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)][string] $ReferencedTable, - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)][string] $ReferencedTableSchema, - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)][bool] $IsEnabled, - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)][Table] $Parent, - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)][ForeignKeyColumnCollection] $Columns, - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)][ExtendedPropertyCollection] $ExtendedProperties - ) - if(!$IsEnabled) {return} - if($AllDatabaseTables[$ReferencedTable,$ReferencedTableSchema].Urn.Value -notin $SelectedTableUrns) {return} - $description = $Columns.Name -join ', ' - if($ExtendedProperties['MS_Description']) {$description += ': {0}' -f ($ExtendedProperties['MS_Description'].Value -replace '"',"'")} - return "$($Parent.Name) }|--|| $ReferencedTable : `"$description`"$NL" - } -} -End -{ - [Table[]] $tables = if($input) {$input} else {@($Table)} - $Local:OFS = '' - return @" -erDiagram -$(($tables |Format-TableAsMermaid) -join $NL) -$($tables | - Select-Object -ExpandProperty ForeignKeys | - Format-ForeignKeyAsMermaid -AllDatabaseTables $tables[0].Parent.Tables -SelectedTableUrns $tables.Urn.Value) -"@ -} diff --git a/Export-TableMerge.ps1 b/Export-TableMerge.ps1 deleted file mode 100644 index 5f54fbcb..00000000 --- a/Export-TableMerge.ps1 +++ /dev/null @@ -1,122 +0,0 @@ -<# -.SYNOPSIS -Exports table data as a T-SQL MERGE statement. - -.OUTPUTS -System.String of SQL MERGE script to replicate the table's data. - -.FUNCTIONALITY -Database - -.LINK -https://learn.microsoft.com/sql/t-sql/statements/merge-transact-sql - -.LINK -https://dbatools.io/ - -.EXAMPLE -Get-DbaDbTable -SqlInstance $server -Schema HumanResources -Table Department |Export-TableMerge.ps1 - -if exists (select * from information_schema.columns where table_schema = 'HumanResources' and table_name = 'Department' -and columnproperty(object_id(table_name), column_name,'IsIdentity') = 1) -set identity_insert [HumanResources].[Department] on; - -merge [HumanResources].[Department] as target -using ( values -(1, 'Engineering', 'Research and Development', '2008-04-30 00:00:00.00000'), -(2, 'Tool Design', 'Research and Development', '2008-04-30 00:00:00.00000'), -(3, 'Sales', 'Sales and Marketing', '2008-04-30 00:00:00.00000'), -(4, 'Marketing', 'Sales and Marketing', '2008-04-30 00:00:00.00000'), -(5, 'Purchasing', 'Inventory Management', '2008-04-30 00:00:00.00000'), -(6, 'Research and Development', 'Research and Development', '2008-04-30 00:00:00.00000'), -(7, 'Production', 'Manufacturing', '2008-04-30 00:00:00.00000'), -(8, 'Production Control', 'Manufacturing', '2008-04-30 00:00:00.00000'), -(9, 'Human Resources', 'Executive General and Administration', '2008-04-30 00:00:00.00000'), -(10, 'Finance', 'Executive General and Administration', '2008-04-30 00:00:00.00000'), -(11, 'Information Services', 'Executive General and Administration', '2008-04-30 00:00:00.00000'), -(12, 'Document Control', 'Quality Assurance', '2008-04-30 00:00:00.00000'), -(13, 'Quality Assurance', 'Quality Assurance', '2008-04-30 00:00:00.00000'), -(14, 'Facilities and Maintenance', 'Executive General and Administration', '2008-04-30 00:00:00.00000'), -(15, 'Shipping and Receiving', 'Inventory Management', '2008-04-30 00:00:00.00000'), -(16, 'Executive', 'Executive General and Administration', '2008-04-30 00:00:00.00000') -) as source ([DepartmentID], [Name], [GroupName], [ModifiedDate]) -on source.[DepartmentID] = target.[DepartmentID] -when matched then -update set [Name] = source.[Name], -[GroupName] = source.[GroupName], -[ModifiedDate] = source.[ModifiedDate] -when not matched by target then -insert ([DepartmentID], [Name], [GroupName], [ModifiedDate]) -values (source.[DepartmentID], source.[Name], source.[GroupName], source.[ModifiedDate]) -when not matched by source then delete ; - -if exists (select * from information_schema.columns where table_schema = 'HumanResources' and table_name = 'Department' -and columnproperty(object_id(table_name), column_name,'IsIdentity') = 1) -set identity_insert [HumanResources].[Department] off; -#> - -#Requires -Version 7 -#Requires -Modules dbatools -using namespace Microsoft.SqlServer.Management.Smo -[CmdletBinding()][OutputType([string])] Param( -[Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)][Table] $Table -) -Begin -{ - filter ConvertTo-SqlName([Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)][string] $Name) - { - return [SqlSmoObject]::QuoteString($Name,'[',']') - } - - filter ConvertTo-SqlLiteral([Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)] $Value) - { - switch($Value.GetType()) - { - dbnull {'null'} - string {"'$($Value -replace "'","''")'"} - datetime {Get-Date $Value -f "\'yyyy-MM-dd HH:mm:ss.fffff\'"} - bool {$Value ? 1 : 0} - guid {"'$Value'"} - default {$Value} - } - } - - function Format-Merge([Table] $Table) - { - Unicodery\Import-CharConstants NL - $identitytest = @" -if exists (select * from information_schema.columns where table_schema = $(ConvertTo-SqlLiteral $Table.Schema) and table_name = $(ConvertTo-SqlLiteral $Table.Name) -and columnproperty(object_id(table_name), column_name,'IsIdentity') = 1) -"@ - $columns = ($Table.Columns.Name |ConvertTo-SqlName) -join ', ' - $fieldupdates = ($Table.Columns |Where-Object {!$_.InPrimaryKey} |Select-Object -ExpandProperty Name | - ConvertTo-SqlName |ForEach-Object {"$_ = source.$_"}) -join ",$NL" - $fieldupdates = - if($fieldupdates) {"when matched then${NL}update set $fieldupdates"} - else {"-- skip 'matched' condition (no non-key columns to update)"} - return @" -$identitytest -set identity_insert $Table on; - -merge $Table as target -using ( values -$((Invoke-DbaQuery -SqlInstance $Table.Parent.Parent -Database $Table.Parent.Name -Query "select * from $Table;" -As DataRow | - ForEach-Object {"($(($_.ItemArray |ConvertTo-SqlLiteral) -join ', '))"}) -join ",$NL") -) as source ($columns) -on $(($Table.Columns |Where-Object {$_.InPrimaryKey} |Select-Object -ExpandProperty Name |ConvertTo-SqlName | - ForEach-Object {"source.$_ = target.$_"}) -join "${NL}and ") -$fieldupdates -when not matched by target then -insert ($columns) -values ($(($Table.Columns.Name |ConvertTo-SqlName |ForEach-Object {"source.$_"}) -join ', ')) -when not matched by source then delete ; - -$identitytest -set identity_insert $Table off; -"@ - } -} -Process -{ - return Format-Merge $Table -} diff --git a/Find-DatabaseValue.ps1 b/Find-DatabaseValue.ps1 deleted file mode 100644 index 45e899b3..00000000 --- a/Find-DatabaseValue.ps1 +++ /dev/null @@ -1,283 +0,0 @@ -<# -.SYNOPSIS -Searches an entire database for a field value. - -.OUTPUTS -System.Management.Automation.PSCustomObject for each found row, including the #TableName, -#ColumnName, and all fields. - -.FUNCTIONALITY -Database - -.COMPONENT -System.Configuration - -.LINK -ConvertFrom-DataRow.ps1 - -.LINK -Invoke-Sqlcmd - -.EXAMPLE -Find-DatabaseValue.ps1 FR -IncludeSchemata Sales -MaxRows 100 -ServerInstance '(localdb)\ProjectsV13' -Database AdventureWorks2016 - -TableName : [Sales].[SalesTerritory] -TerritoryID : 7 -Name : France -CountryRegionCode : FR -Group : Europe -SalesYTD : 4772398.3078 -SalesLastYear : 2396539.7601 -CostYTD : 0.0000 -CostLastYear : 0.0000 -rowguid : bf806804-9b4c-4b07-9d19-706f2e689552 -ModifiedDate : 04/30/2008 00:00:00 - -.EXAMPLE -Find-DatabaseValue.ps1 41636 -IncludeColumns %OrderID -ServerInstance '(localdb)\ProjectsV13' -Database AdventureWorks2016 |tee order41636.txt - -TableName : [Production].[TransactionHistory] -TransactionID : 100046 -ProductID : 826 -ReferenceOrderID : 41636 -ReferenceOrderLineID : 0 -TransactionDate : 07/31/2013 00:00:00 -TransactionType : W -Quantity : 4 -ActualCost : 0.0000 -ModifiedDate : 07/31/2013 00:00:00 - -TableName : [Production].[WorkOrder] -WorkOrderID : 41636 -ProductID : 826 -OrderQty : 4 -StockedQty : 4 -ScrappedQty : 0 -StartDate : 07/31/2013 00:00:00 -EndDate : 08/11/2013 00:00:00 -DueDate : 08/11/2013 00:00:00 -ScrapReasonID : -ModifiedDate : 08/11/2013 00:00:00 - -TableName : [Production].[WorkOrderRouting] -WorkOrderID : 41636 -ProductID : 826 -OperationSequence : 6 -LocationID : 50 -ScheduledStartDate : 07/31/2013 00:00:00 -ScheduledEndDate : 08/11/2013 00:00:00 -ActualStartDate : 08/01/2013 00:00:00 -ActualEndDate : 08/11/2013 00:00:00 -ActualResourceHrs : 3.0000 -PlannedCost : 36.7500 -ActualCost : 36.7500 -ModifiedDate : 08/11/2013 00:00:00 -#> - -#Requires -Version 3 -[CmdletBinding()][OutputType([Management.Automation.PSCustomObject])] Param( -<# -The value to search for. The datatype is significant, e.g. searching for money/smallmoney columns, cast the type to decimal: [decimal]13.55 -Searches, by type: - -* string: varchar, char, nvarchar, nchar (char length must be at least as long as value) -* byte: tinyint -* int: bigint, int -* long: bigint, numeric or decimal (where scale is zero) -* decimal: money, smallmoney -* double or float: float, real, numeric, decimal -* datetime: date (if no time specified), datetime, datetime2, datetimeoffset, smalldatetime -* timespan: time - -If the -LikeValue switch is specified, the type of value is assumed to be string. -#> -[Parameter(Position=0,Mandatory=$true)] $Value, -# The server and instance to connect to. -[Parameter(ParameterSetName='ByConnectionParameters',Mandatory=$true)][string] $ServerInstance, -# The database to use. -[Parameter(ParameterSetName='ByConnectionParameters',Mandatory=$true)][string] $Database, -# Specifies a connection string to connect to the server. -[Parameter(ParameterSetName='ByConnectionString',Mandatory=$true)][Alias('ConnStr','CS')][string] $ConnectionString, -# Specifies an SMO Database object to query. -[Parameter(ParameterSetName='ByDatabase',Mandatory=$true)] -[Microsoft.SqlServer.Management.Smo.Database] $SmoDatabase, -# The connection string name from the ConfigurationManager to use. -[Parameter(ParameterSetName='ByConnectionName',Mandatory=$true)][string] $ConnectionName, -# A like-pattern of database schemata to include (will only include these). -[string[]] $IncludeSchemata, -# A like-pattern of database schemata to exclude. -[string[]] $ExcludeSchemata, -# A like-pattern of database tables to include (will only include these). -[string[]] $IncludeTables, -# A like-pattern of database tables to exclude. -[string[]] $ExcludeTables, -# A like-pattern of database columns to include (will only include these). -[string[]] $IncludeColumns, -# A like-pattern of database columns to exclude. -[string[]] $ExcludeColumns, -# Tables with more rows than this value will be skipped. -[int] $MinRows = 1, -# Tables with more rows than this value will be skipped. -[int] $MaxRows, -# Quit as soon as the first value is found. -[switch] $FindFirst, -# Interpret the value as a like-pattern (% for zero-or-more characters, _ for a single character, \ is escape). -[switch] $LikeValue -) -try{[void][Configuration.ConfigurationManager]}catch{Add-Type -AssemblyName System.Configuration} -function Format-LikeCondition([string]$column,[string[]]$patterns,[switch]$not) -{ - $like,$andOr = if($not){'not like','and'}else{'like','or'} -@" - - and ( $(($patterns |ForEach-Object {"$column $like '$($_ -replace '''','''''')' escape '\'"}) -join " $andOr ") ) - -"@ -} - -Use-SqlcmdParams.ps1 -QueryTimeout 300 - -if($Value -is [int]) -{ - if($Value -le [byte]::MaxValue) {$Value = [byte] $Value} - elseif($Value -le [short]::MaxValue) {$Value = [short] $Value} -} -$selectFrom = "select '{0}.{1}' [#TableName], '{2}' [#ColumnName], * from" -$colssql = @" -select quotename(TABLE_SCHEMA) TABLE_SCHEMA, - quotename(TABLE_NAME) TABLE_NAME, - quotename(COLUMN_NAME) COLUMN_NAME - from INFORMATION_SCHEMA.COLUMNS - -"@ -if($LikeValue) -{ - $minLength = ($Value -replace '\\.','_' -replace '%','').Length - Write-Verbose "Searching for character data with a minimum length of $minLength to match pattern." - $colssql += @" - where DATA_TYPE in ('varchar','char','nvarchar','nchar') - and (CHARACTER_MAXIMUM_LENGTH = -1 or CHARACTER_MAXIMUM_LENGTH >= $minLength) -"@ - $valsql = "$selectFrom {0}.{1} where {2} like '$($Value -replace '''','''''')' escape '\';" -} -elseif($Value -is [string]) -{ - Write-Verbose "Searching for character data with a minimum length of $($Value.Length)." - $colssql += @" - where DATA_TYPE in ('varchar','char','nvarchar','nchar') - and (CHARACTER_MAXIMUM_LENGTH = -1 or CHARACTER_MAXIMUM_LENGTH >= $($Value.Length)) -"@ - $valsql = "$selectFrom {0}.{1} where {2} = '$($Value -replace '''','''''')';" -} -elseif($Value -is [byte]) -{ - Write-Verbose "Searching for byte (tinyint) data." - $colssql += @" - where DATA_TYPE in ('tinyint','smallint','int') -"@ - $valsql = "$selectFrom {0}.{1} where {2} = $Value;" -} -elseif($Value -is [short]) -{ - Write-Verbose "Searching for short (smallint) data." - $colssql += @" - where DATA_TYPE in ('smallint','int') -"@ - $valsql = "$selectFrom {0}.{1} where {2} = $Value;" -} -elseif($Value -is [int]) -{ - Write-Verbose "Searching for integer data." - $colssql += @" - where DATA_TYPE in ('int') -"@ - $valsql = "$selectFrom {0}.{1} where {2} = $Value;" -} -elseif($Value -is [long]) -{ - Write-Verbose "Searching for long integer data." - $colssql += @" - where (DATA_TYPE = 'bigint' - or (DATA_TYPE in ('numeric','decimal') and NUMERIC_SCALE = 0)) -"@ - $valsql = "$selectFrom {0}.{1} where {2} = '$Value';" -} -elseif($Value -is [decimal]) -{ - Write-Verbose "Searching for decimal (money) data." - $colssql += @" - where DATA_TYPE in ('money','smallmoney') -"@ - $valsql = "$selectFrom {0}.{1} where {2} = $Value;" -} -elseif($Value -is [double] -or $Value -is [float]) -{ - Write-Verbose "Searching for double-precision floating-point or money data." - $colssql += @" - where DATA_TYPE in ('float','real','numeric','decimal') -"@ - $valsql = "$selectFrom {0}.{1} where {2} = $Value;" -} -elseif($Value -is [datetime] -and $Value.TimeOfDay -eq 0) -{ - Write-Verbose "Searching for date data." - $colssql += @" - where DATA_TYPE in ('date','datetime','datetime2','datetimeoffset','smalldatetime') -"@ - $valsql = "$selectFrom {0}.{1} where {2} = '$($Value.ToString('yyyy-MM-dd'))';" -} -elseif($Value -is [datetime]) -{ - Write-Verbose "Searching for datetime data." - $colssql += @" - where DATA_TYPE in ('datetime','datetime2','datetimeoffset','smalldatetime') -"@ - $valsql = "$selectFrom {0}.{1} where {2} = '$($Value.ToString('u'))';" -} -elseif($Value -is [timespan]) -{ - Write-Verbose "Searching for time data." - $colssql += @" - where DATA_TYPE in ('time') -"@ - $valsql = "$selectFrom {0}.{1} where {2} = '$($Value.ToString('HH:mm:ss.fffff'))';" -} -if($IncludeSchemata) { $colssql += Format-LikeCondition TABLE_SCHEMA $IncludeSchemata } -if($ExcludeSchemata) { $colssql += Format-LikeCondition TABLE_SCHEMA $ExcludeSchemata -Not } -if($IncludeTables) { $colssql += Format-LikeCondition TABLE_NAME $IncludeTables } -if($ExcludeTables) { $colssql += Format-LikeCondition TABLE_NAME $ExcludeTables -Not } -if($IncludeColumns) { $colssql += Format-LikeCondition COLUMN_NAME $IncludeColumns } -if($ExcludeColumns) { $colssql += Format-LikeCondition COLUMN_NAME $ExcludeColumns -Not } -$colssql += ' order by TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION;' - -Write-Debug "Schema Query:`n$colssql" -$corpus = Invoke-Sqlcmd $colssql |ConvertFrom-DataRow.ps1 -if(!$corpus) {ModernConveniences\Stop-ThrowError 'No columns left to search.' -SearchContext $PSBoundParameters} -Write-Verbose "Searching $($corpus.Length) tables" -$count,$p,$rows,$lasttable = 0,0,0,'' -foreach($row in $corpus) -{ - ModernConveniences\Import-Variables $row - if($lasttable -ne "$TABLE_SCHEMA.$TABLE_NAME") - { - [int]$rows = Invoke-Sqlcmd "select count(*) rows from $TABLE_SCHEMA.$TABLE_NAME" |ConvertFrom-DataRow.ps1 -AsValues - $lasttable = "$TABLE_SCHEMA.$TABLE_NAME" - } - Write-Progress 'Searching columns' "$TABLE_SCHEMA.$TABLE_NAME.$COLUMN_NAME" 1 -CurrentOperation "$rows rows" ` - -PercentComplete ((++$p)*100/$corpus.Length) -ErrorAction Ignore - if($rows -lt $MinRows) {Write-Verbose "Skipping $TABLE_SCHEMA.$TABLE_NAME ($rows rows < $MinRows)"; continue} - if($MaxRows -and $rows -gt $MaxRows) {Write-Verbose "Skipping $TABLE_SCHEMA.$TABLE_NAME ($rows rows > $MaxRows)"; continue} - $query = $valsql -f $TABLE_SCHEMA,$TABLE_NAME,$COLUMN_NAME - [Data.DataTable]$data = $null - Write-Verbose "Query: $query" - $data = try {Invoke-Sqlcmd $query -OutputAs DataTables} catch {Write-Error $_; continue} - if($data -and ($data.Rows.Count -gt 0)) - { - $count += $data.Rows.Count - Write-Verbose "Found $($data.Rows.Count) rows in $TABLE_SCHEMA.$TABLE_NAME." - $data.Rows |ConvertFrom-DataRow.ps1 - if($FindFirst) { break } - } -} -if(!$count) {Write-Warning "No rows found."} -else {Write-Verbose "Found $count total rows."} diff --git a/Find-DbColumn.ps1 b/Find-DbColumn.ps1 deleted file mode 100644 index ac20923e..00000000 --- a/Find-DbColumn.ps1 +++ /dev/null @@ -1,150 +0,0 @@ -<# -.SYNOPSIS -Searches for database columns. - -.OUTPUTS -System.Management.Automation.PSCustomObject for each found column: - -* TableSchema -* TableName -* ColumnName -* DataType -* Nullable -* DefaultValue - -.FUNCTIONALITY -Database - -.COMPONENT -System.Configuration - -.LINK -ConvertFrom-DataRow.ps1 - -.LINK -Invoke-Sqlcmd - -.EXAMPLE -Find-DbColumn.ps1 -ServerInstance '(localdb)\ProjectsV13' -Database AdventureWorks2016 -IncludeColumns %price% |Format-Table -AutoSize - -TableSchema TableName ColumnName DataType Nullable DefaultValue ------------ --------- ---------- -------- -------- ------------ -Production Product ListPrice money False -Production ProductListPriceHistory ListPrice money False -Purchasing ProductVendor StandardPrice money False -Purchasing PurchaseOrderDetail UnitPrice money False -Sales SalesOrderDetail UnitPrice money False -Sales SalesOrderDetail UnitPriceDiscount money False ((0.0)) -#> - -#Requires -Version 3 -[CmdletBinding()][OutputType([Management.Automation.PSCustomObject])] Param( -# The server and instance to connect to. -[Parameter(ParameterSetName='ByConnectionParameters',Mandatory=$true)][string] $ServerInstance, -# The database to use. -[Parameter(ParameterSetName='ByConnectionParameters',Mandatory=$true)][string] $Database, -# Specifies a connection string to connect to the server. -[Parameter(ParameterSetName='ByConnectionString',Mandatory=$true)][Alias('ConnStr','CS')][string] $ConnectionString, -# Specifies an SMO Database object to query. -[Parameter(ParameterSetName='ByDatabase',Mandatory=$true)] -[Microsoft.SqlServer.Management.Smo.Database] $SmoDatabase, -# The connection string name from the ConfigurationManager to use. -[Parameter(ParameterSetName='ByConnectionName',Mandatory=$true)][string] $ConnectionName, -# A like-pattern of database schemata to include (will only include these). -[string[]] $IncludeSchemata, -# A like-pattern of database schemata to exclude. -[string[]] $ExcludeSchemata, -# A like-pattern of database tables to include (will only include these). -[string[]] $IncludeTables, -# A like-pattern of database tables to exclude. -[string[]] $ExcludeTables, -# A like-pattern of database columns to include (will only include these). -[string[]] $IncludeColumns, -# A like-pattern of database columns to exclude. -[string[]] $ExcludeColumns, -# The basic datatype to search for. -[ValidateSet('char','byte','int','long','decimal','double','date','datetime','time')] -[string] $DataType, -# The minimum character column length. -[int] $MinLength, -# The maximum character column length. -[int] $MaxLength -) -try{[void][Configuration.ConfigurationManager]}catch{Add-Type -AssemblyName System.Configuration} -function Format-LikeCondition([string]$column,[string[]]$patterns,[switch]$not) -{ - $like,$andOr = if($not){'not like','and'}else{'like','or'} -@" - - and ( $(($patterns |ForEach-Object {"$column $like '$($_ -replace '''','''''')' escape '\'"}) -join " $andOr ") ) - -"@ -} - -Use-SqlcmdParams.ps1 -QueryTimeout 300 - -$colssql = @" -select TABLE_SCHEMA TableSchema, - TABLE_NAME TableName, - COLUMN_NAME ColumnName, - DATA_TYPE + - case - when DATA_TYPE in ('int','smallint','bigint','tinyint','money','bit') then '' - when CHARACTER_MAXIMUM_LENGTH is not null then '(' + cast(CHARACTER_MAXIMUM_LENGTH as varchar) + ')' - when NUMERIC_PRECISION is not null then '(' + cast(NUMERIC_PRECISION as varchar) + - case when NUMERIC_PRECISION_RADIX is not null and NUMERIC_PRECISION_RADIX <> 10 then ' base ' + - cast(NUMERIC_PRECISION_RADIX as varchar) else '' end + - case when NUMERIC_SCALE is not null then ',' + cast(NUMERIC_SCALE as varchar) else '' end + ')' - else '' - end DataType, - cast(case IS_NULLABLE when 'Yes' then 1 else 0 end as bit) Nullable, - COLUMN_DEFAULT DefaultValue - from INFORMATION_SCHEMA.COLUMNS - -"@ -$colssql += switch($DataType) -{ - string {@" - where DATA_TYPE in ('varchar','char','nvarchar','nchar') -$(if($MinLength){" and (CHARACTER_MAXIMUM_LENGTH = -1 or CHARACTER_MAXIMUM_LENGTH >= $MinLength)"}) -$(if($MaxLength){" and (CHARACTER_MAXIMUM_LENGTH = -1 or CHARACTER_MAXIMUM_LENGTH >= $MaxLength)"}) -"@} - byte {@" - where DATA_TYPE in ('tinyint') -"@} - int {@" - where DATA_TYPE in ('int') -"@} - long {@" - where (DATA_TYPE = 'bigint' - or (DATA_TYPE in ('numeric','decimal') and NUMERIC_SCALE = 0)) -"@} - decimal {@" - where DATA_TYPE in ('money','smallmoney') -"@} - {$_ -in 'float','double'} {@" - where DATA_TYPE in ('float','real','numeric','decimal') -"@} - date {@" - where DATA_TYPE in ('date','datetime','datetime2','datetimeoffset','smalldatetime') -"@} - datetime {@" - where DATA_TYPE in ('datetime','datetime2','datetimeoffset','smalldatetime') -"@} - time {@" - where DATA_TYPE in ('time') -"@} - default {@" - where 1 = 1 -"@} -} -if($IncludeSchemata) { $colssql += Format-LikeCondition TABLE_SCHEMA $IncludeSchemata } -if($ExcludeSchemata) { $colssql += Format-LikeCondition TABLE_SCHEMA $ExcludeSchemata -Not } -if($IncludeTables) { $colssql += Format-LikeCondition TABLE_NAME $IncludeTables } -if($ExcludeTables) { $colssql += Format-LikeCondition TABLE_NAME $ExcludeTables -Not } -if($IncludeColumns) { $colssql += Format-LikeCondition COLUMN_NAME $IncludeColumns } -if($ExcludeColumns) { $colssql += Format-LikeCondition COLUMN_NAME $ExcludeColumns -Not } -$colssql += ' order by TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION;' - -Write-Debug "Schema Query:`n$colssql" -Invoke-Sqlcmd $colssql |ConvertFrom-DataRow.ps1 diff --git a/Find-DbIndexes.ps1 b/Find-DbIndexes.ps1 deleted file mode 100644 index 9f010f07..00000000 --- a/Find-DbIndexes.ps1 +++ /dev/null @@ -1,80 +0,0 @@ -<# -.SYNOPSIS -Returns indexes using a column with the given name. - -.OUTPUTS -System.Management.Automation.PSCustomObject with these properties: - -* SchemaName -* TableName -* IndexName -* IndexOrdinal -* IsUnique -* IsClustered -* IsDisabled -* ColumnsInIndex - -.FUNCTIONALITY -Database - -.LINK -Invoke-Sqlcmd - -.LINK -ConvertFrom-DataRow.ps1 - -.LINK -https://docs.microsoft.com/sql/relational-databases/system-catalog-views/sys-index-columns-transact-sql - -.EXAMPLE -Find-DbIndexes.ps1 -ServerInstance '(localdb)\ProjectsV13' -Database AdventureWorks2014 -ColumnName ErrorLogID - -SchemaName : dbo -TableName : ErrorLog -IndexName : PK_ErrorLog_ErrorLogID -IndexOrdinal : 1 -IsUnique : 1 -IsClustered : 1 -IsDisabled : 0 -ColumnsInIndex : 1 -#> - -#Requires -Version 3 -#Requires -Module SqlServer -[CmdletBinding()][OutputType([Management.Automation.PSCustomObject])] Param( -<# -The name of a server (and optional instance) to connect and use for the query. -May be used with optional Database, Credential, and ConnectionProperties parameters. -#> -[Parameter(ParameterSetName='ByConnectionParameters',Position=0,Mandatory=$true)][string] $ServerInstance, -# The the database to connect to on the server. -[Parameter(ParameterSetName='ByConnectionParameters',Position=1,Mandatory=$true)][string] $Database, -# Specifies a connection string to connect to the server. -[Parameter(ParameterSetName='ByConnectionString',Mandatory=$true)][Alias('ConnStr','CS')][string]$ConnectionString, -# Specifies an SMO Database object to query. -[Parameter(ParameterSetName='ByDatabase',Mandatory=$true)] -[Microsoft.SqlServer.Management.Smo.Database] $SmoDatabase, -# The connection string name from the ConfigurationManager to use. -[Parameter(ParameterSetName='ByConnectionName',Mandatory=$true)][string]$ConnectionName, -# The column name to search for. -[Parameter(Position=2,Mandatory=$true)][Alias('ColName')][string]$ColumnName -) - -Use-SqlcmdParams.ps1 - -Invoke-Sqlcmd @" -select object_schema_name(i.object_id) SchemaName, - object_name(i.object_id) TableName, - i.name IndexName, - ic.index_column_id IndexOrdinal, - indexproperty(i.object_id,i.name,'IsUnique') IsUnique, - indexproperty(i.object_id,i.name,'IsClustered') IsClustered, - indexproperty(i.object_id,i.name,'IsDisabled') IsDisabled, - (select count(*) from sys.index_columns c where c.object_id = i.object_id and c.index_id = i.index_id) ColumnsInIndex - from sys.index_columns ic - join sys.indexes i - on ic.object_id = i.object_id - and ic.index_id = i.index_id - where col_name(ic.object_id,ic.column_id) = '$($ColumnName -replace "'","''")' - order by TableName, IndexName; -"@ |ConvertFrom-DataRow.ps1 diff --git a/Get-ConfigConnectionStringBuilders.ps1 b/Get-ConfigConnectionStringBuilders.ps1 deleted file mode 100644 index bcf5edce..00000000 --- a/Get-ConfigConnectionStringBuilders.ps1 +++ /dev/null @@ -1,40 +0,0 @@ -<# -.SYNOPSIS -Return named connection string builders for connection strings in a config file. - -.INPUTS -System.String of the path to a .NET config file with connection strings. - -.OUTPUTS -System.Management.Automation.PSCustomObject with the Name and ConnectionString -(a ConnectionStringBuilder) for each connection string found. - -.FUNCTIONALITY -Configuration - -.LINK -Select-Xml - -.EXAMPLE -Get-ConfigConnectionStringBuilders.ps1 web.Debug.config - -Returns the connection strings found in the debug web.config XDT. -#> - -#Requires -Version 3 -[CmdletBinding()][OutputType([Management.Automation.PSCustomObject])] Param( -# The .NET config file containing connection strings. -[Parameter(Position=0,ValueFromPipelineByPropertyName=$true)][Alias('FullName')][string]$Path -) -Process -{ - Select-Xml '//connectionStrings/add' $Path | - ForEach-Object { - $provider = $_.Node.Attributes.GetNamedItem('providerName') - if($provider){$provider=$provider.Value} - [pscustomobject]@{ - Name = $_.Node.name - ConnectionString = New-DbProviderObject.ps1 $provider ConnectionStringBuilder $_.Node.connectionString - } - } -} diff --git a/Measure-DbColumn.ps1 b/Measure-DbColumn.ps1 deleted file mode 100644 index 52e0745f..00000000 --- a/Measure-DbColumn.ps1 +++ /dev/null @@ -1,374 +0,0 @@ -<# -.SYNOPSIS -Provides statistics about SQL Server column data. - -.INPUTS -Microsoft.SqlServer.Management.Smo.Column to calculate statistics for, -or Microsoft.SqlServer.Management.Smo.Table to select a column from by name. - -.OUTPUTS -System.Management.Automation.PSCustomObject that describes the column: - -* ColumnName -* SqlType -* NullValues -* IsUnique -* UniqueValues -* MinimumValue -* MaximumValue -* MeanAverage -* ModeAverage -* Variance -* StandardDeviation -* additonal properties, depending on type - -.FUNCTIONALITY -Database - -.LINK -https://www.powershellgallery.com/packages/SqlServer/ - -.LINK -https://dbatools.io/ - -.LINK -https://wikipedia.org/wiki/Windows1252 - -.EXAMPLE -$table = Get-DbaDbTable SqlServerName -Database DbName -Table TableName; Measure-DbColumn.ps1 $table.Columns['record_id'] - -ColumnName : record_id -SqlType : int -NullValues : 0 -IsUnique : True -UniqueValues : 43 -MinimumValue : 2 -MaximumValue : 56 -MeanAverage : 28 -ModeAverage : 28 -Variance : 290.330011074197 -StandardDeviation : 17.0390730696889 - -.EXAMPLE -Get-DbaDbTable SqlServerName -Database DbName -Table TableName |Measure-DbColumn.ps1 surname - -ColumnName : surname -SqlType : varchar(40) -NullValues : 0 -IsUnique : False -UniqueValues : 72281 -MinimumValue : AARONSON -MaximumValue : ZYKOWSKI -MostCommonValue : SMITH -MininumLength : 1 -MaximumLength : 40 -HasLeadingSpaces : True -HasTrailingSpaces : False -HasControlChars : False -HasWindows1252 : False -HasUnicode : False -HasNonAscii7 : False -HasNonAlphanumeric : True - -.EXAMPLE -Get-DbaDbTable '(localdb)\ProjectsV13' -database AdventureWorks2016 -Table Sales.SalesOrderHeader |Measure-DbColumn.ps1 OrderDate - -ColumnName : OrderDate -SqlType : datetime -Values : 31465 -NullValues : 0 -IsUnique : False -IsDateOnly : True -DateOnlyValues : 31465 -DateTimeValues : 0 -UniqueValues : 1124 -MostCommonValue : 03/31/2014 00:00:00 -MinimumValue : 05/31/2011 00:00:00 -MaximumValue : 06/30/2014 00:00:00 -ModeAverage : 03/31/2014 00:00:00 -MeanYear : 2013 -ModeYear : 2013 -MeanMonth : January -ModeMonth : May -MeanDayOfWeek : Thursday -ModeDayOfWeek : Monday -MeanDayOfMonth : 16 -Sunday : 4444 -Monday : 4875 -Tuesday : 4482 -Wednesday : 4591 -Thursday : 4346 -Friday : 4244 -Saturday : 4483 -January : 2877 -Febuary : 2300 -March : 3144 -April : 2812 -May : 3175 -June : 2189 -July : 2356 -August : 2324 -September : 2300 -October : 2616 -November : 2716 -December : 2656 -#> - -#Requires -Version 3 -#Requires -Module SqlServer -[CmdletBinding(ConfirmImpact='Medium')][OutputType([Management.Automation.PSCustomObject])] Param( -# An SMO column object associated to the database column to examine. -[Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true,ParameterSetName='Column')] -[Microsoft.SqlServer.Management.Smo.Column] $Column, -# The name of the column to examine in the table associated with the SMO Table object. -[Parameter(Position=0,Mandatory=$true,ParameterSetName='ColumnName')][string] $ColumnName, -# An SMO table object associated to the database to examine. -[Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$true,ParameterSetName='ColumnName')] -[Microsoft.SqlServer.Management.Smo.Table] $Table, -<# -Conditions to be provided as a SQL WHERE clause to filter the column values to examine. -Useful for databases that implement "soft deletes" as specific field values. -#> -[string] $Condition -) -Begin -{ - $SOQ = @' -select '{2}' ColumnName, - '{3}' SqlType, -'@ - $EOQ = if(!$Condition) {' from [{0}].[{1}];'} else {" from [{0}].[{1}] where $Condition ;"} - $query = @{ - Numeric = @" - with TopValues as ( -select top 1 with ties [{2}] value, count(*) # - from [{0}].[{1}] - group by [{2}] - order by # desc -), MedianValue as ( -select max(value) value - from (select top 50 percent [{2}] value from [{0}].[{1}] order by value) a - union -select min(value) - from (select top 50 percent [{2}] value from [{0}].[{1}] order by value desc) b -) -$SOQ - count([{2}]) [Values], - sum(case when [{2}] is null then 1 else 0 end) NullValues, - cast(case when count(*) = count(distinct [{2}]) then 1 else 0 end as bit) IsUnique, - count(distinct [{2}]) UniqueValues, - min([{2}]) MinimumValue, - max([{2}]) MaximumValue, - avg(cast([{2}] as real)) MeanAverage, - (select avg(cast(value as real)) from MedianValue) MedianAverage, - (select avg(cast(value as real)) from TopValues) ModeAverage, - var([{2}]) Variance, - stdev([{2}]) StandardDeviation -$EOQ -"@ - DateTime = @" - with TopValues as ( -select top 1 [{2}] value, count(*) # - from [{0}].[{1}] - group by [{2}] - order by # desc -), MedianValue as ( -select max(a.value) value - from (select top 50 percent [{2}] value from [{0}].[{1}] order by value) a - union -select min(b.value) - from (select top 50 percent [{2}] value from [{0}].[{1}] order by value desc) b -), DateOnlyCount as ( -select count(*) # - from [{0}].[{1}] - where [{2}] = cast([{2}] as date) -), TopYears as ( -select top 1 Year([{2}]) [year], count(*) # - from [{0}].[{1}] - group by Year([{2}]) - order by # desc -), TopMonths as ( -select top 1 datename(month,[{2}]) [month], count(*) # - from [{0}].[{1}] - group by datename(month,[{2}]) - order by # desc -), TopDaysOfWeek as ( -select top 1 datename(dw,[{2}]) [dayofweek], count(*) # - from [{0}].[{1}] - group by datename(dw,[{2}]) - order by # desc -), TopDays as ( -select top 1 Day([{2}]) [day], count(*) # - from [{0}].[{1}] - group by Day([{2}]) - order by # desc -) -$SOQ - count([{2}]) [Values], - sum(case when [{2}] is null then 1 else 0 end) NullValues, - cast(case when count(*) = count(distinct [{2}]) then 1 else 0 end as bit) IsUnique, - cast(case count([{2}]) when (select # from DateOnlyCount) then 1 else 0 end as bit) IsDateOnly, - (select # from DateOnlyCount) DateOnlyValues, - count([{2}]) - (select # from DateOnlyCount) DateTimeValues, - count(distinct [{2}]) UniqueValues, - (select top 1 value from TopValues) MostCommonValue, - min([{2}]) MinimumValue, - max([{2}]) MaximumValue, - --dateadd(seconds,'1970-01-01',avg(cast(datediff(second,'1970-01-01',[{2}]) as real))) MeanAverage, - --(select dateadd(seconds,avg([{2}]),'1970-01-01') from TopValues) MedianAverage, - (select value from TopValues) ModeAverage, - cast(avg(cast(Year([{2}]) as real)) as int) MeanYear, - (select [year] from TopYears) ModeYear, - datename(month,avg(Month([{2}]))) MeanMonth, - (select [month] from TopMonths) ModeMonth, - datename(dw,avg(datepart(dw,[{2}]))) MeanDayOfWeek, - (select [dayofweek] from TopDaysOfWeek) ModeDayOfWeek, - avg(Day([{2}])) MeanDayOfMonth, - sum(case datepart(dw,[{2}]) when 1 then 1 end) Sunday, - sum(case datepart(dw,[{2}]) when 2 then 1 end) Monday, - sum(case datepart(dw,[{2}]) when 3 then 1 end) Tuesday, - sum(case datepart(dw,[{2}]) when 4 then 1 end) Wednesday, - sum(case datepart(dw,[{2}]) when 5 then 1 end) Thursday, - sum(case datepart(dw,[{2}]) when 6 then 1 end) Friday, - sum(case datepart(dw,[{2}]) when 7 then 1 end) Saturday, - sum(case datepart(m,[{2}]) when 1 then 1 end) January, - sum(case datepart(m,[{2}]) when 2 then 1 end) Febuary, - sum(case datepart(m,[{2}]) when 3 then 1 end) March, - sum(case datepart(m,[{2}]) when 4 then 1 end) April, - sum(case datepart(m,[{2}]) when 5 then 1 end) May, - sum(case datepart(m,[{2}]) when 6 then 1 end) June, - sum(case datepart(m,[{2}]) when 7 then 1 end) July, - sum(case datepart(m,[{2}]) when 8 then 1 end) August, - sum(case datepart(m,[{2}]) when 9 then 1 end) September, - sum(case datepart(m,[{2}]) when 10 then 1 end) October, - sum(case datepart(m,[{2}]) when 11 then 1 end) November, - sum(case datepart(m,[{2}]) when 12 then 1 end) December -$EOQ -"@ - Temporal = @" - with TopValues as ( -select top 1 [{2}] value, count(*) # - from [{0}].[{1}] - group by [{2}] - order by # desc -) -$SOQ - count([{2}]) [Values], - sum(case when [{2}] is null then 1 else 0 end) NullValues, - cast(case when count(*) = count(distinct [{2}]) then 1 else 0 end as bit) IsUnique, - count(distinct [{2}]) UniqueValues, - (select top 1 value from TopValues) MostCommonValue, - min([{2}]) MinimumValue, - max([{2}]) MaximumValue -$EOQ -"@ - String = @" - with TopValues as ( -select top 1 [{2}] value, count(*) # - from [{0}].[{1}] - group by [{2}] - order by # desc -) -$SOQ - count([{2}]) [Values], - sum(case when [{2}] is null then 1 else 0 end) NullValues, - cast(case when count(*) = count(distinct [{2}]) then 1 else 0 end as bit) IsUnique, - count(distinct [{2}]) UniqueValues, - min([{2}]) MinimumValue, - max([{2}]) MaximumValue, - (select top 1 value from TopValues) MostCommonValue, - min(len([{2}])) MininumLength, - max(len([{2}])) MaximumLength, - cast(case when exists (select top 1 * from [{0}].[{1}] where [{2}] <> ltrim([{2}])) then 1 else 0 end as bit) HasLeadingSpaces, - cast(case when exists (select top 1 * from [{0}].[{1}] where [{2}] <> rtrim([{2}])) then 1 else 0 end as bit) HasTrailingSpaces, - cast(case when exists (select top 1 * from [{0}].[{1}] where [{2}] like '%'+char(0x09)+'%') then 1 else 0 end as bit) HasTabs, - cast(case when exists (select top 1 * from [{0}].[{1}] where [{2}] - like '%[' + char(0x00) + '-' + char(0x1F) + ']%') then 1 else 0 end as bit) HasControlChars, - cast(case when exists (select top 1 * from [{0}].[{1}] where [{2}] - like '%[€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ]%') then 1 else 0 end as bit) HasWindows1252Conflicts, - cast(case when exists (select top 1 * from [{0}].[{1}] where [{2}] collate SQL_Latin1_General_CP437_BIN - <> cast([{2}] as varchar(max)) collate SQL_Latin1_General_CP437_BIN) then 1 else 0 end as bit) HasUnicode, - cast(case when exists (select top 1 * from [{0}].[{1}] where [{2}] collate SQL_Latin1_General_CP437_BIN - like '%[^' + char(0x00) + '-~]%') then 1 else 0 end as bit) HasNonAscii7, - cast(case when exists (select top 1 * from [{0}].[{1}] where ltrim(rtrim([{2}])) like '%[^0-9A-Za-z_]%') then 1 else 0 end as bit) HasNonAlphanumeric -$EOQ -"@ - VariableLength = @" -$SOQ - count([{2}]) [Values], - sum(case when [{2}] is null then 1 else 0 end) NullValues, - cast(case when count(*) = count(distinct [{2}]) then 1 else 0 end as bit) IsUnique, - count(distinct [{2}]) UniqueValues, - min(len([{2}])) MininumLength, - max(len([{2}])) MaximumLength -$EOQ -"@ - Other = @" -$SOQ - count([{2}]) Values, - sum(case when [{2}] is null then 1 else 0 end) NullValues -$EOQ -"@ - } - $typeinfo = @{ - bigint = @('Numeric','{0}') - binary = @('VariableLength','{0}({1})') - bit = @('Other','{0}') - char = @('String','{0}({1})') - cursor = @('Other','{0}') - date = @('Temporal','{0}') - datetime = @('DateTime','{0}') - datetime2 = @('DateTime','{0}({3})') - datetimeoffset = @('DateTime','{0}({3})') - decimal = @('Numeric','{0}({2},{3})') - float = @('Numeric','{0}') - geography = @('Other','{0}') - geometry = @('Other','{0}') - hierarchyid = @('Other','{0}') - image = @('Other','{0}') - int = @('Numeric','{0}') - money = @('Numeric','{0}') - nchar = @('String','{0}({1})') - ntext = @('Other','{0}') - numeric = @('Numeric','{0}({2},{3})') - nvarchar = @('String','{0}({1:0;max})') - real = @('Numeric','{0}') - rowversion = @('Other','{0}') - smalldatetime = @('DateTime','{0}') - smallint = @('Numeric','{0}') - smallmoney = @('Numeric','{0}') - sql_variant = @('VariableLength','{0}') - table = @('Other','{0}') - text = @('Other','{0}') - time = @('Temporal','{0}') - tinyint = @('Numeric','{0}') - uniqueidentifier = @('Other','{0}') - varbinary = @('VariableLength','{0}({1:0;max})') - varchar = @('String','{0}({1:0;max})') - xml = @('VariableLength','{0}') - } -} -Process -{ - if($Column) {$ColumnName = $Column.Name} - else - { - $Column = $Table.Columns[$ColumnName] - if(!$Column) {ModernConveniences\Stop-ThrowError "Column '$ColumnName' not found in table '$($Table.Name)'" -Argument ColumnName} - } - $datatype = $Column.DataType - $querytype,$typefmt = $typeinfo[$datatype.Name] - $table = $Column.Parent - $fqtn = "$($table.Parent.Parent.Name).$($table.Parent.Name).$($table.Name)" - $sql = $query[$querytype] -f $table.Schema,$table.Name,$ColumnName, - ($typefmt -f $datatype.Name,$datatype.MaximumLength,$datatype.NumericPrecision,$datatype.NumericScale) - Write-Verbose "SQL: $sql" - @{ - Query = $sql - Database = $table.Parent.Name - ServerInstance = $table.Parent.Parent.Name - } | - Where-Object {$PSCmdlet.ShouldProcess("column $fqtn.$ColumnName","query $($table.RowCount) rows")} | - ForEach-Object {Invoke-Sqlcmd @_} | - ConvertFrom-DataRow.ps1 -} diff --git a/Measure-DbColumnValues.ps1 b/Measure-DbColumnValues.ps1 deleted file mode 100644 index 32a990fc..00000000 --- a/Measure-DbColumnValues.ps1 +++ /dev/null @@ -1,72 +0,0 @@ -<# -.SYNOPSIS -Provides sorted counts of SQL Server column values. - -.INPUTS -Microsoft.SqlServer.Management.Smo.Column to calculate statistics for, -or Microsoft.SqlServer.Management.Smo.Table to select a column from by name. - -.OUTPUTS -System.Management.Automation.PSCustomObject that describes each counted value. - -.FUNCTIONALITY -Database - -.LINK -https://www.powershellgallery.com/packages/SqlServer/ - -.LINK -https://dbatools.io/ -#> - -#Requires -Version 3 -#Requires -Module SqlServer -[CmdletBinding(ConfirmImpact='Medium')][OutputType([Management.Automation.PSCustomObject])] Param( -# An SMO column object associated to the database column to examine. -[Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true,ParameterSetName='Column')] -[Microsoft.SqlServer.Management.Smo.Column] $Column, -# The name of the column to examine in the table associated with the SMO Table object. -[Parameter(Position=0,Mandatory=$true,ParameterSetName='ColumnName')][string] $ColumnName, -# An SMO table object associated to the database to examine. -[Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$true,ParameterSetName='ColumnName')] -[Microsoft.SqlServer.Management.Smo.Table] $Table, -<# -Conditions to be provided as a SQL WHERE clause to filter the column values to examine. -Useful for databases that implement "soft deletes" as specific field values. -#> -[string] $Condition, -# Excludes values with fewer than this number of occurrences. -[int] $MinimumCount -) -Begin -{ - $query = @" -select [{2}] [Value], count(*) [Count] - from [{0}].[{1}] -$(if($Condition){" where $Condition"}) - group by [{2}] -$(if($MinimumCount){"having count(*) > $MinimumCount"}) - order by [Count] desc; -"@ -} -Process -{ - if($Column) {$ColumnName = $Column.Name} - else - { - $Column = $Table.Columns[$ColumnName] - if(!$Column) {ModernConveniences\Stop-ThrowError "Column '$ColumnName' not found in table '$($Table.Name)'" -Argument ColumnName} - } - $table = $Column.Parent - $fqtn = "$($table.Parent.Parent.Name).$($table.Parent.Name).$($table.Name)" - $sql = $query -f $table.Schema,$table.Name,$ColumnName - Write-Verbose "SQL: $sql" - @{ - Query = $sql - Database = $table.Parent.Name - ServerInstance = $table.Parent.Parent.Name - } | - Where-Object {$PSCmdlet.ShouldProcess("column $fqtn.$ColumnName","query $($table.RowCount) rows")} | - ForEach-Object {Invoke-Sqlcmd @_} | - ConvertFrom-DataRow.ps1 -} diff --git a/Measure-DbTable.ps1 b/Measure-DbTable.ps1 deleted file mode 100644 index 7d9aa6f7..00000000 --- a/Measure-DbTable.ps1 +++ /dev/null @@ -1,133 +0,0 @@ -<# -.SYNOPSIS -Provides frequency details about SQL Server table data. - -.INPUTS -Microsoft.SqlServer.Management.Smo.Table to analyze. - -.OUTPUTS -System.Management.Automation.PSCustomObject that describes each table column. - -.FUNCTIONALITY -Database - -.LINK -https://www.powershellgallery.com/packages/SqlServer/ - -.LINK -https://dbatools.io/ - -.EXAMPLE -Get-DbaDbTable -sqli '(localdb)\ProjectsV13' -dat AdventureWorks2016 -tab Production.Product |Measure-DbTable.ps1 - -#TableName : [Production].[Product] -#RowCount : 504 -ProductID : unique, 0 nulls, 504 values: 1 .. 999 -Name : unique, 0 nulls, 504 values: Adjustable Race .. Women's Tights, S -ProductNumber : unique, 0 nulls, 504 values: AR-5381 .. WB-H098 -MakeFlag : bit: 0 nulls, 239 ones, 265 zeros -FinishedGoodsFlag : bit: 0 nulls, 295 ones, 209 zeros -Color : 248 nulls, 9 values: Black .. Yellow -SafetyStockLevel : 0 nulls, 6 values: 4 .. 1000 -ReorderPoint : 0 nulls, 6 values: 3 .. 750 -StandardCost : 0 nulls, 114 values: 0.00 .. 2171.29 -ListPrice : 0 nulls, 103 values: 0.00 .. 3578.27 -Size : 293 nulls, 18 values: 38 .. XL -SizeUnitMeasureCode : CM -WeightUnitMeasureCode : 299 nulls, 2 values: G .. LB -Weight : 299 nulls, 127 values: 2.12 .. 1050.00 -DaysToManufacture : 0 nulls, 4 values: 0 .. 4 -ProductLine : 226 nulls, 4 values: M .. T -Class : 257 nulls, 3 values: H .. M -Style : 293 nulls, 3 values: M .. W -ProductSubcategoryID : 209 nulls, 37 values: 1 .. 37 -ProductModelID : 209 nulls, 119 values: 1 .. 128 -SellStartDate : 0 nulls, 4 values: Apr 30 2008 12:00AM .. May 30 2013 12:00AM -SellEndDate : 406 nulls, 2 values: May 29 2012 12:00AM .. May 29 2013 12:00AM -DiscontinuedDate : null -rowguid : unique, 0 nulls, 504 values: 7A927632-99A4-4F24-ADCE-0062D2D113D9 .. B9EDE243-A6F4-4629-B1D4-FFE1AEDC6DE7 -ModifiedDate : 0 nulls, 2 values: Feb 8 2014 10:01AM .. Feb 8 2014 10:03AM -#> - -#Requires -Version 3 -#Requires -Module SqlServer -[CmdletBinding(ConfirmImpact='Medium')][OutputType([Management.Automation.PSCustomObject])] Param( -# An SMO table object associated to the database to examine. -[Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$true)] -[Microsoft.SqlServer.Management.Smo.Table] $Table, -<# -Conditions to be provided as a SQL WHERE clause to filter the record values to examine. -Useful for databases that implement "soft deletes" as specific field values. -#> -[string] $Condition -) -Begin -{ - function Format-ColumnRange([string]$colname) - {@" -case count([$colname]) - when count(*) then 'not null, ' + - cast(count(distinct [$colname]) as varchar(max)) + ' values: ' + - cast(min([$colname]) as varchar(max)) + ' .. ' + cast(max([$colname]) as varchar(max)) - when 0 then 'null' - else cast(count(*) - count([$colname]) as varchar(max)) + ' nulls, ' + - cast(count(distinct [$colname]) as varchar(max)) + ' values: ' + - cast(min([$colname]) as varchar(max)) + ' .. ' + cast(max([$colname]) as varchar(max)) - end -"@} - filter Format-ColumnCount - { - $colname = $_.Name - switch($_.DataType.Name) - { - {$_ -in 'bit','Flag'} - {@" -, - 'bit: ' + - cast(count(*) - count([$colname]) as varchar(max)) + ' nulls, ' + - cast(sum(cast([$colname] as int)) as varchar(max)) + ' ones, ' + - cast(count([$colname]) - sum(cast([$colname] as int)) as varchar(max)) + ' zeros' - [$colname] -"@} - {$_ -in 'text','ntext','image'} - {@" -, - 'text/image: ' + - case sum(case when [$colname] is null then 1 else 0 end) - when 0 then 'not null' - when count(*) then 'null' - else cast(count(*) - sum(case when [$colname] is null then 1 else 0 end) as varchar(max)) + ' nulls, ' + - cast(sum(case when [$colname] is null then 1 else 0 end) as varchar(max)) + ' values' - end - [$colname] -"@} - default - {@" -, - case count(distinct [$colname]) - when 0 then 'null' - when 1 then cast(min([$colname]) as varchar(max)) - when count(*) then 'unique, ' + $(Format-ColumnRange $colname) - when count([$colname]) then 'nullable unique (no duplicates), ' + $(Format-ColumnRange $colname) - else $(Format-ColumnRange $colname) - end - [$colname] -"@} - } - } - $SOQ = "select '[{0}].[{1}]' #TableName, count(*) #RowCount" - $EOQ = if(!$Condition) {' from [{0}].[{1}];'} else {" from [{0}].[{1}] where $Condition ;"} -} -Process -{ - $sql = "$SOQ $($Table.Columns |Format-ColumnCount) $EOQ" -f $Table.Schema,$Table.Name - Write-Verbose "SQL: $sql" - @{ - Query = $sql - Database = $Table.Parent.Name - ServerInstance = $Table.Parent.Parent.Name - } | - Where-Object {$PSCmdlet.ShouldProcess("column $Table","query $($Table.RowCount) rows")} | - ForEach-Object {Invoke-Sqlcmd @_} | - ConvertFrom-DataRow.ps1 -} diff --git a/New-DbProviderObject.ps1 b/New-DbProviderObject.ps1 deleted file mode 100644 index 7948a60d..00000000 --- a/New-DbProviderObject.ps1 +++ /dev/null @@ -1,108 +0,0 @@ -<# -.SYNOPSIS -Create a common database object. - -.INPUTS -System.String to initialize the database object. - -.OUTPUTS -System.Data.Common.DbCommand (e.g. System.Data.SqlClient.SqlCommand) or -System.Data.Common.DbConnection (e.g. System.Data.SqlClient.SqlConnection) or -System.Data.Common.DbConnectionStringBuilder (e.g. System.Data.SqlClient.SqlConnectionStringBuilder), -as requested. - -.FUNCTIONALITY -Database - -.LINK -https://msdn.microsoft.com/library/system.data.common.dbproviderfactories.aspx - -.EXAMPLE -New-DbProviderObject.ps1 ConnectionStringBuilder 'Server=(localdb)\ProjectsV13;Database=AdventureWorks;Integrated Security=SSPI;Encrypt=True' - -Key Value ---- ----- -Data Source (localdb)\ProjectsV13 -Initial Catalog AdventureWorks -Integrated Security True -Encrypt True - -.EXAMPLE -$conn = New-DbProviderObject.ps1 Connection $connstr -Open - -($conn contains an open DbConnection object.) - -.EXAMPLE -$cmd = New-DbProviderObject.ps1 Command -ConnectionString $connstr -Provider Odbc -StoredProcedure -OpenConnection - -($cmd contains an OdbcCommand with a CommandType of StoredProcedure and an open connection to $connstr.) -#> - -#Requires -Version 7 -[CmdletBinding()][OutputType([Data.Common.DbCommand])] -[OutputType([Data.Common.DbConnection])][OutputType([Data.Common.DbConnectionStringBuilder])] Param( -# The type of object to create. -[ValidateSet('Command','Connection','ConnectionStringBuilder')] -[Parameter(Mandatory=$true,Position=0)][string] $TypeName, -<# -A value to initialize the object with, such as CommandText for a Command object, or -a ConnectionString for a Connection or ConnectionStringBuilder. -#> -[Parameter(Position=2,ValueFromPipeline=$true)][Alias('Value')][string] $InitialValue, -# The DbProviderFactory subclass to use to create the object. -[ValidateSet('Odbc','OleDb','Oracle','Sql')][string] $Provider = 'Sql', -<# -A connection string to use (when creating a Command object). -No connection will be made if not specified. -#> -[Parameter(Position=3)][Alias('CS')][string] $ConnectionString, -<# -Sets the CommandType property of a Command object to StoredProcedure. -Ignored for other objects. -#> -[switch] $StoredProcedure, -# Opens the Connection object (or Command connection) if an InitialValue was provided, ignored otherwise. -[switch] $OpenConnection -) -Process -{ - $factory = switch($Provider) - { - Odbc {[Data.Odbc.OdbcFactory]::Instance} - OleDb {[Data.OleDb.OleDbFactory]::Instance} - Oracle {[Data.OracleClient.OracleClientFactory]::Instance} - Sql {[Data.SqlClient.SqlClientFactory]::Instance} - } - $value = switch($TypeName) - { - Command {$factory.CreateCommand()} - Connection {$factory.CreateConnection()} - ConnectionStringBuilder {$factory.CreateConnectionStringBuilder()} - } - if($InitialValue) - { - switch($TypeName) - { - Command - { - $value.CommandText = $InitialValue - } - Connection - { - $value.ConnectionString = $InitialValue - if($OpenConnection) {$value.Open()} - } - ConnectionStringBuilder - { # PowerShell must use the method form - $value.set_ConnectionString($InitialValue) - } - } - } - if($TypeName -eq 'Command') - { - if($StoredProcedure) {$obj.CommandType = 'StoredProcedure'} - if($ConnectionString) - {$obj.Connection = New-DbProviderObject.ps1 Connection $ConnectionString -Provider:$Provider -OpenConnection:$OpenConnection} - } - return $value -} diff --git a/Repair-DatabaseConstraintNames.ps1 b/Repair-DatabaseConstraintNames.ps1 deleted file mode 100644 index 7954e19f..00000000 --- a/Repair-DatabaseConstraintNames.ps1 +++ /dev/null @@ -1,134 +0,0 @@ -<# -.SYNOPSIS -Finds database constraints with system-generated names and gives them deterministic names. - -.FUNCTIONALITY -Database - -.LINK -Use-SqlcmdParams.ps1 - -.LINK -Invoke-Sqlcmd - -.LINK -https://www.databasejournal.com/features/mssql/article.php/1570801/Beware-of-the-System-Generated-Constraint-Name.htm - -.EXAMPLE -Repair-DatabaseConstraintNames.ps1 SqlServerName DatabaseName -Update - -WARNING: Renamed 10 defaults -#> - -#Requires -Version 3 -#Requires -Module SqlServer -[CmdletBinding(SupportsShouldProcess=$true)][OutputType([void])] Param( -# The name of a server (and optional instance) to connect to. -[Parameter(ParameterSetName='ByConnectionParameters',Position=0,Mandatory=$true)][string] $ServerInstance, -# The the database to connect to on the server. -[Parameter(ParameterSetName='ByConnectionParameters',Position=1,Mandatory=$true)][string] $Database, -# Specifies a connection string to connect to the server. -[Parameter(ParameterSetName='ByConnectionString',Mandatory=$true)][Alias('ConnStr','CS')][string]$ConnectionString, -# Specifies an SMO Database object to query. -[Parameter(ParameterSetName='ByDatabase',Mandatory=$true)] -[Microsoft.SqlServer.Management.Smo.Database] $SmoDatabase, -# The connection string name from the ConfigurationManager to use. -[Parameter(ParameterSetName='ByConnectionName',Mandatory=$true)][string]$ConnectionName, -# Update the database when present, otherwise simply outputs the changes as script. -[switch] $Update -) - -Use-SqlcmdParams.ps1 - -function Resolve-SqlcmdResult -{ -<# -.SYNOPSIS -Executes SQL that generates SQL strings, and optionally executes the generated SQL. - -.PARAMETER Action -Descriptive text for the commands produced, with two format arguments: -0: Verb tense, e.g. 'Renam{0:e;ing;ed}' -1: Command count - -.PARAMETER Query -A SQL query that produces a single-column result set, named "command", containing -executable SQL. -#> - [CmdletBinding(SupportsShouldProcess=$true)] Param([string]$Action,[string]$Query) - $count,$i = 0,0 - [string[]]$commands = Invoke-Sqlcmd $Query |Select-Object -ExpandProperty command - if(!$commands){return} - $max,$act = ($commands.Count/100),($Action -f -1,$commands.Count) - Write-Verbose ($Action -f 1,$commands.Count) - foreach($command in $commands) - { - Write-Progress $act "Execute command #$i" -CurrentOperation $command -PercentComplete ($i++/$max) - if(!$Update) {$command} - elseif($PSCmdlet.ShouldProcess($command,'execute')) {Invoke-Sqlcmd $command; $count++} - } - Write-Progress ($action -f 0,$i) -Completed - if($count) {Write-Warning ($Action -f 0,$count)} -} - -function Repair-DefaultName -{ - @{ - Action = 'Renam{0:e;ing;ed} {1} defaults' - Query = @" -select 'if object_id(''' + quotename(schema_name(schema_id)) +'.'+ quotename(name) - +''') is not null exec sp_rename '''+quotename(schema_name(schema_id))+'.'+quotename(name) - +''', ''DF_'+object_name(parent_object_id)+'_'+col_name(parent_object_id,parent_column_id) - +''', ''OBJECT'';' [command] - from sys.default_constraints - where name like 'DF._._%' escape '.' - and name <> 'DF_'+object_name(parent_object_id)+'_'+col_name(parent_object_id,parent_column_id) - and objectproperty(parent_object_id,'IsUserTable') = 1 -- excludes 'sys' schema, &c - and objectproperty(parent_object_id,'IsMsShipped') = 0 -- excludes dtproperties, &c - and parent_object_id not in (select major_id from sys.extended_properties - where class = 1 and minor_id = 0 and name = 'microsoft_database_tools_support'); -- excludes sysdiagrams, &c -"@ - } |ForEach-Object {Resolve-SqlcmdResult @_} -} - -function Repair-PrimaryKeyName -{ - @{ - Action = 'Renam{0:e;ing;ed} {1} primary keys' - Query = @" -select 'if object_id(''' + quotename(schema_name(schema_id)) +'.'+ quotename(name) - +''') is not null exec sp_rename '''+quotename(schema_name(schema_id))+'.'+quotename(name) - +''', '''+'PK_'+object_name(parent_object_id)+''', ''OBJECT'';' command - from sys.key_constraints - where name like 'PK._._%' escape '.' - and name <> 'PK_'+object_name(parent_object_id) - and objectproperty(parent_object_id,'IsUserTable') = 1 -- excludes 'sys' schema, &c - and objectproperty(parent_object_id,'IsMsShipped') = 0 -- excludes dtproperties, &c - and parent_object_id not in (select major_id from sys.extended_properties - where class = 1 and minor_id = 0 and name = 'microsoft_database_tools_support'); -- excludes sysdiagrams, &c -"@ - } |ForEach-Object {Resolve-SqlcmdResult @_} -} - -function Repair-ForeignKeyName -{ #TODO: Mitigate possible deterministic naming collisions. - @{ - Action = 'Renam{0:e;ing;ed} {1} foreign keys' - Query = @" -select 'if object_id(''' + quotename(schema_name(schema_id)) +'.'+ quotename(name) - +''') is not null exec sp_rename '''+quotename(schema_name(schema_id))+'.'+quotename(name) - +''', '''+'FK_'+object_name(parent_object_id)+'_'+object_name(referenced_object_id)+''', ''OBJECT'';' command - from sys.foreign_keys - where name like 'FK._._%' escape '.' - and name <> 'FK_'+object_name(parent_object_id) - and objectproperty(parent_object_id,'IsUserTable') = 1 -- excludes 'sys' schema, &c - and objectproperty(parent_object_id,'IsMsShipped') = 0 -- excludes dtproperties, &c - and parent_object_id not in (select major_id from sys.extended_properties - where class = 1 and minor_id = 0 and name = 'microsoft_database_tools_support'); -- excludes sysdiagrams, &c -"@ - } |ForEach-Object {Resolve-SqlcmdResult @_} -} - -Repair-DefaultName -Repair-PrimaryKeyName -Repair-ForeignKeyName diff --git a/Repair-DatabaseUntrustedConstraints.ps1 b/Repair-DatabaseUntrustedConstraints.ps1 deleted file mode 100644 index d6347fe3..00000000 --- a/Repair-DatabaseUntrustedConstraints.ps1 +++ /dev/null @@ -1,106 +0,0 @@ -<# -.SYNOPSIS -Finds database constraints that have been incompletely re-enabled. - -.FUNCTIONALITY -Database - -.LINK -Use-SqlcmdParams.ps1 - -.LINK -Invoke-Sqlcmd - -.LINK -https://www.brentozar.com/blitz/foreign-key-trusted/ - -.EXAMPLE -Repair-DatabaseUntrustedConstraints.ps1 SqlServerName DatabaseName -Update - -WARNING: Checked 2 constraints -#> - -#Requires -Version 3 -#Requires -Module SqlServer -[CmdletBinding(SupportsShouldProcess=$true)][OutputType([void])] Param( -# The name of a server (and optional instance) to connect to. -[Parameter(ParameterSetName='ByConnectionParameters',Position=0,Mandatory=$true)][string] $ServerInstance, -# The the database to connect to on the server. -[Parameter(ParameterSetName='ByConnectionParameters',Position=1,Mandatory=$true)][string] $Database, -# Specifies a connection string to connect to the server. -[Parameter(ParameterSetName='ByConnectionString',Mandatory=$true)][Alias('ConnStr','CS')][string]$ConnectionString, -# Specifies an SMO Database object to query. -[Parameter(ParameterSetName='ByDatabase',Mandatory=$true)] -[Microsoft.SqlServer.Management.Smo.Database] $SmoDatabase, -# The connection string name from the ConfigurationManager to use. -[Parameter(ParameterSetName='ByConnectionName',Mandatory=$true)][string]$ConnectionName, -# Update the database when present, otherwise simply outputs the changes as script. -[switch] $Update -) - -Use-SqlcmdParams.ps1 - -function Resolve-SqlcmdResult -{ -<# -.SYNOPSIS -Executes SQL that generates SQL strings, and optionally executes the generated SQL. - -.PARAMETER Action -Descriptive text for the commands produced, with two format arguments: -0: Verb tense, e.g. 'Renam{0:e;ing;ed}' -1: Command count - -.PARAMETER Query -A SQL query that produces a single-column result set, named "command", containing -executable SQL. -#> - [CmdletBinding(SupportsShouldProcess=$true)] Param([string]$Action,[string]$Query) - $count,$i = 0,0 - [string[]]$commands = Invoke-Sqlcmd $Query |Select-Object -ExpandProperty command - if(!$commands){return} - $max,$act = ($commands.Count/100),($Action -f -1,$commands.Count) - Write-Verbose ($Action -f 1,$commands.Count) - foreach($command in $commands) - { - Write-Progress $act "Execute command #$i" -CurrentOperation $command -PercentComplete ($i++/$max) - if(!$Update) {$command} - elseif($PSCmdlet.ShouldProcess($command,'execute')) {Invoke-Sqlcmd $command; $count++} - } - Write-Progress ($action -f 0,$i) -Completed - if($count) {Write-Warning ($Action -f 0,$count)} -} - -function Repair-DefaultName -{ - @{ - Action = 'Check{0:;ing;ed} {1} constraints' - Query = @" -select 'if exists (select * from sys.foreign_keys where object_id = object_id(''' - + quotename(schema_name(schema_id)) - + '.' + quotename(object_name(object_id)) - + ''') and is_not_trusted = 1) alter table ' - + quotename(object_schema_name(parent_object_id)) - + '.' + quotename(object_name(parent_object_id)) - + ' with check check constraint ' + quotename(name) + '; -- FK' command - from sys.foreign_keys - where is_not_trusted = 1 - and is_not_for_replication = 0 - and is_disabled = 0 - union all -select 'if exists (select * from sys.foreign_keys where object_id = object_id(''' - + quotename(schema_name(schema_id)) - + '.' + quotename(object_name(object_id)) - + ''') and is_not_trusted = 1) alter table ' - + quotename(object_schema_name(parent_object_id)) - + '.' + quotename(object_name(parent_object_id)) - + ' with check check constraint ' + quotename(name) + ';' command - from sys.check_constraints - where is_not_trusted = 1 - and is_not_for_replication = 0 - and is_disabled = 0; -"@ - } |ForEach-Object {Resolve-SqlcmdResult @_} -} - -Repair-DefaultName diff --git a/Send-SqlReport.ps1 b/Send-SqlReport.ps1 deleted file mode 100644 index ee8ad5c9..00000000 --- a/Send-SqlReport.ps1 +++ /dev/null @@ -1,175 +0,0 @@ -<# -.SYNOPSIS -Execute a SQL statement and email the results. - -.FUNCTIONALITY -Database - -.LINK -Use-SqlcmdParams.ps1 - -.LINK -Send-MailMessage - -.LINK -Invoke-Sqlcmd -#> - -#Requires -Version 3 -#Requires -Module SqlServer -[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='None')][OutputType([void])] Param( -# The email subject. -[Parameter(Position=0,Mandatory=$true)][string]$Subject, -# The email address(es) to send the results to. -[Parameter(Position=1,Mandatory=$true)][string[]]$To, -# The SQL statement to execute. -[Parameter(Position=2,Mandatory=$true)][string]$Sql, -# The name of a server (and optional instance) to connect and use for the query. -[Parameter(ParameterSetName='ByConnectionParameters',Position=3)][string]$ServerInstance, -# The the database to connect to on the server. -[Parameter(ParameterSetName='ByConnectionParameters',Position=4)][string]$Database, -# Specifies a connection string to connect to the server. -[Parameter(ParameterSetName='ByConnectionString',Mandatory=$true)][string]$ConnectionString, -# Specifies an SMO Database object to query. -[Parameter(ParameterSetName='ByDatabase',Mandatory=$true)] -[Microsoft.SqlServer.Management.Smo.Database] $SmoDatabase, -# The connection string name from the ConfigurationManager to use when executing the query. -[Parameter(ParameterSetName='ByConnectionName',Mandatory=$true)][string]$ConnectionName, -# The subject line for the email when no data is returned. -[string]$EmptySubject, -<# -The from address to use for the email. -The default is to use $PSEmailServer. -If that is missing, it will be populated by the value from the -configuration value: - - - - - - - - - -(If enableSsl is set to true, SSL will be used to send the report.) -#> -[string]$From, -# The optional table caption to add. -[string]$Caption, -<# -A UNC path to a .csv or .tsv file writable by the script and readable by the email recipient to output the data to, -which will be linked in the email rather than included in the email body. - -Supports a format template for the current date and time (e.g. {0:yyyyMMddHHmmss}). -#> -[string]$ReportFile, -# The timeout to use for the query, in seconds. The default is 90. -[Alias('Timeout')][int]$QueryTimeout= 90, -# HTML content to insert into the email before the query results. -[string]$PreContent= ' ', -# HTML content to insert into the email after the query results. -[string]$PostContent= ' ', -# The email address(es) to CC the results to. -[string[]]$Cc, -# The email address(es) to BCC the results to. -[string[]]$Bcc, -# The priority of the email, one of: High, Low, Normal -[Net.Mail.MailPriority]$Priority, -<# -Indicates that SSL should be used when sending the message. - -(See the From parameter for an alternate SSL flag.) -#> -[switch]$UseSsl, -# The URL of the Seq server to log to. -[uri]$SeqUrl = $PSDefaultParameterValues['SeqLogger\Send-SeqEvent:Server'] -) - -Use-NetMailConfig.ps1 -Use-SqlcmdParams.ps1 -if($SeqUrl){SeqLogger\Use-SeqServer $SeqUrl} - -# use the default From host for emails without a host -$mailhost = ([Net.Mail.MailAddress]$PSDefaultParameterValues['Send-MailMessage:From']).Host |Out-String -if($mailhost) -{ - $To = $To |ForEach-Object { if($_ -like '*@*'){$_}else{"$_@$mailhost"} } # allow username-only emails - $Cc = $Cc |ForEach-Object { if($_ -like '*@*'){$_}elseif($_){"$_@$mailhost"} } # allow username-only emails - if($Bcc) { $Bcc = $Bcc |ForEach-Object { if($_ -like '*@*'){$_}else{"$_@$mailhost"} } } # allow username-only emails -} - -$Msg = @{ - To = $To - Subject = $Subject - BodyAsHtml = $true - SmtpServer = $PSEmailServer -} -if($From) { $Msg.From= $From } -if($Cc) { $Msg.Cc= $Cc } -if($Bcc) { $Msg.Bcc= $Bcc } -if($Priority) { $Msg.Priority= $Priority } -if($UseSsl) { $Msg.UseSsl = $true } - -try -{ - $query = @{ Query = $Sql } - [psobject[]]$data = Invoke-Sqlcmd @query -ErrorAction Stop |ConvertFrom-DataRow.ps1 - $data |Format-Table |Out-String |Write-Verbose - if(!$data -or $data.Length -eq 0) # no rows - { - Write-Verbose "No rows returned." - if($SeqUrl) { SeqLogger\Send-SeqEvent 'No rows returned for {Subject}' @{Subject=$Subject} -Level Information } - if($EmptySubject) { $Msg.Subject = $EmptySubject; Send-MailMessage @Msg } - return - } - Write-Verbose "$($data.Length) rows returned." - if($ReportFile) - { # convert the table into a tsv/csv file and link to it - $ReportFile = $ReportFile -f (Get-Date) - if($ReportFile -like '*.tsv') {$data |Export-Csv $ReportFile -Delimiter "`t" -Encoding UTF8 -NoTypeInformation} - else {$data |Export-Csv $ReportFile -Encoding UTF8 -NoTypeInformation} - $ReportFile = (Resolve-Path $ReportFile).ProviderPath - if(([uri]$ReportFile).IsUnc) - { - $Msg.Add('Body',@" -$PreContent -$([Security.SecurityElement]::Escape((Split-Path $ReportFile -Leaf))) -$PostContent -"@) - } - else - { - $Msg.Add('Body',"$PreContent`n$PostContent") - $Msg.Add('Attachments',$ReportFile) - } - } - else - { # convert the table into HTML (select away the add'l properties the DataTable adds), add some Outlook 2007-compat CSS, email it - $tableFormat = @{OddRowBackground='#EEE'} - if($Caption){$tableFormat.Add('Caption',$Caption)} - $Msg.Add('Body',($data | - ConvertTo-Html -PreContent $PreContent -PostContent $PostContent -Head '' | - ModernConveniences\Format-HtmlDataTable @tableFormat | - Out-String)) - } - if($PSCmdlet.ShouldProcess("Message:`n$(New-Object PSObject -Property $Msg|Format-List|Out-String)`n",'Send message')) - { Send-MailMessage @Msg } # splat the arguments hashtable -} -catch # report problems -{ - Write-Warning $_ - if($SeqUrl) { SeqLogger\Send-SeqScriptEvent 'Reporting' -InvocationScope 2 } - # consciously omitting Cc & Bcc - $Msg = @{ - To = $To - Subject = "$Subject [Error]" - BodyAsHtml = $false - SmtpServer = $PSEmailServer - Body = $_ - } - if($From) { $Msg.From= $From } - if($Priority) { $Msg.Priority= $Priority } - if($PSCmdlet.ShouldProcess("Message:`n$(New-Object PSObject -Property $Msg|Format-List|Out-String)`n",'Send message')) - { Send-MailMessage @Msg } - ModernConveniences\Stop-ThrowError "$_" -OperationContext $_ -} diff --git a/Test-ConnectionString.ps1 b/Test-ConnectionString.ps1 deleted file mode 100644 index 9c438a74..00000000 --- a/Test-ConnectionString.ps1 +++ /dev/null @@ -1,87 +0,0 @@ -<# -.SYNOPSIS -Test a given connection string and provide details about the connection. - -.OUTPUTS -System.Management.Automation.PSObject containing properties about the connection. - -.FUNCTIONALITY -Database - -.EXAMPLE -Test-ConnectionString.ps1 'Server=(localdb)\ProjectsV13;Integrated Security=SSPI;Encrypt=True' -Details - -ServerName : SERVERNAME\LOCALDB#DCCC9EEC -AppName : Core Microsoft SqlClient Data Provider -LocalRunAsAdmin : False -ConnectingAsUser : SERVERNAME\username -SqlInstance : (localdb)\ProjectsV13 -LocalWindows : 10.0.19045.0 -InstanceName : LOCALDB#DCCC9EEC -DatabaseName : master -AuthType : Windows Authentication -Integrated Security : True -Data Source : (localdb)\ProjectsV13 -ConnectSuccess : True -Workstation ID : SERVERNAME -AuthScheme : NTLM -ComputerName : SERVERNAME -Encrypt : True -LocalCLR : -TcpPort : 1433 -LocalPowerShell : 7.3.9 -NetBiosName : SERVERNAME -Edition : Express Edition (64-bit) -IPAddress : 192.168.1.223 -ServerTime : 2023-11-10 12:14:09 -DomainName : WORKGROUP -Server : [(localdb)\ProjectsV13] -IsPingable : True -LocalEdition : Core -Pooling : True -LocalDomainUser : False -MachineName : SERVERNAME -SqlVersion : 13.0.4001 -LocalSMOVersion : 17.100.0.0 -#> - -#Requires -Version 3 -#Requires -Modules dbatools -[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText','', -Justification='The data source is plaintext. SecureString benefits may be in dispute: ')] -[CmdletBinding()][OutputType([psobject])] Param( -[Parameter(Position=0,Mandatory=$true)][string] $ConnectionString, -[switch] $Details -) -Process -{ - try - { - if($Details) - { - $csb = New-DbaConnectionStringBuilder -ConnectionString $ConnectionString - $server = Connect-DbaInstance -ConnectionString $ConnectionString - $conn = ModernConveniences\Join-Keys -ReferenceObject (New-Object Collections.Hashtable $csb) ` - -InputObject (Test-DbaConnection $csb.DataSource -SkipPSRemoting |ModernConveniences\ConvertTo-OrderedDictionary) - $info = Invoke-DbaQuery -SqlInstance $server -As PSObject -Query @' -select @@ServerName [ServerName], db_name() [DatabaseName], - serverproperty('ComputerNamePhysicalNetBIOS') [ComputerName], - serverproperty('MachineName') [MachineName], - serverproperty('InstanceName') [InstanceName], - current_timestamp [ServerTime], - serverproperty('Edition') [Edition], - app_name() [AppName]; -'@ |ModernConveniences\ConvertTo-OrderedDictionary - [void] $info.Add('Server', $server) - $connInfo = ModernConveniences\Join-Keys $conn $info - if($connInfo.Contains('Password')) {$connInfo['Password'] = ConvertTo-SecureString $connInfo['Password'] -AsPlainText -Force} - return [pscustomobject]$connInfo - } - else - { - return Invoke-DbaQuery -SqlInstance (Connect-DbaInstance -ConnectionString $ConnectionString) ` - -Query 'select cast(1 as bit) Success;' |ConvertFrom-DataRow.ps1 -AsValues - } - } - catch {return $false} -} diff --git a/Use-DbInstance.ps1 b/Use-DbInstance.ps1 deleted file mode 100644 index 33d86b77..00000000 --- a/Use-DbInstance.ps1 +++ /dev/null @@ -1,23 +0,0 @@ -<# -.SYNOPSIS -Sets a default dbatools connection, using a caller script's parameter values when available. - -.FUNCTIONALITY -Database -#> - -#Requires -Version 7 -using module dbatools -[CmdletBinding()] Param( -# The server to use, by name or constructed via Connect-DbaInstance. -[Parameter(Position=0)][Alias('Parent','ServerInstance')][DbaInstanceParameter] $SqlInstance = - (Get-Variable PSBoundParameters -ValueOnly -Scope 1 |ForEach-Object {$_ ? $_['SqlInstance'] : $null}), -# The the database to connect to on the server. -[Parameter(Position=1)][Alias('Name')][string] $Database = - (Get-Variable PSBoundParameters -ValueOnly -Scope 1 |ForEach-Object {$_ ? $_['Database'] : $null}), -# Sets a default output type for Invoke-DbaQuery. -[ValidateSet('DataSet','DataTable','DataRow','PSObject','PSObjectArray','SingleValue')][string] $As -) -ModernConveniences\Set-ParameterDefault Invoke-DbaQuery SqlInstance $SqlInstance -Scope 1 -if($Database) {ModernConveniences\Set-ParameterDefault Invoke-DbaQuery Database $Database -Scope 1} -if($As) {ModernConveniences\Set-ParameterDefault Invoke-DbaQuery As $As -Scope 1} diff --git a/test/Add-GitHubMetadata.Tests.ps1 b/test/Add-GitHubMetadata.Tests.ps1 deleted file mode 100644 index 76a17b0a..00000000 --- a/test/Add-GitHubMetadata.Tests.ps1 +++ /dev/null @@ -1,135 +0,0 @@ -<# -.SYNOPSIS -Tests Adds GitHub Linguist overrides to a repo's .gitattributes. -#> - -$basename = "$(($MyInvocation.MyCommand.Name -split '\.',2)[0])." -$skip = !(Test-Path .changes -Type Leaf) ? $false : - !@(Get-Content .changes |Get-Item |Select-Object -ExpandProperty Name |Where-Object {$_.StartsWith($basename)}) -if($skip) {Write-Information "No changes to $basename" -infa Continue} -Describe 'Add-GitHubMetadata' -Tag Add-GitHubMetadata -Skip:$skip { - BeforeAll { - if(!(Get-Module -List Detextive)) {Install-Module Detextive -Force} - $scriptsdir,$sep = (Split-Path $PSScriptRoot),[io.path]::PathSeparator - if($scriptsdir -notin ($env:Path -split $sep)) {$env:Path += "$sep$scriptsdir"} - if(!(git config --global user.email)) {git config --global user.email "test@example.com"} - if(!(git config --global user.name)) {git config --global user.name "Test User"} - } - BeforeEach { - Push-Location (mkdir "TestDrive:\$(New-Guid)") - git init |Write-Information -infa Continue - '' |Out-File nothing - git add -A - git commit -m first |Write-Information -infa Continue - git status |Write-Information -infa Continue - git shortlog |Write-Information -infa Continue - } - AfterEach { - if("$PWD" -match "\A$([regex]::Escape($TestDrive))") {Pop-Location} - } - Context 'Add basic GitHub metadata' ` - -Tag AddGitHubMetadata,Add,GitHubMetadata,GitHub,Metadata,Readme,EditorConfig,CodeOwners,Linguist { - It "Should create README.md, .editorconfig, CODEOWNERS, and .gitattributes (Linguist)" { - '.gitattributes' |Should -Not -Exist -Because 'a new repo should not have a .gitattributes' - '.editorconfig' |Should -Not -Exist -Because 'a new repo should not have an .editorconfig' - '.github\CODEOWNERS' |Should -Not -Exist -Because 'a new repo should not have a CODEOWNERS' - 'README.md' |Should -Not -Exist -Because 'a new repo should not have a readme' - Add-GitHubMetadata.ps1 -DefaultOwner 'test@example.com' -NoWarnings - '.gitattributes' |Should -Exist - '.gitattributes' |Should -FileContentMatchExactly '\*\*/packages/\*\* linguist-vendored' ` - -Because 'default Linguist settings should be added' - '.editorconfig' |Should -Exist - '.editorconfig' |Should -FileContentMatchMultilineExactly '# defaults\r?\n\[\*\]\r?\nindent_style' ` - -Because 'default .editorconfig settings should be added' - '.github\CODEOWNERS' |Should -Exist - '.github\CODEOWNERS' |Should -FileContentMatchExactly '\* test@example.com' - 'README.md' |Should -Exist - 'README.md' |Should -FileContentMatchMultilineExactly '\A.+\r?\n=+\r?\n' ` - -Because 'the readme should include a CommonMark Setext header' - } - } - Context 'Set Linguist rules' -Tag AddGitHubMetadata,Add,GitHubMetadata,GitHub,Metadata,Linguist { - It "Should set Linguist rules in .gitattributes" -Tag Linguist { - Add-GitHubMetadata.ps1 -VendorCode openapi/*.cs -DocumentationCode docs/* ` - -GeneratedCode *.svg -NoWarnings - '.gitattributes' |Should -FileContentMatchExactly '^openapi/\*\.cs linguist-vendored$' - '.gitattributes' |Should -FileContentMatchExactly '^docs/\* linguist-documentation$' - '.gitattributes' |Should -FileContentMatchExactly '^\*\.svg linguist-generated=true$' - } - } - Context 'Set .editorconfig rules' -Tag AddGitHubMetadata,Add,GitHubMetadata,GitHub,Metadata,EditorConfig { - It "Should set .editorconfig rules" { - Add-GitHubMetadata.ps1 -DefaultUsesTabs -DefaultIndentSize 6 -DefaultLineEndings cr ` - -DefaultCharset latin1 -DefaultKeepTrailingSpace -DefaultNoFinalNewLine -NoWarnings - '.editorconfig' |Should -FileContentMatchExactly '^indent_style\s*=\s*tab$' - '.editorconfig' |Should -FileContentMatchExactly '^indent_size\s*=\s*6$' - '.editorconfig' |Should -FileContentMatchExactly '^tab_width\s*=\s*6$' - '.editorconfig' |Should -FileContentMatchExactly '^end_of_line\s*=\s*cr$' - '.editorconfig' |Should -FileContentMatchExactly '^charset\s*=\s*latin1$' - '.editorconfig' |Should -FileContentMatchExactly '^trim_trailing_whitespace\s*=\s*false$' - '.editorconfig' |Should -FileContentMatchExactly '^insert_final_newline\s*=\s*false$' - } - } - Context 'Set CODEOWNERS' -Tag AddGitHubMetadata,Add,GitHubMetadata,GitHub,Metadata,CodeOwners { - It "Should set specific CODEOWNERS by pattern" { - Add-GitHubMetadata.ps1 -DefaultOwner zaphodb@example.com -Owners @{ - 'sql/*' = 'eddie@example.com','marvin@example.com' - 'docs/*' = 'fordp@example.com' - } -NoWarnings - '.github/CODEOWNERS' |Should -FileContentMatchExactly '^\* zaphodb@example\.com$' - '.github/CODEOWNERS' |Should -FileContentMatchExactly '^sql/\* eddie@example\.com marvin@example\.com$' - '.github/CODEOWNERS' |Should -FileContentMatchExactly '^docs/\* fordp@example\.com$' - } - } - Context 'Set templates' -Tag AddGitHubMetadata,Add,GitHubMetadata,GitHub,Metadata,Template { - It "Should set issue template" -Skip:$([bool](Get-Variable psEditor -EA Ignore)) { - '.github\ISSUE_TEMPLATE.md' |Should -Not -Exist -Because 'a new repo should not have a ISSUE_TEMPLATE.md' - $content = 'Thanks for submitting an issue' - Add-GitHubMetadata.ps1 -IssueTemplate $content -NoWarnings - '.github\ISSUE_TEMPLATE.md' |Should -FileContentMatchMultilineExactly "\A$([regex]::Escape($content))\r?\Z" - } - It "Should set pull request template" -Skip:$([bool](Get-Variable psEditor -EA Ignore)) { - '.github\PULL_REQUEST_TEMPLATE.md' |Should -Not -Exist -Because 'a new repo should not have a PULL_REQUEST_TEMPLATE.md' - $content = 'Thanks for submitting a pull request' - Add-GitHubMetadata.ps1 -PullRequestTemplate $content -NoWarnings - '.github\PULL_REQUEST_TEMPLATE.md' |Should -FileContentMatchMultilineExactly "\A$([regex]::Escape($content))\r?\Z" - } - It "Should set contributing guidelines" -Skip:$([bool](Get-Variable psEditor -EA Ignore)) {` - '.github\CONTRIBUTING.md' |Should -Not -Exist -Because 'a new repo should not have a CONTRIBUTING.md' - $content,$file = 'Thanks for your interest in contributing, here are the guidelines for the project', - [io.path]::GetTempFileName() - $content |Out-File $file utf8BOM - Add-GitHubMetadata.ps1 -ContributingFile $file -NoWarnings - '.github\CONTRIBUTING.md' |Should -FileContentMatchMultilineExactly "\A$([regex]::Escape($content))\r?\Z" - } - It "Should set license" -Skip:$([bool](Get-Variable psEditor -EA Ignore)) { - 'LICENSE.md' |Should -Not -Exist -Because 'a new repo should not have a LICENSE.md' - $content,$file = 'Thanks for using this project, here are the terms of use',[io.path]::GetTempFileName() - $content |Out-File $file utf8BOM - Add-GitHubMetadata.ps1 -LicenseFile $file -NoWarnings - 'LICENSE.md' |Should -FileContentMatchMultilineExactly "\A$([regex]::Escape($content))\r?\Z" - } - It "Should set VSCode extension recommendations" -Skip:$([bool](Get-Variable psEditor -EA Ignore)) { - '.vscode\settings.json' |Should -Not -Exist -Because 'a new repo should not have VSCode settings' - Add-GitHubMetadata.ps1 -VsCodeExtensionRecommendations - '.vscode\settings.json' |Should -Exist - $settings = Get-Content '.vscode\settings.json' -Raw | - ConvertFrom-Json - $settings |Should -BeOfType pscustomobject - ,$settings.recommendations |Should -BeOfType array - $settings.recommendations |Should -Contain yzhang.markdown-all-in-one - $settings.recommendations |Should -Contain EditorConfig.EditorConfig - } - It "Should set VSCode Prettier disable" -Skip:$([bool](Get-Variable psEditor -EA Ignore)) { - '.vscode\settings.json' |Should -Not -Exist -Because 'a new repo should not have VSCode settings' - Add-GitHubMetadata.ps1 -VSCodeDisablePrettierForMarkdown - '.vscode\settings.json' |Should -Exist - $settings = Get-Content '.vscode\settings.json' -Raw | - ConvertFrom-Json - $settings |Should -BeOfType pscustomobject - $settings.'prettier.disableLanguages' |Should -Be @('markdown') - $settings.'[markdown]' |Should -BeOfType pscustomobject - $settings.'[markdown]'.'editor.defaultFormatter' |Should -BeExactly 'yzhang.markdown-all-in-one' - } - } -} diff --git a/test/Convert-ChocolateyToWinget.Tests.ps1 b/test/Convert-ChocolateyToWinget.Tests.ps1 index c54fcbd6..ae7fd76b 100644 --- a/test/Convert-ChocolateyToWinget.Tests.ps1 +++ b/test/Convert-ChocolateyToWinget.Tests.ps1 @@ -3,6 +3,7 @@ Tests Change from managing various packages with Chocolatey to WinGet. #> +return #TODO: Maybe try to fix? $basename = "$(($MyInvocation.MyCommand.Name -split '\.',2)[0])." $skip = !(Test-Path .changes -Type Leaf) ? $false : !@(Get-Content .changes |Get-Item |Select-Object -ExpandProperty Name |Where-Object {$_.StartsWith($basename)}) @@ -14,8 +15,8 @@ Describe 'Convert-ChocolateyToWinget' -Tag Convert-ChocolateyToWinget -Skip:$ski } Context 'Change from managing various packages with Chocolatey to WinGet' ` -Tag ConvertChocolateyToWinget,Convert,Chocolatey,Winget ` - -Skip:(!(([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).` - IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))) { + -Skip:($IsWindows ? !(([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).` + IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) : $true) { It 'Should convert chocolatey packages to winget' { Mock choco { if($args.Count -gt 1 -and $args[0] -eq 'list') diff --git a/test/Export-DatabaseScripts.Tests.ps1 b/test/Export-DatabaseScripts.Tests.ps1 deleted file mode 100644 index c9d96d4d..00000000 --- a/test/Export-DatabaseScripts.Tests.ps1 +++ /dev/null @@ -1,27 +0,0 @@ -<# -.SYNOPSIS -Tests exporting MS SQL database objects from the given server and database as files, into a consistent folder structure. -#> - -$basename = "$(($MyInvocation.MyCommand.Name -split '\.',2)[0])." -$skip = !(Test-Path .changes -Type Leaf) ? $false : - !@(Get-Content .changes |Get-Item |Select-Object -ExpandProperty Name |Where-Object {$_.StartsWith($basename)}) -if($skip) {Write-Information "No changes to $basename" -infa Continue} -Describe 'Export-DatabaseScripts' -Tag Export-DatabaseScripts -Skip:$skip { - BeforeAll { - if(!(Get-Module -List dbatools)) {Install-Module dbatools -Force} - $scriptsdir,$sep = (Split-Path $PSScriptRoot),[io.path]::PathSeparator - if($scriptsdir -notin ($env:Path -split $sep)) {$env:Path += "$sep$scriptsdir"} - Mock Export-DbaScript {} - $mockfile = Join-Path $PSScriptRoot mock ([io.path]::ChangeExtension((Split-Path $PSCommandPath -Leaf), 'cs')) - try {[void][MockObject]} - catch {Add-Type -TypeDefinition (Get-Content $mockfile -Raw)} - } - Context 'Exports MS SQL database objects from the given server and database as files, into a consistent folder structure' ` - -Tag ExportDatabaseScripts,Export,DatabaseScripts,Database,SQL { - It "Export scripts" { - New-Object Database |Export-DatabaseScripts.ps1 - Assert-MockCalled -CommandName Export-DbaScript -Times 3 - } - } -} diff --git a/test/Export-MermaidER.Tests.ps1 b/test/Export-MermaidER.Tests.ps1 deleted file mode 100644 index edc4bbaa..00000000 --- a/test/Export-MermaidER.Tests.ps1 +++ /dev/null @@ -1,52 +0,0 @@ -<# -.SYNOPSIS -Tests generating a Mermaid entity relation diagram for database tables. -#> - -if(!(Get-Module -List dbatools)) {Install-Module dbatools -Force} -$basename = "$(($MyInvocation.MyCommand.Name -split '\.',2)[0])." -$skip = !(Test-Path .changes -Type Leaf) ? $false : - !@(Get-Content .changes |Get-Item |Select-Object -ExpandProperty Name |Where-Object {$_.StartsWith($basename)}) -if($skip) {Write-Information "No changes to $basename" -infa Continue} -Describe 'Export-MermaidER' -Tag Export-MermaidER -Skip:$skip { - BeforeAll { - if(!(Get-Module -List dbatools)) {Install-Module dbatools -Force} - $scriptsdir,$sep = (Split-Path $PSScriptRoot),[io.path]::PathSeparator - if($scriptsdir -notin ($env:Path -split $sep)) {$env:Path += "$sep$scriptsdir"} - $datadir = Join-Path $PSScriptRoot 'data' - $mockfile = Join-Path $PSScriptRoot mock ([io.path]::ChangeExtension((Split-Path $PSCommandPath -Leaf), 'cs')) - $server = if(!!$env:TestConnectionString) {Connect-DbaInstance -SqlInstance $env:TestConnectionString} - } - Context 'Generates a Mermaid entity relation diagram for database tables' -Tag ExportMermaidER,Export,MermaidER,Mermaid,Diagram,Database { - It "From the test database, the table '' generates the diagram in the '' data file" -Skip:$(!$env:TestConnectionString) -TestCases @( - @{ Schema = 'Production'; Table = 'Product'; ResultFile = 'AW.Production.Product.mmd' } - ) { - Param([string] $Schema, [string] $Table, [string] $ResultFile) - $result = Join-Path $datadir $ResultFile |Get-Item |Get-Content -Raw - Get-DbaDbTable -SqlInstance $server -Schema $Schema -Table $Table |Export-MermaidER.ps1 |Should -BeExactly $result - } - It "From the test database, the schema '' generates the diagram in the '' data file" -Skip:$(!$env:TestConnectionString) -TestCases @( - @{ Schema = 'Purchasing'; ResultFile = 'AW.Purchasing.mmd' } - ) { - Param([string] $Schema, [string] $ResultFile) - $result = Join-Path $datadir $ResultFile |Get-Item |Get-Content -Raw - Get-DbaDbTable -SqlInstance $server -Schema $Schema |Export-MermaidER.ps1 |Should -BeExactly $result - } - It "From the mock Library database, the table '
' generates the diagram in the '' data file" -Skip:$(!!$env:TestConnectionString) -TestCases @( - @{ Table = 'Book'; ResultFile = 'Library.dbo.Book.mmd' } - ) { - Param([string] $Table, [string] $ResultFile) - try {[void][MockDatabases]} catch {Add-Type -TypeDefinition (Get-Content $mockfile -Raw)} - $result = Join-Path $datadir $ResultFile |Get-Item |Get-Content -Raw - [MockDatabases]::Library.Tables[$Table, "dbo"] |Export-MermaidER.ps1 |Should -BeExactly $result - } - It "From the mock Library database generates the diagram in the '' data file" -Skip:$(!!$env:TestConnectionString) -TestCases @( - @{ ResultFile = 'Library.mmd' } - ) { - Param([string] $ResultFile) - try {[void][MockDatabases]} catch {Add-Type -TypeDefinition (Get-Content $mockfile -Raw)} - $result = Join-Path $datadir $ResultFile |Get-Item |Get-Content -Raw - [MockDatabases]::Library.Tables |Export-MermaidER.ps1 |Should -BeExactly $result - } - } -} diff --git a/test/Export-TableMerge.Tests.ps1 b/test/Export-TableMerge.Tests.ps1 deleted file mode 100644 index 414a8861..00000000 --- a/test/Export-TableMerge.Tests.ps1 +++ /dev/null @@ -1,31 +0,0 @@ -<# -.SYNOPSIS -Tests exporting table data as a T-SQL MERGE statement. -#> - -$basename = "$(($MyInvocation.MyCommand.Name -split '\.',2)[0])." -$skip = !(Test-Path .changes -Type Leaf) ? $false : - !@(Get-Content .changes |Get-Item |Select-Object -ExpandProperty Name |Where-Object {$_.StartsWith($basename)}) -if($skip) {Write-Information "No changes to $basename" -infa Continue} -Describe 'Export-TableMerge' -Tag Export-TableMerge -Skip:$skip { - BeforeAll { - if(!(Get-Module -List dbatools)) {Install-Module dbatools -Force} - $scriptsdir,$sep = (Split-Path $PSScriptRoot),[io.path]::PathSeparator - if($scriptsdir -notin ($env:Path -split $sep)) {$env:Path += "$sep$scriptsdir"} - $datadir = Join-Path $PSScriptRoot 'data' - $server = if(!!$env:TestConnectionString) {Connect-DbaInstance -SqlInstance $env:TestConnectionString} - } - Context 'Exports table data' -Tag ExportTableMerge,Export,TableMerge,Database { - It "Exports AdventureWorks HumanResources.Department table data" -Skip:$(!$env:TestConnectionString) -TestCases @( - @{ Schema = 'HumanResources'; Table = 'Department' } - @{ Schema = 'Person'; Table = 'PhoneNumberType' } - @{ Schema = 'Production'; Table = 'ProductModelIllustration' } - ) { - $result = Join-Path $datadir "${Schema}.${Table}.merge.sql" |Get-Item |Get-Content -Raw - $result = $result.TrimEnd() - Get-DbaDbTable -SqlInstance $server -Schema $Schema -Table $Table | - Export-TableMerge.ps1 | - Should -BeExactly $result - } - } -} diff --git a/test/Find-DatabaseValue.Tests.ps1 b/test/Find-DatabaseValue.Tests.ps1 deleted file mode 100644 index be4c6b78..00000000 --- a/test/Find-DatabaseValue.Tests.ps1 +++ /dev/null @@ -1,44 +0,0 @@ -<# -.SYNOPSIS -Tests searching an entire database for a field value. -#> - -$basename = "$(($MyInvocation.MyCommand.Name -split '\.',2)[0])." -$skip = !(Test-Path .changes -Type Leaf) ? $false : - !@(Get-Content .changes |Get-Item |Select-Object -ExpandProperty Name |Where-Object {$_.StartsWith($basename)}) -if($skip) {Write-Information "No changes to $basename" -infa Continue} -Describe 'Find-DatabaseValue' -Tag Find-DatabaseValue -Skip:$skip { - BeforeAll { - $scriptsdir,$sep = (Split-Path $PSScriptRoot),[io.path]::PathSeparator - if($scriptsdir -notin ($env:Path -split $sep)) {$env:Path += "$sep$scriptsdir"} - } - Context 'Searches an entire database for a field value' -Tag FindDatabaseValue,Find,DatabaseValue,Database { - It "Finds France in [Sales].[SalesTerritory] by country code" -Skip:$(!$env:TestConnectionString) { - $found = Find-DatabaseValue.ps1 FR -IncludeSchemata Sales -MaxRows 100 -ConnectionString $env:TestConnectionString - $found.'#TableName' |Should -BeExactly '[Sales].[SalesTerritory]' - $found.'#ColumnName' |Should -BeExactly '[CountryRegionCode]' - $found.CountryRegionCode |Should -BeExactly 'FR' - $found.Name |Should -BeExactly 'France' - $found.Group |Should -BeExactly 'Europe' - } - It "Finds matching values across several tables" -Skip:$(!$env:TestConnectionString) { - $found = Find-DatabaseValue.ps1 41636 -IncludeColumns %OrderID -ConnectionString $env:TestConnectionString - $TransactionHistory = $found |Where-Object '#TableName' -eq '[Production].[TransactionHistory]' - $TransactionHistory.'#TableName' |Should -BeExactly '[Production].[TransactionHistory]' - $TransactionHistory.'#ColumnName' |Should -BeExactly '[ReferenceOrderID]' - $TransactionHistory.ReferenceOrderID |Should -BeExactly 41636 - $TransactionHistory.TransactionID |Should -BeExactly 100046 - $TransactionHistory.ProductID |Should -BeExactly 826 - $WorkOrder = $found |Where-Object '#TableName' -eq '[Production].[WorkOrder]' - $WorkOrder.'#TableName' |Should -BeExactly '[Production].[WorkOrder]' - $WorkOrder.'#ColumnName' |Should -BeExactly '[WorkOrderID]' - $WorkOrder.WorkOrderID |Should -BeExactly 41636 - $WorkOrder.ProductID |Should -BeExactly 826 - $WorkOrderRouting = $found |Where-Object '#TableName' -eq '[Production].[WorkOrderRouting]' - $WorkOrderRouting.'#TableName' |Should -BeExactly '[Production].[WorkOrderRouting]' - $WorkOrderRouting.'#ColumnName' |Should -BeExactly '[WorkOrderID]' - $WorkOrderRouting.WorkOrderID |Should -BeExactly 41636 - $WorkOrderRouting.ProductID |Should -BeExactly 826 - } - } -} diff --git a/test/Find-DbColumn.Tests.ps1 b/test/Find-DbColumn.Tests.ps1 deleted file mode 100644 index 7264583c..00000000 --- a/test/Find-DbColumn.Tests.ps1 +++ /dev/null @@ -1,22 +0,0 @@ -<# -.SYNOPSIS -Tests searching for database columns. -#> - -$basename = "$(($MyInvocation.MyCommand.Name -split '\.',2)[0])." -$skip = !(Test-Path .changes -Type Leaf) ? $false : - !@(Get-Content .changes |Get-Item |Select-Object -ExpandProperty Name |Where-Object {$_.StartsWith($basename)}) -if($skip) {Write-Information "No changes to $basename" -infa Continue} -Describe 'Find-DbColumn' -Tag Find-DbColumn -Skip:$skip { - BeforeAll { - $scriptsdir,$sep = (Split-Path $PSScriptRoot),[io.path]::PathSeparator - if($scriptsdir -notin ($env:Path -split $sep)) {$env:Path += "$sep$scriptsdir"} - } - Context 'Searches for database columns' -Tag FindDbColumn,Find,DbColumn,Database { - It "Finds price columns in the test database" -Skip:$(!$env:TestConnectionString) { - Find-DbColumn.ps1 -ConnectionString $env:TestConnectionString -IncludeColumns %price% | - Select-Object -ExpandProperty ColumnName | - Should -BeLike '*Price*' - } - } -} diff --git a/test/Find-DbIndexes.Tests.ps1 b/test/Find-DbIndexes.Tests.ps1 deleted file mode 100644 index eba21f06..00000000 --- a/test/Find-DbIndexes.Tests.ps1 +++ /dev/null @@ -1,22 +0,0 @@ -<# -.SYNOPSIS -Tests returning indexes using a column with the given name. -#> - -$basename = "$(($MyInvocation.MyCommand.Name -split '\.',2)[0])." -$skip = !(Test-Path .changes -Type Leaf) ? $false : - !@(Get-Content .changes |Get-Item |Select-Object -ExpandProperty Name |Where-Object {$_.StartsWith($basename)}) -if($skip) {Write-Information "No changes to $basename" -infa Continue} -Describe 'Find-DbIndexes' -Tag Find-DbIndexes -Skip:$skip { - BeforeAll { - $scriptsdir,$sep = (Split-Path $PSScriptRoot),[io.path]::PathSeparator - if($scriptsdir -notin ($env:Path -split $sep)) {$env:Path += "$sep$scriptsdir"} - } - Context 'Returns indexes using a column with the given name' -Tag FindDbIndexes,Find,DbIndexes,Database { - It "Finds the ErrorLog ID" -Skip:$(!$env:TestConnectionString) { - $index = Find-DbIndexes.ps1 -ConnectionString $env:TestConnectionString -ColumnName ErrorLogID - $index.IndexName |Should -BeExactly PK_ErrorLog_ErrorLogID - $index.TableName |Should -BeExactly ErrorLog - } - } -}