构建一个包装器以从Powershell执行SQL查询

时间:2015-02-02 21:43:06

标签: sql-server powershell

我正在尝试构建一个通用的包装器,以便在Powershell中轻松查询SQL Server数据库并使用结果:

$result = SQL("SELECT * CustomerID FROM [dbo].[TblCustomers]")

$result.Tables[0] | Foreach {
    Write-Host $_.CustomerID
}

包装

## Wrapper for SQL Select statements
#
Function SQL {
    param(
        [string]$query
    )

    $Server = "SQLEXPRESS"
    $DBase  = "DataStore"
    $User   = "DataUser"
    $Pass   = "DataPass"

    $conn  = New-Object System.Data.SqlClient.SqlConnection("Server=$Server;Database=$DBase;User=$User;Password=$Pass;Connect Timeout=15")

    try {
        $conn.Open()
        $cmd     = New-Object System.Data.SqlClient.SqlCommand($query,$conn)
        $adapter = New-Object System.Data.SqlClient.SqlDataAdapter($cmd)
        $dataset = New-Object System.Data.DataSet
        $adapter.Fill($dataset) | Out-Null
        $conn.Close()
    }
    catch {
        $ex = $_.Exception
        Write-Error "$ex.Message"
        continue
    }

    return $dataset
}

这仅适用于SELECT语句:

  • 如果我执行UPDATEINSERT,我想返回受影响的行数,或者如果适用则返回错误
  • 应忽略任何其他查询(ALTERDROPDELETE),并返回错误消息

最好的方法是:

  • 确定查询命令的类型(SELECTDROP)?
  • 处理一个函数中的所有请求? (切换语句或重定向到特定功能?)

非常感谢任何帮助。

P.S。因为我是唯一一个在后端脚本中使用该函数的人,所以我并不太担心SQL注入。

[编辑]

我现在有:

Function Query {
    param (
        [string]$query
        [string]$server
        [string]$dbase
        [string]$user
        [string]$pass
    )

    if ($user) { 
        $connstr = "Server={0};Database={1};User ID={2};Password={3};Trusted_Connection=False;Connect Timeout=15" -f $server, $dbase, $user, $pass 
    } 
    else { 
        $connstr = "Server={0};Database={1};Integrated Security=True;Connect Timeout=15" -f $server, $dbase
    }
    $conn.ConnectionString = $connstr 


    switch ($query.Split()[0]) {
        "SELECT" {
            $cmd = New-Object System.Data.SqlClient.SqlCommand($query,$conn)
            $adapter = New-Object System.Data.SqlClient.SqlDataAdapter($cmd)
            $dataset = New-Object System.Data.DataSet
            $adapter.Fill($dataset) | Out-Null
            return $dataset
        }
        "UPDATE" {
            $cmd = New-Object System.Data.SqlClient.SqlCommand($query,$conn)
            return $cmd.ExecuteNonQuery()
        }
        "INSERT" {
            $cmd = New-Object System.Data.SqlClient.SqlCommand($query,$conn)
            return $cmd.ExecuteNonQuery()
        }
    }
}

1 个答案:

答案 0 :(得分:1)

以下是您可以构建的示例,它使用参数集来标识查询类型。 executenonquery方法返回受查询影响的行数。我使用validatescript属性来阻止任何包含单词drop,delete或alter的查询。您可以根据需要添加其他人。我没有方便测试的SQL框,但这应该有效。您也可以调整此选项以使用服务器,db,user,pass的参数,而不是对它们进行硬编码以使其可重用。

function Invoke-SQLQuery
{
    [CmdletBinding(DefaultParameterSetName='SELECT', 
                  SupportsShouldProcess=$true, 
                  ConfirmImpact='Medium')]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true, 
                   Position=0,
                   ParameterSetName='SELECT')]
        [Parameter(Mandatory=$true, 
                   Position=0,
                   ParameterSetName='UPDATE')]
        [Parameter(Mandatory=$true, 
                   Position=0,
                   ParameterSetName='INSERT')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({$_ -notmatch "ALTER|DROP|DELETE" })]
        $Query,

        # Param2 help description
        [Parameter(ParameterSetName='SELECT')]
        [switch]
        $Select,

        # Param3 help description
        [Parameter(ParameterSetName='UPDATE')]
        [switch]
        $Update,

        [Parameter(ParameterSetName='INSERT')]
        [switch]
        $Insert
    )

    Begin
    {
        $Server = "SQLEXPRESS"
        $DBase  = "DataStore"
        $User   = "DataUser"
        $Pass   = "DataPass"
        $conn  = New-Object System.Data.SqlClient.SqlConnection("Server=$Server;Database=$DBase;User=$User;Password=$Pass;Connect Timeout=15")
    }
    Process
    {
        if ($pscmdlet.ShouldProcess("$Server", "Execute Query"))
        {
            try
            {
                $conn.Open()
                switch($pscmdlet.ParameterSetName){
                    "SELECT" {
                                $cmd = New-Object System.Data.SqlClient.SqlCommand($query,$conn)
                                $adapter = New-Object System.Data.SqlClient.SqlDataAdapter($cmd)
                                $dataset = New-Object System.Data.DataSet
                                $adapter.Fill($dataset) | Out-Null
                                return $dataset
                        }
                    "UPDATE" {
                            $cmd = New-Object System.Data.SqlClient.SqlCommand($query,$conn)
                            return $cmd.ExecuteNonQuery()
                        }
                    "INSERT" {
                            $cmd = New-Object System.Data.SqlClient.SqlCommand($query,$conn)
                            return $cmd.ExecuteNonQuery()
                        }
                    }
                }
               catch [System.Data.SqlClient.SqlException]
               {
                    #Implement Error Handling
                    $ex = $_.Exception
                    Write-Error "$ex.Message"
                    continue
               }
               finally
               {
                   $conn.Close()
                   $conn.Dispose()
               }
           }
      }
}