Powershell 使用 System.Data.SqlDBType varbinary

问题描述

我正在尝试从 sql Server 导入 ZIP 文件sql 表中的列定义为 varbinary(max)。我正在使用带有输出参数的 sql 存储过程,该过程为我提供了这个 zip 文件。 我定义了(见代码一个 cmd.parameter (system.data.sqldbtype::varbinary,-1) ,“-1”应该是“max”-length,但我没有得到任何记录($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",5) | out-Null
        $cmd.Parameters['@domain'].Direction = [system.data.ParameterDirection]::Input
        $cmd.Parameters['@domain'].value = ($env:USERDNSDOMAIN).Split('.')[0] # domain
        #
        $cmd.Parameters.Add("@serverName",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",100) | out-Null
        $cmd.Parameters['@operatingSystem'].Direction = [system.data.ParameterDirection]::Input
        $cmd.Parameters['@operatingSystem'].value = (gwmi -Class win32_operatingsystem).caption 
        #
        $cmd.Parameters.Add("@serverTyp",50) | out-Null
        $cmd.Parameters['@serverTyp'].Direction = [system.data.ParameterDirection]::Input
        $cmd.Parameters['@serverTyp'].value = $serverTyp
        #
        $cmd.Parameters.Add("@serverSubTyp",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,$bufferSize - 1);      ## 1     
                While ($received -gt 0)            
                {            
                   $bw.Write($out,$received);            
                   $bw.Flush();            
                   $start += $received;            
                   # Read next byte stream            
                   $received = $rd.GetBytes(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}\7-Zip\7z.exe x $fileLocation "-o$($unzip)" -y
            Write-Output ("UNZIP Finished")
        } 
        $conn.Close()
        $conn.dispose()
    }
}

解决方法

正如解决您问题的评论中所述,您问题中的参数是正确的。问题在于执行过程和处理结果的代码。

此处无需使用 SqlDataReader,因为 proc 在输出参数中而不是在结果集列中返回值。此外,由于返回的是整个字节数组,因此将值直接写入文件比在读/写循环中更容易。

以下是将输出参数字节数组写入文件的一种方法。

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