微调Powershell SQL脚本

时间:2017-08-23 14:53:21

标签: sql-server powershell

我的公司有一个跟踪员工锻炼的计划。当我们制定了这个程序时,我们没有考虑添加添加或删除员工的能力。

我在PowerShell中编写了一个脚本,它允许我们比在SSMS中更容易地执行此操作。我想看看是否有人可以帮我清理一下并对其进行微调。

我最头疼的是1-1,只要我们执行一个函数就会返回。我也想问这个问题是否完成,然后循环或退出。现在它只是在完成后立即退出。

<#Writes the invoker to log#>
$trandate = Get-Date 
$tranuser = $env:UserName
<# Variables to open the connection to the SQL server #>

$sqlcn = New-Object System.Data.SqlClient.SqlConnection
$sqlcn.ConnectionString = "server=10.10.1.19\VTSWORKOUT;Integrated 
Security=true;Database=VTSWORKOUT;"


<# Read what the user wants to do #>
$input = Read-Host "Do you want to [A]dd a New Employee, [R]emove an Employee or [E]xit?"
switch($input){

<# Stuff for adding an employee to the database #>

A{
$eid = Read-Host "What is the Employees ID number?"
$fname = Read-Host "What is the Employees first name?"
$lname = Read-Host "What is the Employees last name?"
$dept = Read-Host "What department is the Employee in?"
$pay = Read-Host "Is the Employee Salaried? [0]Yes or [1]No"
$hire = Read-Host "When was the Employee hired? Input as MM-DD-YYYY"

        Out-File -FilePath "L:\Personnel\WorkoutApp\workouts.log" -Append -InputObject "On $trandate, $tranuser  added Employee# $eid, $fname $lname"

    $sqlcn.Open()
    $sqlcmd = $sqlcn.CreateCommand()
    $query = "INSERT INTO employees values (@eid,@lname,@fname,@dept,@pay,@hire)"
    $sqlcmd.CommandText = $query
    $sqlcmd.Parameters.AddWithValue("@eid", $eid) | Out-Null
    $sqlcmd.Parameters.AddWithValue("@fname", $fname) | Out-Null
    $sqlcmd.Parameters.AddWithValue("@lname", $lname) | Out-Null
    $sqlcmd.Parameters.AddWithValue("@dept", $dept) | Out-Null
    $sqlcmd.Parameters.AddWithValue("@pay", $pay) | Out-Null
    $sqlcmd.Parameters.AddWithValue("@hire", $hire) | Out-Null

    $sqlcmd.ExecuteNonQuery()
    $sqlcn.Close() 
 }

<# Stuff for removing an employee from the database#>

R{

<#Collect reason for removal#>
    $reason = Read-Host -Prompt "Why are you deleting this employee?"

    $eid = Read-Host "What is the ID number of the Employee you want to remove?"
    $sqlcn.Open()
    $sqlcmd = $sqlcn.CreateCommand()
    $query = "SELECT EmployeeID,FirstName, LastName from Employees WHERE EmployeeID = @eid"
    $sqlcmd.CommandText = $query 
    $sqlcmd.Parameters.AddWithValue("@eid", $eid) | Out-Null
    $sqlcmd.ExecuteNonQuery()
    $Reader = $sqlcmd.ExecuteReader()
    $arry = @()
    while ($Reader.Read()) {
    $row = @{}
    for ($i = 0; $i -lt $reader.FieldCount; $i++)
    {
        $row[$reader.GetName($i)] = $reader.GetValue($i)
    }
    #convert hashtable into an array of PSObjects
    $arry+= new-object psobject -property $row
    }

    $sqlcn.Close()
    write-host $arry
    $empResult = Read-Host "Is that the correct employee? [Y]es or [N]o"

    <#If the correct employee was found, continue below.
    If the wrong employee was returned, Kill Program #>
    switch($empResult) {

    Y{
                            Out-File -FilePath "L:\Personnel\WorkoutApp\workouts.log" -Append -InputObject "On $trandate, $tranuser deleted Employee $eid for the following reason: $reason"
                            $sqlcn.Open()
                            $sqlcmd = $sqlcn.CreateCommand()
                            $query = "DELETE FROM Employees WHERE EmployeeID = @eid"
                            $sqlcmd.CommandText = $query
                            $sqlcmd.Parameters.AddWithValue("@eid", $eid)
                            $sqlcmd.ExecuteNonQuery()

                            $adp = New-Object System.Data.SqlClient.SqlDataAdapter $sqlcmd
                            $data = New-Object System.Data.DataSet
                            $adp.fill($data) | Out-Null
                            $sqlcn.Close()
                          }
    N{
    Out-File -FilePath "L:\Personnel\WorkoutApp\workouts.log" -Append -InputObject "On $trandate, $tranuser tried to deleted Employee $eid. But exited the program before doing so."
    Write-Host "Please restart the program. If the issue persists, please contact the IT department."
    Read-Host -Prompt "Press Enter to exit"
    }
    }
}

<# Line to exit the program #>

E{
exit
}
}

