Обновите поле adVarChar в файле .ACF с помощью ADODB. Выдает ошибку. Ошибка многоэтапной операции. - PullRequest
0 голосов
/ 06 ноября 2018

Я нахожусь в процессе отладки приложения и обнаружил, что оно использует строку подключения к базе данных, зашифрованную в поле «Db» в файле .ACF. Пока я работал над тем, как написать процедуру дешифрования / шифрования, я не могу записать свое новое значение.

Пример фрагмента кода 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()

Этот код читает строку подключения и расшифровывает ее ОК. Он также прекрасно шифрует новую строку подключения. Однако при попытке обновить поле «Db» выдает ошибку:

Настройка исключения «Значение»: «Многошаговая операция вызвала ошибки. Проверьте каждое значение состояния. "В C: \ debugging \ Decryptor.ps1: 329 char: 1 + $ recordSet.Fields ["Db"]. Value = [Decryptor.NativeMethods] :: Encrypt ($ n ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ + CategoryInfo: NotSpecified: (:) [], SetValueInvocationException + FullyQualifiedErrorId: ExceptionWhenSetting

[Decryptor.NativeMethods] :: Encrypt возвращает строку, хотя не все символы пригодны для печати, и строка длиннее исходной строки.

Я могу установить значение БД для обычных строк или строку, которую я только что прочитал из базы данных:

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

Я подумал, что это может быть размер, поскольку исходная зашифрованная строка содержала 147 символов, а новая - 179 символов. Поэтому я сократил новую строку до 147 символов, и даже меньше, но она все равно не будет установлена. Поэтому я подозреваю, что это связано с содержимым строки.

Строка, которую я пытаюсь установить, выглядит следующим образом:

Ì Ì Ì Ì Ì ù ù Ò Ò J · D R R R L L L L L ((! $ ($ $ \ \ \ \ \ \ \ \ \ H h h h þ þ þ Z Z Z Z Z Z Z Z Z) Õ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            : 

Текущие настройки для набора записей. Поля ["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"]. Свойства содержат

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

1 Ответ

0 голосов
/ 06 ноября 2018

Эта проблема была вызвана ошибкой в ​​процедуре шифрования, которая создала результат, визуально выглядящий так же, как и правильное шифрование, но представление результирующей строки в байтах было другим.

Процедура шифрования была скопирована из декомпилированной 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.

...