Skip to content

Commit 061fd00

Browse files
Add sqlbulkcopy
1 parent c96d9a9 commit 061fd00

File tree

2 files changed

+293
-7
lines changed

2 files changed

+293
-7
lines changed

Invoke-SQLBulkCopy.ps1

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
function Invoke-SQLBulkCopy {
2+
<#
3+
.SYNOPSIS
4+
Use the .NET SQLBulkCopy class to write data to SQL Server tables.
5+
6+
.DESCRIPTION
7+
Use the .NET SQLBulkCopy class to write data to SQL Server tables.
8+
9+
The data source is not limited to SQL Server; any data source can be used, as long as the data can be loaded to a DataTable instance or read with a IDataReader instance.
10+
11+
.PARAMETER ServerInstance
12+
A SQL instance to run against. For default instances, only specify the computer name: "MyComputer". For named instances, use the format "ComputerName\InstanceName".
13+
14+
.PARAMETER Database
15+
A string specifying the name of a database.
16+
17+
.PARAMETER Credential
18+
Specifies A PSCredential for SQL Server Authentication connection to an instance of the Database Engine. If -Credential is not specified, Invoke-Sqlcmd attempts a Windows Authentication connection using the Windows account running the PowerShell session.
19+
SECURITY NOTE: If you use the -Debug switch, the connectionstring including plain text password will be sent to the debug stream.
20+
21+
.PARAMETER ConnectionTimeout
22+
Specifies the number of seconds when Invoke-Sqlcmd2 times out if it cannot successfully connect to an instance of the Database Engine. The timeout value must be an integer between 0 and 65534. If 0 is specified, connection attempts do not time out.
23+
24+
.PARAMETER Force
25+
If specified, skip the confirm prompt
26+
27+
.PARAMETER BatchSize
28+
The batch size for the bulk copy operation.
29+
30+
.PARAMETER NotifyAfter
31+
The number of rows to fire the notification event after transferring. 0 means don't notify. Notifications hit the verbose stream (use -verbose to see them)
32+
33+
.PARAMETER ColumnMappings
34+
A hash table with the format Key = SourceColumn, Value = DestinationColumn
35+
36+
Example, converting SourceColumn FirstName to DestinationColumn surname, and converting SourceColumn LastName to DestinationColumn givenname
37+
@{
38+
FirstName = 'surname'
39+
LastName = 'givenname'
40+
}
41+
42+
.PARAMETER SQLConnection
43+
An existing SQLConnection to use
44+
45+
.EXAMPLE
46+
Invoke-SQLBulkCopy -ServerInstance $SQLInstance -Database $Database -Table $SQLTable -DataTable $DataTable -verbose -NotifyAfter 1000 -force
47+
48+
Insert a datatable into a table. Notify via verbose every 1000 rows. Don't prompt for confirmation.
49+
50+
.OUTPUTS
51+
None
52+
Produces no output
53+
54+
.NOTES
55+
This function borrows from:
56+
Chad Miller's Write-Datatable
57+
jbs534's Invoke-SQLBulkCopy
58+
Mike Shepard's Invoke-BulkCopy from SQLPSX
59+
60+
.LINK
61+
https://github.com/RamblingCookieMonster/PowerShell
62+
63+
.LINK
64+
http://msdn.microsoft.com/en-us/library/30c3y597
65+
66+
.LINK
67+
Out-DataTable
68+
69+
.LINK
70+
Invoke-Sqlcmd2
71+
72+
.LINK
73+
New-SQLConnection
74+
75+
.FUNCTIONALITY
76+
SQL
77+
#>
78+
[cmdletBinding( DefaultParameterSetName = 'Instance',
79+
SupportsShouldProcess = $true,
80+
ConfirmImpact = 'High' )]
81+
param(
82+
[parameter( Position = 0,
83+
Mandatory = $true,
84+
ValueFromPipeline = $true,
85+
ValueFromPipelineByPropertyName= $true)]
86+
[System.Data.DataTable]
87+
$DataTable,
88+
89+
[Parameter( ParameterSetName = 'Instance',
90+
Position = 1,
91+
Mandatory = $true,
92+
ValueFromPipeline = $false,
93+
ValueFromPipelineByPropertyName = $true)]
94+
[Alias( 'SQLInstance', 'Server', 'Instance' )]
95+
[string]
96+
$ServerInstance,
97+
98+
[Parameter( ParameterSetName = 'Connection',
99+
Position = 1,
100+
Mandatory = $true,
101+
ValueFromPipeline = $false,
102+
ValueFromPipelineByPropertyName = $false,
103+
ValueFromRemainingArguments = $false )]
104+
[Alias( 'Connection', 'Conn' )]
105+
[System.Data.SqlClient.SQLConnection]
106+
$SQLConnection,
107+
108+
[Parameter( Position = 2,
109+
Mandatory = $true)]
110+
[string]
111+
$Database,
112+
113+
[parameter( Position = 3,
114+
Mandatory = $true)]
115+
[string]
116+
$Table,
117+
118+
[Parameter( ParameterSetName = 'Instance',
119+
Position = 4,
120+
Mandatory = $false)]
121+
[System.Management.Automation.PSCredential]
122+
$Credential,
123+
124+
[Parameter( ParameterSetName = 'Instance',
125+
Position = 5,
126+
Mandatory = $false)]
127+
[Int32]
128+
$ConnectionTimeout=15,
129+
130+
[switch]
131+
$Temp,
132+
133+
[int]
134+
$BatchSize = 0,
135+
136+
[int]
137+
$NotifyAfter = 0,
138+
139+
[System.Collections.Hashtable]
140+
$ColumnMappings,
141+
142+
[switch]
143+
$Force
144+
145+
)
146+
begin {
147+
148+
#Handle existing connections
149+
if ($PSBoundParameters.Keys -contains "SQLConnection")
150+
{
151+
if ($SQLConnection.State -notlike "Open")
152+
{
153+
Try
154+
{
155+
$SQLConnection.Open()
156+
}
157+
Catch
158+
{
159+
Throw $_
160+
}
161+
}
162+
163+
if ($Database -and $SQLConnection.Database -notlike $Database)
164+
{
165+
Try
166+
{
167+
$SQLConnection.ChangeDatabase($Database)
168+
}
169+
Catch
170+
{
171+
Throw "Could not change Connection database '$($SQLConnection.Database)' to $Database`: $_"
172+
}
173+
}
174+
175+
if ($SQLConnection.state -notlike "Open")
176+
{
177+
Throw "SQLConnection is not open"
178+
}
179+
}
180+
else
181+
{
182+
if ($Credential)
183+
{
184+
$ConnectionString = "Server={0};Database={1};User ID={2};Password={3};Trusted_Connection=False;Connect Timeout={4}" -f $ServerInstance,$Database,$Credential.UserName,$Credential.GetNetworkCredential().Password,$ConnectionTimeout
185+
}
186+
else
187+
{
188+
$ConnectionString = "Server={0};Database={1};Integrated Security=True;Connect Timeout={2}" -f $ServerInstance,$Database,$ConnectionTimeout
189+
}
190+
191+
$SQLConnection = New-Object System.Data.SqlClient.SQLConnection
192+
$SQLConnection.ConnectionString = $ConnectionString
193+
194+
Write-Debug "ConnectionString $ConnectionString"
195+
196+
Try
197+
{
198+
$SQLConnection.Open()
199+
}
200+
Catch
201+
{
202+
Write-Error $_
203+
continue
204+
}
205+
}
206+
207+
$bulkCopy = New-Object System.Data.SqlClient.SqlBulkCopy $SQLConnection
208+
$bulkCopy.BatchSize = $BatchSize
209+
$bulkCopy.BulkCopyTimeout = 10000000
210+
211+
if ($Temp)
212+
{
213+
$bulkCopy.DestinationTableName = "#$Table"
214+
}
215+
else
216+
{
217+
$bulkCopy.DestinationTableName = $Table
218+
}
219+
if ($NotifyAfter -gt 0)
220+
{
221+
$bulkCopy.NotifyAfter=$notifyafter
222+
$bulkCopy.Add_SQlRowscopied( {Write-Verbose "$($args[1].RowsCopied) rows copied"} )
223+
}
224+
else
225+
{
226+
$bulkCopy.NotifyAfter=$DataTable.Rows.count
227+
$bulkCopy.Add_SQlRowscopied( {Write-Verbose "$($args[1].RowsCopied) rows copied"} )
228+
}
229+
}
230+
process
231+
{
232+
try
233+
{
234+
foreach ($column in ( $DataTable.Columns | Select -ExpandProperty ColumnName ))
235+
{
236+
if ( $PSBoundParameters.ContainsKey( 'ColumnMappings') -and $ColumnMappings.ContainsKey($column) )
237+
{
238+
[void]$bulkCopy.ColumnMappings.Add($column,$ColumnMappings[$column])
239+
}
240+
else
241+
{
242+
[void]$bulkCopy.ColumnMappings.Add($column,$column)
243+
}
244+
}
245+
Write-Verbose "ColumnMappings: $($bulkCopy.ColumnMappings | Format-Table -Property SourceColumn, DestinationColumn -AutoSize | Out-String)"
246+
247+
if ($Force -or $PSCmdlet.ShouldProcess("$($DataTable.Rows.Count) rows, with BoundParameters $($PSBoundParameters | Out-String)", "SQL Bulk Copy"))
248+
{
249+
$bulkCopy.WriteToServer($DataTable)
250+
}
251+
}
252+
catch
253+
{
254+
throw $_
255+
}
256+
}
257+
end
258+
{
259+
#Only dispose of the connection if we created it
260+
if($PSBoundParameters.Keys -notcontains 'SQLConnection')
261+
{
262+
$SQLConnection.Close()
263+
$SQLConnection.Dispose()
264+
}
265+
}
266+
}

