【问题标题】:Powershell Script to SQL Server databasePowershell 脚本到 SQL Server 数据库
【发布时间】:2015-06-17 19:03:04
【问题描述】:

我有这个 PowerShell 脚本,它将收集我的远程服务器的系统信息。

我的问题:我不确定在运行时如何使用此脚本来填充我在 SQL Server Management Studio 中创建的新创建的数据库Hal0Test

最终目标:我希望我的 powershell 脚本查看远程服务器中的列 QAUTILITYDB01 > ServerList(数据库)> 标记为“ServerName”取“QACGAPPSVR01, QACGAPPSVR03等"将这些值中的每一个推送到我的 powershell 脚本中,并为每台服务器生成其 FQDN 和操作系统。最后,将新值(FQDN 和 OS)推送回远程数据库。

新的 Powershell 脚本代码:

$connectionString = "Server=QAUTILITYDB01;Database=Hal0Test;Integrated Security=True;"
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
$command = $connection.CreateCommand()

$ServerArray = [System.Collections.ArrayList]@()
$query = "SELECT ServerName FROM ServerList"
$command.CommandText = $query
$ServerNames = $command.ExecuteReader()

While ($ServerNames.read()){
    $ServerArray.Add($ServerNames[0])
}

foreach($Server in $ServerArray){
    # $Server returns each server name
    $os    = Get-WmiObject -Class Win32_OperatingSystem -Computer $_
    $disks = Get-WmiObject -Class Win32_LogicalDisk -Computer $_ |
             Where-Object {$_.DriveType -eq 3} |
             ForEach-Object {
                 '{0} {1:D} MB Free/{2:D} MB Used' -f $_.DeviceID,
                     [int]($_.FreeSpace/1MB), [int]($_.Size/1MB)
             }

    New-Object -Type PSCustomObject -Property @{
      'FQDN'            = $_
      'ServerName'      = $os.PSComputerName
      'OperatingSystem' = $os.Caption
      'Disks'           = $disks -join ' | '
    }
    $command.CommandText = "UPDATE ServerList SET FQDN = '$_', OS = '$os.Caption' WHERE ServerName = '$os.PSComputerName';"
    $result = $command.ExecuteNonQuery()

} Export-Csv 'C:\Desktop\HalO\output.csv' -Delimiter '|' -NoType

Powershell CSV 文件:

ServerName  FQDN    Disks   OperatingSystem
SVR01   Svr01.xxx.com   C: 17899 MB Free/51097 MB Used | E: 22277 MB Free/25597 MB Used Microsoft Windows Server 2008 R2 Enterprise 
SVR03   svr03.xxx.com   C: 18280 MB Free/61337 MB Used | E: 50079 MB Free/56317 MB Used Microsoft Windows Server 2008 R2 Enterprise 
SVR05   svr05.xxx.com   C: 8751 MB Free/40857 MB Used | E: 4987 MB Free/10237 MB Used   Microsoft Windows Server 2008 R2 Enterprise 
SVR06   svr06.xxx.com   C: 14188 MB Free/61337 MB Used | E: 34962 MB Free/56317 MB Used Microsoft Windows Server 2008 R2 Enterprise 
SVR08   Svr08.xxx.com   C: 6464 MB Free/40857 MB Used | E: 5921 MB Free/10237 MB Used   Microsoft Windows Server 2008 R2 Enterprise 

错误:

Exception calling "ExecuteNonQuery" with "0" argument(s): "There is already an open DataReader 
associated with this Command which must be closed first."
At C:\Users\mdaraghmeh\Desktop\HalO\test2.ps1:33 char:5
+     $result = $command.ExecuteNonQuery()
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : InvalidOperationException

SQL Server 列表:

【问题讨论】:

    标签: sql sql-server database powershell database-design


    【解决方案1】:

    在脚本开头设置 SQL Server 连接:

    $connectionString = "Server=ulidb01;Database=Hal0Test;Integrated Security=True;"
    $connection = New-Object System.Data.SqlClient.SqlConnection
    $connection.ConnectionString = $connectionString
    $connection.Open()
    $command = $connection.CreateCommand()
    

    执行查询以更新服务器:

    $command.CommandText = "UPDATE ServerList SET FQDN = '$_', OS = '$os.Caption' WHERE ServerName = '$os.PSComputerName';"
    $result = $command.ExecuteNonQuery()
    

    好的--现在回到顶部获取服务器名称列表:

    $ServerArray = [System.Collections.ArrayList]@()
    $query = "SELECT ServerName FROM ServerList"
    $command.CommandText = $query
    $ServerNames = $command.ExecuteReader()
    
    While ($ServerNames.read()){
        $ServerArray.Add($ServerNames[0])
    }
    

    这将为您提供服务器名称的数组列表 ($ServerArray)。所以你在外循环中遍历这个数组列表:

    foreach($Server in $ServerArray){
        # $Server returns each server name
    }
    

    ...或者您可以将其保留为将其通过管道传输到 foreach-object 中。我只是不想在脚本中使用管道,因为它更容易阅读。

    然后在脚本的最后你需要关闭 SQL Server 连接:

    $connection.Close()
    

    【讨论】:

    • 不要构建这样的查询字符串。它使您容易受到 SQL 注入的攻击。此外,您需要子表达式来扩展字符串中 $os 的属性。
    • 由于他显示输出他要转为 CSV,我没有考虑 $os.PSComputerName 是否足够。并且不需要修改 WMI 返回的内容以在此处注入 SQL 吗?在我看来,为了劫持这样一个没有从未知来源获得输入的脚本,系统已经受到威胁。
    • 是的——正如我在答案中提到的,ServerID 列需要由 SQL Server 自动生成,或者您需要以某种方式设置 ID。我没有在您的代码中看到您生成该 ID 的位置。请参阅stackoverflow.com/questions/10991894/… 了解如何自动生成它。如果您在代码中创建 ID,则类似于 "INSERT INTO ServerLIst (ServerID, ServerName, FQDN, OS) VALUES('$MyId', '$os.PSComputerName', '$_', '$os.Caption');"
    • 要更新这两列,请将您的查询字符串更改为UPDATE ServerList SET FQDN = '$_', OS = '$os.Caption' WHERE ServerName = '$os.PSComputerName'
    • ...所以现在您只需要从数据库中填充 $serverslist...等等。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-30
    • 1970-01-01
    • 2011-01-29
    • 2020-04-09
    • 1970-01-01
    • 1970-01-01
    • 2015-09-01
    相关资源
    最近更新 更多