Contents of this directory is archived and no longer updated.

Иногда бывает очень полезным найти какой-нибудь запрос в БД CA. Можно, конечно же, сделать это через certutil, но это не всегда удобно, потому что если под конкретный запрос подпадает несколько строк из БД, нужно уже вручную как-то парсить вывод, чтобы найти то, что нужно. Поэтому я решил рассказать, как наваять подобный костыль (только религиозно-православный) родными средствами PowerShell и необходимыми COM интерфейсами. Для работы с БД сервера CA нам понадобится лишь один интерфейс: ICertView2.

Каждая БД состоит из столбцов и рядов. То же самое относится и к БД CA (которая, кстати говоря, является стандартной встроенной Jet БД, что позволяет с ней работать стандартными тулзами типа eseutil). Ряды представляют собой набор свойств каждого запроса и для каждого запроса выделяется ровно один ряд. Столбцы представляют собой сами свойства. Каждому столбцу соответствует одно свойство. CA использует БД с заранее созданной (и неизменяемой) схемой, т.е. набором поддерживаемых столбцов. Давайте попробуем вывести схему БД. Для начала создадим объект ICertView2:

$CaView = New-Object -ComObject CertificateAuthority.View

Далее нужно подключиться к какому-то CA серверу при помощи метода OpenConnection. В качестве аргумента следует указать конфигурационную строку CA сервера вида CAComputerName\CAName.

$CaView.OpenConnection("dc1\Contoso CA")

Если ошибок не высыпало, значит, подключение произошло удачно. Теперь мы хотим посмотреть схему и это можно сделать при помощи метода EnumCertViewColumn. В качестве аргумента указываем CVRC_COLUMN_SCHEMA (которое имеет значение 0).

$CaView.EnumCertViewColumn(0)

В результате мы молучим другой объект интерфейса IEnumCERTVIEWCOLUMN. А теперь методом Next будем шагать по каждому столбцу и собирать сведения о нём, как: имя столбца, локализованное имя, тип данных и максимальный размер данных для этого столбца при помощи набора методов, описанных на страничке ICertView2. Вот как это выглядит:

PS C:\> $CaView = New-Object -ComObject CertificateAuthority.View
PS C:\> $CA = "dc1\Contoso CA"
PS C:\> $CaView.OpenConnection($CA)
PS C:\> $Columns = $CaView.EnumCertViewColumn(0)
PS C:\> $Columns.Next()
0
PS C:\> $Columns.GetName()
Request.RequestID
PS C:\> $Columns.GetDisplayName()
Request ID
PS C:\> $Columns.GetType()
1
PS C:\> $Columns.GetMaxLength()
4
PS C:\> $Columns.Next()
1
PS C:\> $Columns.GetName()
Request.RawRequest
PS C:\> $Columns.GetDisplayName()
Binary Request
PS C:\> $Columns.GetType()
3
PS C:\> $Columns.GetMaxLength()
65536
PS C:\>

После метода Next мы видим текущий индекс столбца. Что касается вывода метода GetType(), то вместо типа данных мы видим только циферки. Это нормальное поведение для CryptoAPI интерфейсов. Каждому числу соответствует свой тип данных (их поддерживается всего 4) и вот как они расшифровываются:

  • 1 = Long
  • 2 = DateTime
  • 3 = Binary
  • 4 = String

Если всё это затолкать в цикл DO…UNTIL, можно всё это дело автоматизировать. По правде говоря некоторые столбцы могут содержать массив данных и это можно проверить при помощи метода IsIndexed. Давайте теперь напишем окончательный скрипт, который нам по одному клику выдаст всю схему БД:

function Get-CADataBaseSchema {
[CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [string]$CAConfig
    )
    # создаём объект ICertView
    try {$CaView = New-Object -ComObject CertificateAuthority.View}
    catch {Write-Error "Unable to instantiate ICertView object"; return}
    # открываем подключение к CA
    $CaView.OpenConnection($CAConfig)
    # говорим, что мы хотим посмотреть схему
    $Columns = $CaView.EnumCertViewColumn(0)
    # начинаем итерацию по столбцам БД
    [void]$Columns.Next()
    do {
        # создаём временный объект, чтобы получить красивый вывод и наполняем его данными
        $Column = "" | Select Name, DisplayName, Type, MaxLength
        $Column.Name = $Columns.GetName()
        $Column.DisplayName = $Columns.GetDisplayName()
        $Column.Type = switch ($Columns.GetType()) {
            1 {"Long"}
            2 {"DateTime"}
            3 {"Binary"}
            4 {"String"}
        }
        [string]$Column.MaxLength = $Columns.GetMaxLength()
        if ($Columns.IsIndexed() -eq 1) {$Column.MaxLength += ", Indexed"}
        $Column
    } until ($Columns.Next() -eq -1)
    # закрываем подключение к БД
    $Columns.Reset()
}

А вывод весьма простенький:

PS C:\> Get-CADataBaseSchema "dc1\Contoso CA"

Name                          DisplayName                   Type                          MaxLength
----                          -----------                   ----                          ---------
Request.RequestID             Request ID                    Long                          4, Indexed
Request.RawRequest            Binary Request                Binary                        65536
Request.RawArchivedKey        Archived Key                  Binary                        65536
Request.KeyRecoveryHashes     Key Recovery Agent Hashes     String                        8192
Request.RawOldCertificate     Old Certificate               Binary                        16384
Request.RequestAttributes     Request Attributes            String                        32768
Request.RequestType           Request Type                  Long                          4
Request.RequestFlags          Request Flags                 Long                          4
Request.StatusCode            Request Status Code           Long                          4
Request.Disposition           Request Disposition           Long                          4, Indexed
Request.DispositionMessage    Request Disposition Message   String                        8192
Request.SubmittedWhen         Request Submission Date       DateTime                      8, Indexed
Request.ResolvedWhen          Request Resolution Date       DateTime                      8, Indexed
Request.RevokedWhen           Revocation Date               DateTime                      8
Request.RevokedEffectiveWhen  Effective Revocation Date     DateTime                      8, Indexed
Request.RevokedReason         Revocation Reason             Long                          4
Request.RequesterName         Requester Name                String                        2048, Indexed
Request.CallerName            Caller Name                   String                        2048, Indexed
Request.SignerPolicies        Signer Policies               String                        8192
Request.SignerApplicationP... Signer Application Policies   String                        8192
Request.Officer               Officer                       Long                          4
<...>

В следующей части (или частях, пока ещё не придумал) поговорим о том, как блуждать по самой БД.


Share this article:

Comments:

Comments are closed.