【问题标题】:PowerShell :: SQL SELECT returns only first rowPowerShell :: SQL SELECT 仅返回第一行
【发布时间】:2021-07-21 22:15:45
【问题描述】:

我有一种奇怪的感觉,我在这里做错了什么。

这是我的 PowerShell 脚本,当然是偷来的,改编自 here

param(
    $instance = "localhost"
)

if (!(Get-Module -ListAvailable -Name "SQLPS")) {
    Write-Host -BackgroundColor Red -ForegroundColor White "Module Invoke-Sqlcmd is not loaded"
    exit
}

#Function to execute queries (depending on if the user will be using specific credentials or not)
function Execute-Query([string]$query,[string]$database,[string]$instance,[int]$trusted,[string]$username,[string]$password){
    if($trusted -eq 1){
        try{ 
            Invoke-Sqlcmd -Query $query -Database $database -ServerInstance $instance -ErrorAction Stop -ConnectionTimeout 5 -QueryTimeout 0      
        }
        catch{
            Write-Host -BackgroundColor Red -ForegroundColor White $_
            exit
        }
    }
    else{
        try{
            Invoke-Sqlcmd -Query $query -Database $database -ServerInstance $instance -Username $username -Password $password -ErrorAction Stop -ConnectionTimeout 5 -QueryTimeout 0
        }
         catch{
            Write-Host -BackgroundColor Red -ForegroundColor White $_
            exit
        }
    }
}

function List-of-Databases([string]$instance,[int]$trusted,[string]$login,[string]$password){
    $ctpQuery = "
    SELECT name 
    FROM master.dbo.sysdatabases
    "

    return $(Execute-Query $ctpQuery "master" $instance $trusted $login $password)[0]
}

function Check-SysAdminLogins([string]$instance,[int]$trusted,[string]$login,[string]$password){
    $sysadminLoginsQuery = "
    SELECT   name
    FROM     master.sys.server_principals 
    WHERE    IS_SRVROLEMEMBER ('sysadmin',name) = 1
    ORDER BY name
    "
    return $(Execute-Query $sysadminLoginsQuery "master" $instance $trusted $login $password)
}


$loginChoices = [System.Management.Automation.Host.ChoiceDescription[]] @("&Trusted", "&Windows Login", "&SQL Login")
$loginChoice = $host.UI.PromptForChoice('', 'Choose login type for instance', $loginChoices, 0)
switch($loginChoice)
{
    1 { 
        $login          = Read-Host -Prompt "Enter Windows Login"
        $securePassword = Read-Host -Prompt "Enter Password" -AsSecureString
        $password       = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securePassword))
      }
    2 { 
        $login          = Read-Host -Prompt "Enter SQL Login"
        $securePassword = Read-Host -Prompt "Enter Password" -AsSecureString
        $password       = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securePassword))
      }
}

#Attempt to connect to the SQL Server instance using the information provided by the user
try{
    switch($loginChoice){
        0       {$buildNumber = Execute-Query "SELECT 1" "master" $instance 1 "" ""}
        default {$buildNumber = Execute-Query "SELECT 1" "master" $instance 0 $login $password}   
    }     
}
catch{
    Write-Host -BackgroundColor Red -ForegroundColor White $_
    exit
}

#If the connection succeeds, then proceed with the verification of best practices
Write-Host ""
Write-Host "------------ ------------ ------------ ------------" 
Write-Host "************ ************ ************ ************" 
Write-Host "------------ ----         ----         ------------" 
Write-Host "    ****     ************ ************     ****    " 
Write-Host "    ----     ------------ ------------     ----    " 
Write-Host "    ****     ****                *****     ****    " 
Write-Host "    ----     ------------ ------------     ----    " 
Write-Host "    ****     ************ ************     ****    " 
Write-Host ""
#List of Databases
Write-Host "#####################"
Write-Host "# List of Databases #"
Write-Host "#####################"           
switch($loginChoice){
    0       {$lod = List-of-Databases $instance 1 "" ""}
    default {$lod = List-of-Databases $instance 0 $login $password}   
} 
foreach($database in $lod)
{
    Write-Host $database.name | Format-Table
}
Write-Host ""

#Logins with sysadmin privilege
Write-Host "##################################"
Write-Host "# Logins with sysadmin privilege #"
Write-Host "##################################"
switch($loginChoice){
    0       {$sysadminLogins = Check-SysadminLogins $instance 1 "" ""}
    default {$sysadminLogins = Check-SysadminLogins $instance 0 $login $password}   
} 
foreach($sysadminLogin in $sysadminLogins)
{
    Write-Host $sysadminLogin.name
}

Write-Host ""

如果你运行它,脚本就会成功执行:

问题是第二个查询:

SELECT   name
FROM     master.sys.server_principals 
WHERE    IS_SRVROLEMEMBER ('sysadmin',name) = 1
ORDER BY name

正确返回所有行:

##################################
# Logins with sysadmin privilege #
##################################
NT SERVICE\SQLSERVERAGENT
NT SERVICE\SQLWriter
NT SERVICE\Winmgmt
sa

第一次查询时:

SELECT name 
FROM master.dbo.sysdatabases

只返回SELECT语句的第一行,当然是master数据库:

#####################
# List of Databases #
#####################
master

但正如你所见,我那里有很多数据库。

我哪里错了?

【问题讨论】:

  • 您是否在 SQL 客户端(SQLMS?)和脚本中为 SqlServer db 使用相同的帐户?
  • 顺便说一句:Write-Host is typically the wrong tool to use,除非意图是仅写入显示器,绕过成功输出流,并能够将输出发送到其他命令,将其捕获在变量中,或将其重定向到文件。要输出一个值,请单独使用它;例如,$value 而不是 Write-Host $value(或使用 Write-Output $value,尽管这很少需要);见this answer
  • 例如,| Format-TableWrite-Host $database.name | Format-Table 中无效,因为Write-Host 不会通过管道发送任何内容。
  • 此外,在 PowerShell 中,return 仅用于显式控制流,而不用于输出(“返回值”),并且在字符串插值之外很少需要$(...)。因此,不要使用return $(...),而只使用return ...,甚至只使用...

标签: sql-server powershell tsql automation scripting


【解决方案1】:

注意return 语句末尾的数组索引:

return $(Execute-Query $ctpQuery "master" $instance $trusted $login $password)[0]

这将只返回第一行。试试:

return $(Execute-Query $ctpQuery "master" $instance $trusted $login $password)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-03
    • 2021-07-09
    • 2014-01-01
    • 1970-01-01
    • 2017-04-17
    • 1970-01-01
    相关资源
    最近更新 更多