Out-DataTable.ps1

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
.DESCRIPTION
88
Creates a DataTable based on an object's properties.
99
10+
.PARAMETER InputObject
11+
One or more objects to convert into a DataTable
12+
13+
.PARAMETER NonNullable
14+
A list of columns to set disable AllowDBNull on
15+
1016
.INPUTS
1117
Object
1218
Any object can be piped to Out-DataTable
@@ -15,11 +21,17 @@
1521
System.Data.DataTable
1622
1723
.EXAMPLE
18-
$dt = Get-psdrive| Out-DataTable
19-
This example creates a DataTable from the properties of Get-psdrive and assigns output to $dt variable
24+
$dt = Get-psdrive | Out-DataTable
25+
26+
# This example creates a DataTable from the properties of Get-psdrive and assigns output to $dt variable
27+
28+
.EXAMPLE
29+
Get-Process | Select Name, CPU | Out-DataTable | Invoke-SQLBulkCopy -ServerInstance $SQLInstance -Database $Database -Table $SQLTable -force -verbose
30+
31+
# Get a list of processes and their CPU, create a datatable, bulk import that data
2032
2133
.NOTES
22-
Adapted from script by Marc van Orsouw see link
34+
Adapted from script by Marc van Orsouw and function from Chad Miller
2335
Version History
2436
v1.0 - Chad Miller - Initial Release
2537
v1.1 - Chad Miller - Fixed Issue with Properties
@@ -33,12 +45,22 @@
3345
- Added perhaps pointless error handling
3446
3547
.LINK
36-
http://thepowershellguy.com/blogs/posh/archive/2007/01/21/powershell-gui-scripblock-monitor-script.aspx
48+
https://github.com/RamblingCookieMonster/PowerShell
49+
50+
.LINK
51+
Invoke-SQLBulkCopy
52+
53+
.LINK
54+
Invoke-Sqlcmd2
55+
56+
.LINK
57+
New-SQLConnection
3758
3859
.FUNCTIONALITY
3960
SQL
4061
#>
4162
[CmdletBinding()]
63+
[OutputType([System.Data.DataTable])]
4264
param(
4365
[Parameter( Position=0,
4466
Mandatory=$true,
@@ -118,7 +140,6 @@
118140
{
119141
Write-Error "Could not add column $($Col | Out-String) for property '$Name' with value '$Value' and type '$($Value.GetType().FullName)':`n$_"
120142
}
121-
122143
}
123144

124145
Try
@@ -161,13 +182,12 @@
161182
}
162183

163184
$First = $false
164-
165185
}
166186
}
167187

168188
End
169189
{
170-
Write-Output @(,($dt))
190+
Write-Output @(,$dt)
171191
}
172192

173193
} #Out-DataTable

0 commit comments

Comments
 (0)