使用PowerShell将大量AD数据插入SQL Server

时间:2017-05-12 22:21:19

标签: sql-server powershell active-directory

我有一个PowerShell脚本,可以提取140多万行数据并将其保存到一个巨大的CSV文件中,然后导入SQL服务器。我认为可能有一种方法让PowerShell直接将数据插入SQL服务器,但我不知道如何。

我担心的一个问题是,我不想将AD结果缓冲到内存中,然后编写它们。我宁愿将它们分批写入1000或者其他东西,以免内存消耗下降。获取1000条记录,保存到SQL服务器,然后重复...

我看到有关如何让PowerShell写入SQL服务器的文章,但他们似乎要么一次做所有数据,要么一次做一条记录 - 这对我来说都是低效的。

这是我必须查询AD的PowerShell脚本。

# the attributes we want to load
$ATTRIBUTES_TO_GET = "name,distinguishedName"

# split into an array
$attributes = $ATTRIBUTES_TO_GET.split(",")

# create a select string to be used when we want to dump the information
$selectAttributes = $attributes | ForEach-Object {@{n="AD $_";e=$ExecutionContext.InvokeCommand.NewScriptBlock("`$_.$($_.toLower())")}}

# get a directory searcher to search the GC
[System.DirectoryServices.DirectoryEntry] $objRoot = New-Object System.DirectoryServices.DirectoryEntry("GC://dc=company,dc=com")
[System.DirectoryServices.DirectorySearcher] $objSearcher = New-Object System.DirectoryServices.DirectorySearcher($objRoot)

# set properties
$objSearcher.SearchScope = "Subtree"
$objSearcher.ReferralChasing = "All"

# need to set page size otherwise AD won't return everything
$objSearcher.PageSize = 1000

# load the data we want
$objSearcher.PropertiesToLoad.AddRange($attributes)

# set the filter
$objSearcher.Filter = "(&(objectClass=group)(|(name=a*)(name=b*)))"

# get the data and export to csv
$objSearcher.FindAll() | select -expandproperty properties | select $selectAttributes | export-csv -notypeinformation -force "out.csv"

4 个答案:

答案 0 :(得分:2)

我使用Out-DataTable将我的对象数组转换为DataTable对象类型,然后使用Write-DataTable将其批量插入数据库(Write-DataTable使用{{1}这样做)。

警告/陷阱(SqlBulkCopy对于排除故障可能会很麻烦):

  • 确保您的属性是正确的类型(varchar / nvarchar的字符串,任何整数值的int,只要格式正确且SQL可以解析它,dateTime就可以是字符串)
  • 确保您的属性符合顺序,并与您要插入的表格对齐,包括自动填充的任何字段(递增ID键,RunDt等)。

Out-DataTable:https://gallery.technet.microsoft.com/scriptcenter/4208a159-a52e-4b99-83d4-8048468d29dd

Write-DataTable:https://gallery.technet.microsoft.com/scriptcenter/2fdeaf8d-b164-411c-9483-99413d6053ae

<强>用法

如果我继续你的例子并跳过CSV,我就是这样做的......用下面的代码替换最后两行(假设你的对象属性与表完美对齐,你的SQL服务器名称为SqlBulkCopy,数据库名称为sql-server-1,表名为org):

employees

答案 1 :(得分:0)

查看您的代码,看起来您来自.NET或基于.NET的某种语言。您是否听说过cmdlet Get-ADUser / Get-ADGroup?这将极大地简化您的工作。

就SQL连接而言,PowerShell没有任何本机支持。微软已经为它做了cmdlets!您只需安装SQL Server即可获得它们....由于SQL非常繁重并且不是每个人都想安装它,这有点令人失望。它仍然可以使用.NET,它不是很快或很漂亮。我不会在这里提供有关cmdlet的建议,你可以Google。至于.NET,我首先阅读System.Data.SqlClient命名空间上的一些文档以及关于该主题的一些historical questions

最后,正如您所说,尝试避免RAM过载会是一个好主意。这里最重要的是尝试将整个脚本保留为单个AD查询。这样就可以避免在一个查询和下一个查询之间发生数据更改的麻烦。我认为最好的方法是将结果直接保存到文件中。完成后,您可以使用SqlBulkCopy直接从文件中插入表格。这样做的缺点是它不允许多个AD属性。至少我不认为SqlBulkCopy会允许这个吗?

Get-ADUser "SomeParamsHere" | Out-File ADOutput.txt

如果你必须拥有多个AD属性,并且仍然希望将RAM的使用保持在最低限度......那么我玩弄了一个可以工作的脚本,但会发出一些从整个文件中读取的调用,这会失败整个目的。您最好的选择可能是将每个属性保存到一个单独的文件,然后执行整个写入数据库的事情。例如:

New-Item Name.txt
New-Item DistinguishedName.txt

Get-ADUser "SomeParamsHere" -Properties "Name,DistinguishedName" | Foreach {
    Add-Content -Path "Name.txt" -Value "$_.Name"
    Add-Content -PassThru "DistinguishedName.txt" -Value "$_.DistinguishedName"
}

答案 2 :(得分:0)

将结果存储在变量的最后一行代码中,而不是将其导出到csv 然后创建你想要的组大小。
使用Out-DataTable和Write-DataTable写入SQL - nferrell答案中的链接。

$res = $objSearcher.FindAll() | select -expandproperty properties | select 
$selectAttributes 
$counter = [pscustomobject] @{ Value = 0 }
#create groups with 1000 entries each 
$groups = $res | Group-Object -Property { [math]::Floor($counter.Value++ / 1000) }
foreach ($group in $groups){
    #convert to data table
    $dt = $group.group | Out-DataTable
    $dt | Write-DataTable -Database DB -ServerInstance SERVER -TableName TABLE 
}

`

答案 3 :(得分:0)

你让这个不必要地复杂化了。 如果我正确阅读了您的代码,您希望所有组以“a”或“b”开头。

# the attributes we want to export
$attributes = 'name', 'distinguishedName'

Import-Module ActiveDirectory

Get-ADGroup -Filter {(name -like "a*") -or (name -like "b*")} -SearchBase 'dc=company,dc=com' |
    select $attributes | Export-Csv -NoTypeInformation -Force "out.csv"

而不是在最后使用Export-Csv,只需将输出传递给创建SQL行的命令。通过管道对象(而不是将它们分配给变量),您可以让PowerShell有效地处理它们(它会在它们进入时开始处理对象,而不是缓冲所有对象)。

不幸的是我无法帮助你使用SQL部分。