Contents of this directory is archived and no longer updated.

Продолжаем серию постов, которые посвящены базовому управлению объектами PKI в Active Directory. На данный момент мы рассмотрели сценарии публикации и просмотра сертификатов в Active Directory:

На данном этапе нам осталось последнее — удаление сертификатов из AD. Логика здесь очень простая: командой Get-ADPKIObject мы получаем коллекцию объектов, которые представляют собой сертификаты и через конвейер командой Remove-ADPKIObject указываем ID объектов, которые необходимо удалить. Если кто-то уже разбирал код предыдущих скриптов, то ему будет совсем нетрудно понять логику скрипта удаления объектов. Вот он, вместе с комментариями:

function Remove-ADPKIObject {
<#
.Synopsis
    Deletes certificates from Active Directory containers
.Description
    Deletes certificates from Active Directory containers by specifying particular ID or IDs
.Parameter ID
    Specifies certificate ID to delete that was set in Get-ADPKIObject command.
.EXAMPLE
    Get-ADPKIObject RootCA | Remove-ADPKIObject 2
    
    deletes certificate with ID = 2 in certificate viewer
.Outputs
    This command provide a resultant of operation.
#>
    param([int[]]$ID = $(throw "you must specify number of the object to delete"))
    # объявляем массив для хранения сертификатов из контейнера NTAuthCertificates
    begin {$sum = @()}
    process {
        # проверяем тип контейнера входящего объекта
        if ($_.Container -ne "NTAuthCertificates") {
            # если это не NTAuthCertificates, то проверяем, что ID текущего объекта
            # совпадает с ID, который нужно удалить
            if (@($ID) -contains $_.Id) {
                # если совпал, то собираем LDAP-запрос
                $ldap = [ADSI]"LDAP://CN=$($_.Container),$script:ConfigContext"
                # и удаляем текущий объект из AD
                $retn = $ldap.Delete("certificationAuthority", "CN=$($_.Subject)")
                if ($?) {
                    Write-Host "`'$($_.Subject)`' certificate was sucessfully deleted from `'$($_.Container)`' container"` 
                   -ForegroundColor Green
                }
            }
        # если контейнер текущего объекта является NTAuthCertificates, то собираем их все в массив
        } else {$sum += $_}
    }
    end {
        # проверяем, что массив непустой (т.е. надо что-то удалять из NTAuthCertificates)
        if ($sum) {
            # если массив непустой, то выбираем те элементы, которые нужно сохранить
            # т.е. ID которых не содержится в аргументах скрипта
            $sum = @($sum |?{$ID -notcontains $_.Id})
            # делаем LDAP-запрос к этому контейнеру
            $ldap = [ADSI]"LDAP://CN=$($_.Container),$script:ConfigContext"
            # проверяем, что после фильтрации, хотя бы один сертификат нужно оставить
            if ($sum.count -ge 1) {
                # записываем первый сертификат. Это необходимо потому что ADSI не поддерживает запись
                # массива сертификатов в свойство cACertificate, а только один сертификат в виде byte[]
                $ldap.put("cACertificate", [byte[]]$sum[0].RawCertificate)
                # а вот простое добавление он поддерживает. Тогда ADSI сам пересоберёт объекты
                # в свойстве в нужный формат данных. На данном этапе я применил маленькую хитрость:
                # как видно, я первый сертификат записываю дважды - предыдущей строкой и в первой итерации
                # текущей строки. Но это не проблема, поскольку метод SetInfo() записывает только уникальные
                # объекты, а дублирующиеся просто отбросит.
                $sum | %{$ldap.cACertificate += ,[byte[]]$($_.RawCertificate)}
                $ldap.SetInfo()
                if ($?) {
                    Write-Host "`'$($_.Subject)`' certificate was sucessfully deleted from `'$($_.Container)`' container"` 
                   -ForegroundColor Green
                }
            # а вот если после фильтрации объектов, у нас ничего не остаётся на запись, то это означает, что все
            # сертификаты из этого контейнера удаляются. Поэтому мы просто удаляем запись NTAuthCertificates.
            } else {
                ([ADSI]"LDAP://$script:ConfigContext").Delete("certificationAuthority", "CN=NTAuthCertificates")
                if ($?) {Write-Host "All certificates was sucessfully deleted from NTAuthCertificates entry ." -ForegroundColor Green
                    Write-Warning "This was last certificate in contaner. NTAuthCertificates entry is removed from Active Directory"
                }
            }
        }
    }
}

И теперь можно подвести краткие итоги. Мы смогли реализовать функционал certutil и других графических утилит (консоли MMC) в PowerShell значительно улучшив читабельность выходных объектов, адаптировали под работу из консоли (синтаксис стал значимо короче и более юзерфрендли) и шаг за шагом делаем из PowerShell единое консольное средство управления различными аспектами PKI.

Можно задать вопрос: а кто целевая аудитория всего этого? Целевая аудитория есть — администраторы PKI. Просто у вас не всегда будет возможность использовать графические консоли для решения этих задач (потому что их функционал далёк от идеального). Можно использовать certutil, который умеет много чего, но тоже имеет свои недостатки. Это и ужасный синтаксис, и вырвиглазный неуправляемый вывод результатов. Вобщем я надеюсь, что рано или поздно PowerShell сможет по-настоящему заменить certutil (который вообще-то ни в чём не виноват) и стать единой консолью всех Windows-администраторов. Вот не знаю на сколько это хорошо или плохо, потому что Microsoft всех насильно переводит на PowerShell (это очень показательно продемонстрировано в MS Exchange, где у вас по сути есть только PowerShell и всё). Обычно, насильно переводят на другой инструмент когда он является УГ и очень тяжело на него перевести людей посредством обычной рекламы. Но является ли PowerShell таким УГ? Я пока не готов ответить на этот вопрос. Моё мнение — PowerShell пока что особой революцией не стал. Даже не смотря на тонны рекламы, пеара и прочего, где восхваляют PowerShell, закидывают ногами CMD/WSH. Это обусловлено тем фактом, что не всегда PowerShell бывает удобней CMD/WSH, особенно в тривиальных задачах. Говорить, что синтаксис стал более простым и компактным тоже нельзя, потому что реально функционала из коробки хватает для решения процентов 10 задач. Всё остальное нужно скриптовать и программировать (да-да!) самому. Благо средств для этого в PowerShell хватает. Во что это обычно выливается? А в то, что в большинстве случаев результирующий объём кода будет не сильно меньше, чем в связке WSH + CMD. В любом случае преимущества PowerShell перед остальными очевидны, но они далеко не определяющие, ведь люди раньше решали свои задачи на WSH/CMD, пирожки продавались, бизнес шёл. С одной стороны Microsoft дал людям простор для творчества, т.е. делать в PowerShell всякие потрясающие штуки и всё такое. Но это не совсем то, что нужно было администраторам. Им нужна одна кнопка на весь экран с надписью «Сделать всё п**дато!». Пока что PowerShell и близко не готов стать такой кнопкой, а является «удочкой». Т.е. удочка у вас уже есть, а что касается конечной рыбы (результата), то дело осталось за малым — написать мега-скрипт. Мне вот интересно, что думают администраторы Exchange (поскольку пока что только они получили полноценную поддержку для своего продукта в PowerShell) — стало ли им жить легче с PowerShell или нет? Если да, то это может быть хорошим знаком, что однажды PowerShell станет такой кнопкой. И не будет более в системе certutil и всеми задачами будет рулить PowerShell (пока что это наиболее логичный сценарий развития событий). А вот если их жизнь не стала легче, то обещанной революции (которая по словам Microsoft уже наступила, как и вендекапец у луноходов) не будет, а будет просто какое-то логическое продолжение предыдущих инструментов для сценариев.

К чему я написал столько букв? К тому, что я ежедневно задаю себе один и тот же вопрос: а зачем я всё это делаю? А ответ найти очень непросто, потому что отмазы вида «проще, удобней, красивее» не годятся для серьёзного аргумента. На самом деле я не ищу ответ на него, а просто говорю себе «так надо» и делаю. Поэтому не надо меня использовать как пример «правильного пользователя PowerShell» и пытаться повторить что-то подобное астрономических масштабов на овер9000 строк — поверьте, оно не стоит того. Используйте его по мере сил. Если чего-то будет не хватать и его решение потребует значительных усилий — посмотрите на готовые утилиты, они наверняка будут уметь то, что вам надо.

Удачи!© One


Share this article:

Comments:

Comments are closed.