А знаете ли вы как можно легко получить список всех Enterprise CA в текущем домене? А в текущем лесу? Оказывается это очень легко! ADSI — самый лучший способ, если вы хотите пошариться в своей базе AD. Список таких CA находится по пути:
CN=Enrollment Services, CN=Public Key Services, CN=Services, CN=Configuration, DC=Domain, DC=COM
Последние 2 значения уже будут отличаться в зависимости от имени домена. Чтобы получить список объектов по этому пути нужно просто создать соответствующий LDAP объект. Объект делается просто, сначала указывается тип объекта [ADSI], следом идёт префикс ссылки LDAP:// (почти как HTTP://) и после префикса уже этот путь (который называется Distinguished Name или просто DN):
[Administrator] $CA = [ADSI]"LDAP://CN=Enrollment Services, CN=Public Key Services, CN=Services, CN=Configuration, DC=co ntoso,DC=COM" [Administrator] $CA distinguishedName : {CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=com} Path : LDAP://CN=Enrollment Services, CN=Public Key Services, CN=Services, CN=Configuration, DC=contoso,DC =COM [Administrator] $CA.distinguishedName CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=com
Если посмотреть этот путь в ADSIEdit.msc, то мы увидим, что это контейнер. А раз это контейнер, то нам нужно в него заглянуть. Здесь, к сожалению, нельзя сделать dir $CA.distinguishedName, а так хочется. Чтобы посмотреть содержимое нужно использовать свойство Children (ворненк, дети отаке!):
[Administrator] $ca.Children distinguishedName : {CN=contoso-DC2-CA,CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=co ntoso,DC=com} Path : LDAP://CN=contoso-DC2-CA,CN=Enrollment Services,CN=Public Key Services, CN=Services, CN=Configurati on, DC=contoso,DC=COM distinguishedName : {CN=Contoso CA,CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=contos o,DC=com} Path : LDAP://CN=Contoso CA,CN=Enrollment Services,CN=Public Key Services, CN=Services, CN=Configuration, DC=contoso,DC=COM [Administrator]
Уже отсюда невооружённым глазом видны имена CA. Собственно, можно показать только имя самого CA и компьютера, на котором работает этот CA:
[Administrator] $ca.Children | ft Name, DNSHostName Name DNSHostName ---- ----------- {contoso-DC2-CA} {dc2.contoso.com} {Contoso CA} {DC1.contoso.com} [Administrator]
Здесь есть один важный нюанс. Если получить этот LDAP объект в PowerShell 1.0, то он будет содержать только Distinguished Name, а свойство Children будет отсутствовать в нём. Для этого нужно воспользоваться свойством PSBase, в котором уже будет Children. Командой Select можете выводить на экран и другие свойства, какие вы захотите:
PS C:\> $ca.children MemberType : Method OverloadDefinitions : TypeNameOfValue : System.Management.Automation.PSMethod Value : Name : children IsInstance : True PS C:\> $ca.psbase.children distinguishedName ----------------- {CN=contoso-DC2-CA,CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=com} {CN=Contoso CA,CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=com} PS C:\> $ca.psbase.children | select Name, DNSHostname Name DNSHostname ---- ----------- {contoso-DC2-CA} {dc2.contoso.com} {Contoso CA} {DC1.contoso.com} PS C:\>
Поэтому для обратной совместимости между версиями лучше использовать PSBase. В этом объекте будут содержаться не только CA вашего домена, а во всех доменах вашего леса, поскольку эта часть AD реплицируется как Forest naming context, т.е. между всеми контроллерами в лесу. Жизнь была бы неинтересной, если в каждом новом домене приходилось бы переписывать хвост (которая определяет домен, в котором следует искать) каждый раз. Для универсальности можно пойти на военную хитрость — раздобыть FQDN текущего домена, разобрать его и воткнуть в LDAP запрос. Получить имя текущего домена можно очень просто, с использованием статического метода GetCurrentDomain() класса System.DirectoryServices.ActiveDirectory.Domain. На самом деле у этого класса есть ещё куча других полезных методов, поэтому не лишним будет заглянуть по ссылке.
PS C:\> [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() Forest : contoso.com DomainControllers : {DC1.contoso.com} Children : {} DomainMode : Windows2003Domain Parent : PdcRoleOwner : DC1.contoso.com RidRoleOwner : DC1.contoso.com InfrastructureRoleOwner : DC1.contoso.com Name : contoso.com PS C:\>
И свойство Name будет содержать имя нашего домена. Что дальше? А дальше, вполне очевидно, что нам надо заменить все точки на строку вида ", DC=". Вот так:
PS C:\> "contoso.com" -replace "\.", ", DC=" contoso, DC=com
А перед первым именем эту часть можно написать ручками. В итоге универсальная часть кода получится вот такая:
$domain = ([System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()).Name $domain = "DC=" + $domain -replace '\.', ", DC=" $CA = [ADSI]"LDAP://CN=Enrollment Services, CN=Public Key Services, CN=Services, CN=Configuration, $domain"
Вот теперь у нас есть всё необходимое, чтобы написать простеньку функцию:
function Get-CertificationAuthority ([string]$CAName) { $domain = ([System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()).Name $domain = "DC=" + $domain -replace '\.', ", DC=" $CA = [ADSI]"LDAP://CN=Enrollment Services, CN=Public Key Services, CN=Services, CN=Configuration, $domain" $CAs = $CA.psBase.Children | %{ $current = "" | Select CAName, Computer $current.CAName = $_ | %{$_.Name} $current.Computer = $_ | %{$_.DNSHostName} $current } if ($CAName) {$CAs = @($CAs | ?{$_.CAName -eq $CAName})} if ($CAs.Count -eq 0) {throw "Sorry, here is no CA that match your search"} $CAs }
Если выполнить эту функцию без аргументов, то она вернёт все CA в лесу. Но можно указать и какой-то один для каких-то других целей.
Comments: