From e344ef8e887627abec6a0a550657f8706a569929 Mon Sep 17 00:00:00 2001 From: Simone Bizzotto Date: Wed, 27 Sep 2023 12:53:02 +0200 Subject: [PATCH] Test-DbaLoginPassword, use parametrized query (#9097) --- public/Test-DbaLoginPassword.ps1 | 88 +++++++++++++++++---------- tests/Test-DbaLoginPassword.Tests.ps1 | 4 ++ 2 files changed, 60 insertions(+), 32 deletions(-) diff --git a/public/Test-DbaLoginPassword.ps1 b/public/Test-DbaLoginPassword.ps1 index 644ff8a584..e0d8ba07f0 100644 --- a/public/Test-DbaLoginPassword.ps1 +++ b/public/Test-DbaLoginPassword.ps1 @@ -82,39 +82,48 @@ function Test-DbaLoginPassword { ) begin { - $CheckPasses = "''", "'@@Name'" - if ($Dictionary) { - $Dictionary | ForEach-Object { $CheckPasses += "'" + $PSItem + "'" } - } - foreach ($CheckPass in $CheckPasses) { - if ($CheckPasses.IndexOf($CheckPass) -eq 0) { - $checks = "SELECT " + $CheckPass - } else { - $checks += " - UNION SELECT " + $CheckPass + function Split-ArrayInChunks { + param( + [object[]] $source, + [int] $size = 1 + ) + $chunkCount = [Math]::Ceiling($source.Count / $size) + 0 .. ($chunkCount - 1) | ForEach-Object { + $startIndex = $_ * $size + $endIndex = [Math]::Min(($_ + 1) * $size, $source.Count) + , $source[$startIndex .. ($endIndex - 1)] } } - $sql = "DECLARE @WeakPwdList TABLE(WeakPwd NVARCHAR(255)) - --Define weak password list - --Use @@Name if users password contain their name - INSERT INTO @WeakPwdList(WeakPwd) - $checks - - SELECT SERVERPROPERTY('MachineName') AS [ComputerName], - ISNULL(SERVERPROPERTY('InstanceName'), 'MSSQLSERVER') AS InstanceName, - SERVERPROPERTY('ServerName') AS [SqlInstance], - SysLogins.name as SqlLogin, - WeakPassword = 'True', - REPLACE(WeakPassword.WeakPwd,'@@Name',SysLogins.name) As [Password], - SysLogins.is_disabled as Disabled, - SysLogins.create_date as CreatedDate, - SysLogins.modify_date as ModifiedDate, - SysLogins.default_database_name as DefaultDatabase - FROM sys.sql_logins SysLogins - INNER JOIN @WeakPwdList WeakPassword ON (PWDCOMPARE(WeakPassword.WeakPwd, password_hash) = 1 - OR PWDCOMPARE(REPLACE(WeakPassword.WeakPwd,'@@Name',SysLogins.name),password_hash) = 1)" + $maxBatch = 200 + + $CheckPasses = "", "@@Name" + if ($Dictionary) { + $Dictionary | ForEach-Object { $CheckPasses += $PSItem } + } + + $sqlStart = "DECLARE @WeakPwdList TABLE(WeakPwd NVARCHAR(255)) + --Define weak password list + --Use @@Name if users password contain their name + INSERT INTO @WeakPwdList(WeakPwd) + VALUES (NULL)" + + $sqlEnd = " + SELECT SERVERPROPERTY('MachineName') AS [ComputerName], + ISNULL(SERVERPROPERTY('InstanceName'), 'MSSQLSERVER') AS InstanceName, + SERVERPROPERTY('ServerName') AS [SqlInstance], + SysLogins.name as SqlLogin, + WeakPassword = 'True', + REPLACE(WeakPassword.WeakPwd,'@@Name',SysLogins.name) As [Password], + SysLogins.is_disabled as Disabled, + SysLogins.create_date as CreatedDate, + SysLogins.modify_date as ModifiedDate, + SysLogins.default_database_name as DefaultDatabase + FROM sys.sql_logins SysLogins + INNER JOIN @WeakPwdList WeakPassword + ON PWDCOMPARE(REPLACE(WeakPassword.WeakPwd,'@@Name',SysLogins.name),password_hash) = 1 + " } process { foreach ($instance in $SqlInstance) { @@ -130,14 +139,29 @@ function Test-DbaLoginPassword { } end { $servers = $logins | Select-Object -Unique -ExpandProperty Parent - $names = $logins | Select-Object -Unique -ExpandProperty Name foreach ($serverinstance in $servers) { - Write-Message -Level Debug -Message "Executing $sql" Write-Message -Level Verbose -Message "Testing: same username as Password" Write-Message -Level Verbose -Message "Testing: the following Passwords $CheckPasses" try { - $serverinstance.Query("$sql") | Where-Object SqlLogin -in $names + $checkParts = , (Split-ArrayInChunks -source $CheckPasses -size $maxBatch) + + $loopIndex = 0 + + foreach ($batch in $checkParts) { + $thisBatch = $sqlStart + $sqlParams = @{ } + foreach ($piece in $batch) { + $loopIndex += 1 + $paramKey = "@p_$loopIndex" + $sqlParams[$paramKey] = $piece + $thisBatch += ", ($paramKey)" + } + $thisBatch += $sqlEnd + Write-Message -Level Debug -Message "sql: $thisBatch" + Invoke-DbaQuery -SqlInstance $serverinstance -Query $thisBatch -SqlParameter $sqlParams + } + } catch { Stop-Function -Message "Failure" -ErrorRecord $_ -Target $serverinstance -Continue } diff --git a/tests/Test-DbaLoginPassword.Tests.ps1 b/tests/Test-DbaLoginPassword.Tests.ps1 index 4d9f88b96e..12769f6703 100644 --- a/tests/Test-DbaLoginPassword.Tests.ps1 +++ b/tests/Test-DbaLoginPassword.Tests.ps1 @@ -38,5 +38,9 @@ Describe "$commandname Integration Tests" -Tag "IntegrationTests" { $results = Test-DbaLoginPassword -SqlInstance $script:instance1 -Login $weaksauce $results.SqlLogin | Should -Be $weaksauce } + It "handles passwords with quotes, see #9095" { + $results = Test-DbaLoginPassword -SqlInstance $script:instance1 -Login $weaksauce -Dictionary "&é`"'(-", "hello" + $results.SqlLogin | Should -Be $weaksauce + } } } \ No newline at end of file