我有一个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"
答案 0 :(得分:2)
我使用Out-DataTable
将我的对象数组转换为DataTable
对象类型,然后使用Write-DataTable
将其批量插入数据库(Write-DataTable
使用{{1}这样做)。
警告/陷阱(SqlBulkCopy对于排除故障可能会很麻烦):
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部分。