【问题标题】:Update adVarChar Field in .ACF File using ADODB Throws Error Multiple-step operation generated errors使用 ADODB 更新 .ACF 文件中的 adVarChar 字段引发错误 多步操作生成错误
【发布时间】:2019-04-09 13:31:04
【问题描述】:

我正在调试一个应用程序,发现它使用了在 .ACF 文件的“Db”字段中加密的数据库连接字符串。虽然我想出了如何编写解密/加密例程,但我无法写回我的新值。

示例 PowerShell 代码片段:

Add-Type -Path C:\app\adodb.dll
Add-Type -TypeDefinition $decryptCode

$recordSet = New-Object ADODB.RecordsetClass
$recordSet.Open("c:\app\connectionstring.acf",[Type]::Missing,[ADODB.CursorTypeEnum]::adOpenKeySet,[ADODB.LockTypeEnum]::adLockBatchOptimistic)

$dbEncrypted = $recordSet.Fields["Db"].Value
"Current Connection String: $([Decryptor.NativeMethods]::Decrypt($dbEncrypted))"

# update connection string
$newConnectionString = "<blah blah blah>"

$recordSet.Fields["Db"].Value = [Decryptor.NativeMethods]::Encrypt($newConnectionString)
$recordSet.Save()

此代码读取连接字符串并对其进行解密。 IT 还可以很好地加密新的连接字符串。但是,当尝试更新“Db”字段时,它会引发错误:

异常设置“Value”:“多步操作产生错误。 检查每个状态值。”在 C:\debugging\Decryptor.ps1:329 char:1 + $recordSet.Fields["Db"].Value = [Decryptor.NativeMethods]::Encrypt($n ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : 未指定: (:) [], SetValueInvocationException + FullyQualifiedErrorId : ExceptionWhenSetting

[Decryptor.NativeMethods]::Encrypt 返回一个字符串,虽然不是所有字符都是可打印的,而且字符串比原始字符串长。

我可以将数据库值设置为普通字符串,或者我刚刚从数据库中读取的字符串:

$recordSet.Fields["Db"].Value = $dbEncrypted

我认为它可能是大小,因为原始加密字符串是 147 个字符,但新的加密字符串是 179 个字符。所以我将新字符串削减为 147 个字符,甚至更少,但它仍然不会设置。所以我怀疑这是由于字符串的内容。

我尝试设置的字符串如下所示:

£àöÌóÓàù:Ò¡J·DμÕ1R|SÀgÐqíÀZ(Lá2 !¯'B$Rä!kýÈg\ISX êmh®¾ oÔçþOZißlß%¼ù@ ÕeæB¦ëvpâNÉ oSÆ!fZÆÿ²ÔFôó Ûvºä2øg ¹¼àU¸ÏAß0g§ÿ¨brÁƾ('îÙ2ÿééµHãhû=¿ 6Å=#´ú½¬ö

$recordSet 显示以下值:

Properties       : {IAccessor, IChapteredRowset, IColumnsInfo, IColumnsRowset...}
AbsolutePosition : 1
ActiveConnection : 
BOF              : False
Bookmark         : 1
CacheSize        : 1
CursorType       : adOpenStatic
EOF              : False
Fields           : {DB}
LockType         : adLockBatchOptimistic
MaxRecords       : 0
RecordCount      : 5
Source           : c:\app\connectionstring.acf
AbsolutePage     : 1
EditMode         : adEditNone
Filter           : 0
PageCount        : 1
PageSize         : 10
Sort             : 
Status           : 8
State            : 1
CursorLocation   : adUseClient
MarshalOptions   : adMarshalAll
DataSource       : ADODB.RecordsetClass
ActiveCommand    : 
StayInSync       : True
DataMember       : 
Index            : 

recordset.Fields["db"] 的当前设置显示:

$recordSet.Fields["Db"]

Status          : 0
ActualSize      : 147
Attributes      : 4
DataFormat      : 
DefinedSize     : 255
Name            : DB
NumericScale    : 0
OriginalValue   : 
Precision       : 0
Properties      : {BASECOLUMNNAME, BASETABLENAME, BASECATALOGNAME, BASESCHEMANAME...}
Type            : adVarChar
UnderlyingValue : 
Value           : £àöÌóÓà™ù:Ò¡J·DµÕ1R|SÀgÐqíÀZ(Lá2  !¯'B$Rä\!kýȘg\ISX  ê‰mh®¾  oÔçþOZißlß%¼ù€@Š˜ ÕeæB¦ëvpâNÉ   
                  oSÆ!fZ–Æÿ²ÔFôó Ûvºä2øÀü"ëöÑ@Õ k§«üdÊ'Ó‹Û§1j©

$recordSet.Fields["Db"].Properties 包含

Attributes Name                      Type Value
---------- ----                      ---- -----
         1 BASECOLUMNNAME      adVarWChar      
         1 BASETABLENAME       adVarWChar      
         1 BASECATALOGNAME     adVarWChar      
         1 BASESCHEMANAME      adVarWChar      
         1 KEYCOLUMN            adBoolean False
         1 ISAUTOINCREMENT      adBoolean False
         1 RELATIONCONDITIONS adVarBinary      
         1 CALCULATIONINFO    adVarBinary      
         1 OPTIMIZE             adBoolean False

在使用不同字符串的进一步测试中发现此字符串有效:

$recordSet.Fields["Db"].Value = "£àöÌóÓà"

但是这个字符串不起作用:

$recordSet.Fields["Db"].Value = "£àöÌóÓà"

Exception setting "Value": "Multiple-step operation generated errors. Check each status value."
At line:1 char:1
+ $recordSet.Fields["Db"].Value = "£àöÌóÓà"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], SetValueInvocationException
    + FullyQualifiedErrorId : ExceptionWhenSetting

进一步测试确定以下内容:

 $broken = "£àöÌóÓà"
$working = "£àöÌóÓà"
# $broken.Length  = 9
# $working.Length = 7 

[System.Text.UTF8Encoding]::UTF8.GetBytes($working)
194
163
195
160
195
182
195
140
195
179
195
147
195
160

[System.Text.UTF8Encoding]::UTF8.GetBytes($broken)
194
163
195
160
195
182
195
140
195
179
195
147
195
160
194
129
194
153

【问题讨论】:

    标签: .net powershell adodb


    【解决方案1】:

    这个问题是由加密例程中的一个缺陷引起的,它创建的结果在视觉上与正确的加密相同,但结果字符串的字节表示不同。

    加密例程已从反编译的 DLL 复制并利用函数将字节数组转换为字符串:

        private static string ByteArrayToString(byte[] Buffer)
                {
    
                    StringBuilder builder = new StringBuilder(Buffer.Count);
                    foreach (byte num in Buffer)
                    {
                        builder.Append(Convert.ToString((char)num));
                    }
    return builder.ToString();
    }
    

    我使用 .NET 内置转换方法替换了代码:

     private static string ByteArrayToString(byte[] Buffer)
            {
                    return Encoding.Default.GetString(Buffer.ToArray());
    }
    

    后一种方法生成的字符串在视觉上相同,但逐字节不同,并且被 ADODB 更新命令接受。

    【讨论】:

      猜你喜欢
      • 2011-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-08
      • 1970-01-01
      • 2011-04-07
      • 2016-09-25
      相关资源
      最近更新 更多