Sql server 使用PowerShell将大量AD数据插入SQL server
我有一个PowerShell脚本,它可以提取140多万行数据,并将其保存到一个巨大的CSV文件中,然后导入SQL server。我认为有一种方法可以让PowerShell直接将数据插入SQL server,但我不确定如何插入 我担心的一点是,我不想将AD结果缓冲到内存中,然后再将其写入。我宁愿把它们成批地写上1000个左右,这样内存消耗就会减少。获取1000条记录,保存到SQL server,然后重复 我看到了一些关于如何让PowerShell写入SQL server的文章,但它们似乎要么一次写入所有数据,要么一次写入一条记录,这两种方法对我来说都是低效的 这是我必须查询的PowerShell脚本Sql server 使用PowerShell将大量AD数据插入SQL server,sql-server,powershell,active-directory,Sql Server,Powershell,Active Directory,我有一个PowerShell脚本,它可以提取140多万行数据,并将其保存到一个巨大的CSV文件中,然后导入SQL server。我认为有一种方法可以让PowerShell直接将数据插入SQL server,但我不确定如何插入 我担心的一点是,我不想将AD结果缓冲到内存中,然后再将其写入。我宁愿把它们成批地写上1000个左右,这样内存消耗就会减少。获取1000条记录,保存到SQL server,然后重复 我看到了一些关于如何让PowerShell写入SQL server的文章,但它们似乎要么一次写
# 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"
我使用
Out DataTable
将我的对象数组转换为DataTable
对象类型,然后使用Write DataTable
将其大容量插入数据库(Write DataTable
使用SqlBulkCopy
执行此操作)
这方面的注意事项/问题(SqlBulkCopy可能是一个麻烦的疑难解答):
- 确保属性的类型正确(varchar/nvarchar为string,任何整数值为int,只要格式正确,dateTime可以是string,SQL可以解析它)
- 确保属性有序并与要插入的表对齐,包括自动填充的任何字段(递增ID键、RunDt等)
SQL-server-1
,数据库名称为org
,表名称为employees
):
看看你的代码,它看起来像你来自.NET或一些基于.NET的语言。您是否听说过cmdlet/?这将大大简化您的工作 就SQL连接而言,PowerShell没有任何本机支持。微软已经成功了!您只需要安装SQL Server就可以获得它们。。。。这有点令人沮丧,因为SQL太重了,不是每个人都想安装它。使用.NET仍然是可能的,只是它不是很快或者很漂亮。我不会在这里提供有关cmdlet的建议,您可以在谷歌上搜索。至于.NET,我将首先阅读一些关于名称空间的文档以及一些关于主题的文档 最后,正如您所说的,尝试避免RAM过载是一个好主意。这里最重要的一点是尽量将整个脚本简化为一个广告查询。这样可以避免在一个查询和下一个查询之间更改数据的麻烦场景。我认为最好的方法是将结果直接保存到文件中。一旦你有了它,你就可以直接从你的文件中插入到表中。缺点是它不允许多个广告属性。至少我不认为SqlBulkCopy会允许这样做
Get-ADUser "SomeParamsHere" | Out-File ADOutput.txt
如果您必须拥有多个广告属性,并且仍然希望将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"
}
将结果存储在变量的最后一行代码中,而不是将其导出为csv。
然后创建您想要的大小的组。
在nferrell的回答中使用Out DataTable和Write DataTable Write to SQL-links
$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
}
`你把这件事弄得太复杂了。 如果我正确阅读了您的代码,您希望所有组都以“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部分。请考虑分批使用SqlBulkCopy。我认为a是最有效的。你为什么会不这么认为?@DanGuzman但我如何使用
System.DirectoryServices.SearchResultCollection
对象分批完成它呢?我能想到的唯一方法是迭代搜索结果集合,在记录的X个之后进行批量SQL插入?@AnsgarWiechers我并不反对。我就是不知道如何使用SearchResultCollection
对象进行批量插入,而不必将整个集合加载到内存中。但是第一行,$set=…
是否会首先将所有内容加载到内存中?难道没有办法只将X行加载到内存中,写入SQL,然后加载下X行吗?如果对AD的查询正在提取所有内容,那么它已经加载到内存中了。您需要收紧查询,否则这是一个无关紧要的问题。我已经将我的更新为一个用try-catch语句包装的单行程序,因此它会立即加载到数组中,转换为datatable,然后批量插入到数据库中。考虑到您的$objSearcher.PageSize=1000
位已经受到限制,也许可以将其转换为在循环中一次批量插入1000条记录?我会说,我使用相同的方法一次将75000多行加载到SQL中,其中许多是nvarchar(最大)字段。它可以处理很大的负载,我认为你可以节省大量的时间一次做更大的块我听说过Get ADUser
,但我认为.NET更快、更高效。不是这样吗?如果我先保存到文件,那么这是一个多步骤的过程:获取数据,写入fi
# 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"