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)
}