任何关于清理它的想法都将非常感激。

1 个答案:

答案 0 :(得分:0)

这是偏离主题的,但我会给你一个答案。

通常,您根本不想使用Parameters.AddWithValue(),因为它会将每个参数作为NVARCHAR发送。它没有被弃用,但是it's not a good idea to use it。如果您有日期时间或其他非字符串参数,则可能会遇到问题。通常最好使用Parameters.Add()

$sqlcmd.Parameters.Add("@eid", [System.Data.SqlDbType]::Int).Value = $eid

显然,您在[System.Data.SqlDbType]中使用的数据类型应该与数据库中实际列的数据类型匹配。这样做的好处是,您不需要将任何返回值发送到Out-Null或投放为[void]

这也是一团糟:

$sqlcmd.ExecuteNonQuery()
$Reader = $sqlcmd.ExecuteReader()
$arry = @()
while ($Reader.Read()) {
    $row = @{}
    for ($i = 0; $i -lt $reader.FieldCount; $i++)
    {
        $row[$reader.GetName($i)] = $reader.GetValue($i)
    }
    #convert hashtable into an array of PSObjects
    $arry+= new-object psobject -property $row
}

首先,您要执行两次查询。 ExecuteNonQuery()ExecuteReader()都会执行查询!您可以在脚本中多次执行此操作。

其次,你可以这样做:

$DataTable = New-Object System.Data.DataTable
$DataTable.Load($sqlcmd.ExecuteReader())

然后,如果您真的不想使用DataTable - 它们比自定义对象更复杂但实际上并不那么糟糕 - 您可以这样做将其转换为通用对象非常容易:

$Data = $DataTable | ConvertTo-Csv -NoTypeInformation | ConvertFrom-Csv

但是,这将使一切都成为一个字符串,所以请确保这是你想要的。你也可以试试这个:

$Data = $DataTable | Select-Object -Property <list>

您不想使用Select-Object *,因为您将获得您可能不想要的额外属性。

这也是执行两次查询:

$sqlcn.Open()
$sqlcmd = $sqlcn.CreateCommand()
$query = "DELETE FROM Employees WHERE EmployeeID = @eid"
$sqlcmd.CommandText = $query
$sqlcmd.Parameters.AddWithValue("@eid", $eid)
$sqlcmd.ExecuteNonQuery()

$adp = New-Object System.Data.SqlClient.SqlDataAdapter $sqlcmd
$data = New-Object System.Data.DataSet
$adp.fill($data) | Out-Null
$sqlcn.Close()

$sqlcmd.ExecuteNonQuery()$adp.fill($data)都执行查询!此外,ExecuteNonQuery()返回受影响的记录数。你可以这样做:

$sqlcmd.ExecuteNonQuery() | Out-Null

或者这个:

[void]$sqlcmd.ExecuteNonQuery()

但你真正应该做的是验证结果是否符合预期。对于INSERT或DELETE语句,你不应该得到-1。

Learn to look up the documentation了解您调用的方法并了解可能的返回值是什么以及原因。所有.Net方法都在MSDN上进行了详细记录。你几乎总能通过谷歌搜索&#34; C#&#34;找到它们。您还可以找到可轻松转换为PowerShell的C#示例。