Powershell 使用 System.Data.SqlDBType varbinary
Powershell using System.Data.SqlDBType varbinary
我正在尝试从 SQL-服务器导入 ZIP 文件。 der SQL-table 中的列定义为 varbinary(max)。我正在使用 SQL 存储过程,其输出参数为我提供此 zip 文件。
我定义(见代码)一个 cmd.parameter (system.data.sqldbtype::varbinary,-1) ,“-1”应该是“最大”长度,但我没有得到任何记录($rd.HasRecords 为空..).
感谢您的帮助。
Function Get-SQLData
{
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Server=XXXX\YYYY;Database=SQL_XXX;Integrated Security=no;User=SQLServer_XX;Password=xxYYYY"
$conn.Open() | out-null
$cmd = new-Object System.Data.SqlClient.SqlCommand #("deployment.getZIPFile", $conn)
#Proz
$cmd.Connection = $conn
$cmd.CommandType = [System.Data.CommandType]::StoredProcedure
$cmd.CommandText = "deployment.getZIPFile"
#### Proz-Parameter
$cmd.Parameters.Add("@file_typ",[system.data.SqlDbType]::VarChar,5) | out-Null
$cmd.Parameters['@file_typ'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@file_typ'].value = 'PS'
#
$cmd.Parameters.Add("@domain",[system.data.SqlDbType]::VarChar,5) | out-Null
$cmd.Parameters['@domain'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@domain'].value = ($env:USERDNSDOMAIN).Split('.')[0] # domain
#
$cmd.Parameters.Add("@serverName",[system.data.SqlDbType]::VarChar,50) | out-Null
$cmd.Parameters['@serverName'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@serverName'].value = $env:COMPUTERNAME #local server
#
$cmd.Parameters.Add("@scriptVersion",[system.data.SqlDbType]::decimal) | out-Null
$cmd.Parameters['@scriptVersion'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@ScriptVersion'].Precision=18
$cmd.Parameters['@ScriptVersion'].Scale=2
$cmd.Parameters['@scriptVersion'].value = $MyVersion
#
$cmd.Parameters.Add("@operatingSystem",[system.data.SqlDbType]::VarChar, 100) | out-Null
$cmd.Parameters['@operatingSystem'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@operatingSystem'].value = (gwmi -Class win32_operatingsystem).caption
#
$cmd.Parameters.Add("@serverTyp",[system.data.SqlDbType]::VarChar, 50) | out-Null
$cmd.Parameters['@serverTyp'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@serverTyp'].value = $serverTyp
#
$cmd.Parameters.Add("@serverSubTyp",[system.data.SqlDbType]::VarChar, 50) | out-Null
$cmd.Parameters['@serverSubTyp'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@serverSubTyp'].value = $serverSubTyp
#
$cmd.Parameters.Add("@aktScriptVersion",[system.data.SqlDbType]::decimal) | out-Null
$cmd.Parameters['@aktScriptVersion'].Direction = [system.data.ParameterDirection]::Output
$cmd.Parameters['@aktScriptVersion'].Precision=18
$cmd.Parameters['@aktScriptVersion'].Scale=2
#
$cmd.Parameters.Add("@ZIPFile",[system.data.SqlDbType]::varbinary,-1) | out-Null
$cmd.Parameters['@ZIPFile'].Direction = [system.data.ParameterDirection]::Output
#### Proz-Parameter Ende
#$cmd.ExecuteNonQuery() #| out-null ## org
$rd = $cmd.ExecuteReader() # gibt es Records?
#$rd = $cmd.ExecuteNonQuery()
if ($rd.HasRows) # gibt es Records?
{
$bufferSize = 8192
# Stream Lesen..
# Create a byte array for the stream.
$out = [array]::CreateInstance('Byte', $bufferSize)
# Looping through records
While ($rd.Read())
{
$fileLocation = "C:\PerfLogs\XXXX\ZIPImport.7z"
#Write-Output ("Exporting: {0}" -f $rd.GetInt32(0));
# New BinaryWriter
$fs = New-Object System.IO.FileStream $fileLocation,'Create','Write';
$bw = New-Object System.IO.BinaryWriter $fs;
$start = 0;
# Read first byte stream
$received = $rd.GetBytes(0, $start, $out, 0, $bufferSize - 1); ## 1
While ($received -gt 0)
{
$bw.Write($out, 0, $received);
$bw.Flush();
$start += $received;
# Read next byte stream
$received = $rd.GetBytes(0, $start, $out, 0, $bufferSize - 1); ## 1
}
$bw.Close();
$fs.Close();
}
# Closing & Disposing all objects
$fs.Dispose()
$rd.Close()
$cmd.Dispose()
$conn.Close()
Write-Output ("ZIP-Import Finished")
# 7z Sektion
$unzip = 'C:\PerfLogs\xxxx\Modul'
& ${env:ProgramFiles}-Zipz.exe x $fileLocation "-o$($unzip)" -y
Write-Output ("UNZIP Finished")
}
$conn.Close()
$conn.Dispose()
}
}
如解决您问题的评论中所述,您问题中的参数是正确的。问题在于执行过程和处理结果的代码。
这里不需要使用 SqlDataReader
因为 proc returns 输出参数中的值而不是结果集列中的值。此外,由于返回了整个字节数组,因此将值直接写入文件比在 read/write 循环中写入要容易得多。
下面是将输出参数字节数组写入文件的一种方法。
# execute the proc, returning the @ZIPFile output parameter
$cmd.ExecuteNonQuery() | out-null
if($cmd.Parameters["@ZIPFile"].Value -eq [System.DBNull]::Value) {
Write-Output "Zipfile not found in database"
}
else {
# write the byte arrary output value to a file
$fileLocation = "C:\PerfLogs\XXXX\ZIPImport.7z"
Write-Output "Exporting $($cmd.Parameters["@ZIPFile"].Value.Length) bytes to $fileLocation"
[System.IO.File]::WriteAllBytes($fileLocation, $cmd.Parameters["@ZIPFile"].Value)
}
我正在尝试从 SQL-服务器导入 ZIP 文件。 der SQL-table 中的列定义为 varbinary(max)。我正在使用 SQL 存储过程,其输出参数为我提供此 zip 文件。 我定义(见代码)一个 cmd.parameter (system.data.sqldbtype::varbinary,-1) ,“-1”应该是“最大”长度,但我没有得到任何记录($rd.HasRecords 为空..).
感谢您的帮助。
Function Get-SQLData
{
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Server=XXXX\YYYY;Database=SQL_XXX;Integrated Security=no;User=SQLServer_XX;Password=xxYYYY"
$conn.Open() | out-null
$cmd = new-Object System.Data.SqlClient.SqlCommand #("deployment.getZIPFile", $conn)
#Proz
$cmd.Connection = $conn
$cmd.CommandType = [System.Data.CommandType]::StoredProcedure
$cmd.CommandText = "deployment.getZIPFile"
#### Proz-Parameter
$cmd.Parameters.Add("@file_typ",[system.data.SqlDbType]::VarChar,5) | out-Null
$cmd.Parameters['@file_typ'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@file_typ'].value = 'PS'
#
$cmd.Parameters.Add("@domain",[system.data.SqlDbType]::VarChar,5) | out-Null
$cmd.Parameters['@domain'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@domain'].value = ($env:USERDNSDOMAIN).Split('.')[0] # domain
#
$cmd.Parameters.Add("@serverName",[system.data.SqlDbType]::VarChar,50) | out-Null
$cmd.Parameters['@serverName'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@serverName'].value = $env:COMPUTERNAME #local server
#
$cmd.Parameters.Add("@scriptVersion",[system.data.SqlDbType]::decimal) | out-Null
$cmd.Parameters['@scriptVersion'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@ScriptVersion'].Precision=18
$cmd.Parameters['@ScriptVersion'].Scale=2
$cmd.Parameters['@scriptVersion'].value = $MyVersion
#
$cmd.Parameters.Add("@operatingSystem",[system.data.SqlDbType]::VarChar, 100) | out-Null
$cmd.Parameters['@operatingSystem'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@operatingSystem'].value = (gwmi -Class win32_operatingsystem).caption
#
$cmd.Parameters.Add("@serverTyp",[system.data.SqlDbType]::VarChar, 50) | out-Null
$cmd.Parameters['@serverTyp'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@serverTyp'].value = $serverTyp
#
$cmd.Parameters.Add("@serverSubTyp",[system.data.SqlDbType]::VarChar, 50) | out-Null
$cmd.Parameters['@serverSubTyp'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@serverSubTyp'].value = $serverSubTyp
#
$cmd.Parameters.Add("@aktScriptVersion",[system.data.SqlDbType]::decimal) | out-Null
$cmd.Parameters['@aktScriptVersion'].Direction = [system.data.ParameterDirection]::Output
$cmd.Parameters['@aktScriptVersion'].Precision=18
$cmd.Parameters['@aktScriptVersion'].Scale=2
#
$cmd.Parameters.Add("@ZIPFile",[system.data.SqlDbType]::varbinary,-1) | out-Null
$cmd.Parameters['@ZIPFile'].Direction = [system.data.ParameterDirection]::Output
#### Proz-Parameter Ende
#$cmd.ExecuteNonQuery() #| out-null ## org
$rd = $cmd.ExecuteReader() # gibt es Records?
#$rd = $cmd.ExecuteNonQuery()
if ($rd.HasRows) # gibt es Records?
{
$bufferSize = 8192
# Stream Lesen..
# Create a byte array for the stream.
$out = [array]::CreateInstance('Byte', $bufferSize)
# Looping through records
While ($rd.Read())
{
$fileLocation = "C:\PerfLogs\XXXX\ZIPImport.7z"
#Write-Output ("Exporting: {0}" -f $rd.GetInt32(0));
# New BinaryWriter
$fs = New-Object System.IO.FileStream $fileLocation,'Create','Write';
$bw = New-Object System.IO.BinaryWriter $fs;
$start = 0;
# Read first byte stream
$received = $rd.GetBytes(0, $start, $out, 0, $bufferSize - 1); ## 1
While ($received -gt 0)
{
$bw.Write($out, 0, $received);
$bw.Flush();
$start += $received;
# Read next byte stream
$received = $rd.GetBytes(0, $start, $out, 0, $bufferSize - 1); ## 1
}
$bw.Close();
$fs.Close();
}
# Closing & Disposing all objects
$fs.Dispose()
$rd.Close()
$cmd.Dispose()
$conn.Close()
Write-Output ("ZIP-Import Finished")
# 7z Sektion
$unzip = 'C:\PerfLogs\xxxx\Modul'
& ${env:ProgramFiles}-Zipz.exe x $fileLocation "-o$($unzip)" -y
Write-Output ("UNZIP Finished")
}
$conn.Close()
$conn.Dispose()
}
}
如解决您问题的评论中所述,您问题中的参数是正确的。问题在于执行过程和处理结果的代码。
这里不需要使用 SqlDataReader
因为 proc returns 输出参数中的值而不是结果集列中的值。此外,由于返回了整个字节数组,因此将值直接写入文件比在 read/write 循环中写入要容易得多。
下面是将输出参数字节数组写入文件的一种方法。
# execute the proc, returning the @ZIPFile output parameter
$cmd.ExecuteNonQuery() | out-null
if($cmd.Parameters["@ZIPFile"].Value -eq [System.DBNull]::Value) {
Write-Output "Zipfile not found in database"
}
else {
# write the byte arrary output value to a file
$fileLocation = "C:\PerfLogs\XXXX\ZIPImport.7z"
Write-Output "Exporting $($cmd.Parameters["@ZIPFile"].Value.Length) bytes to $fileLocation"
[System.IO.File]::WriteAllBytes($fileLocation, $cmd.Parameters["@ZIPFile"].Value)
}