Ano, už je to tak. Zapojil jsem se zcela nezištně do pomoci našim bratrům a sestrám z Afriky. Dvě hodiny jsem pro ně dřel zcela bez nároku na odměnu. Doufám, že moje obětavá pomoc přispěje ke vzájemnému sblížení našich národů, povzbudí ještě více multikulturní souznění našich civilizací a probudí i v dalších duších naší společnosti touhu pomáhat strádajícím ajťákům v zámoří.
Publishing uživatelských certifikátů do Active Directory
No, ve skutečnosti mě známý, co jsme spolu dělali certifikaci Microsoft Certified Master (MCM) požádal o jeden skript :-) Nekecám ale, je z Afriky a jmenuje se Rob Silver (takže luxusní pirátské jméno). Tak doufám, že jeho zákazník přestane strádat a začně pilně šifrovat :-)
Jde o to, že jeden jeho zákazník má 5000 uživatelů s Exchange mailovými certifikáty, které vydala jeho vlastní AD CS certifikační autorita. Problém je, že lidi si chtějí mailovat zašifrovaně :-) K tomu potřebují mít svoje certifikáty (nebo přesněji řečeno naopak certifikáty kolegů) uloženy (publish) v Active Directory (AD) - to jest, v atributu userCertificate uživatelských účtů.
Ve vlastnostech šablony certifikátů (Certificate Template) je zaškrtávátko, které nutí přímo AD CS, aby tam vydané certifikáty zapisovala automaticky. Takže jakmile se certifikát vydá (issue), AD CS služba se sama připojí do Active Directory a ten certifikát uloží danému uživateli do jeho účtu.

Jenže k tomu potřebuje mít počítač s AD CS oprávnění zapisovat do toho userCertificate atributu. K tomu slouží skupina Cert Publishers. Problém byl, že v jejich případě nebyl počítač s AD CS členem této skupiny. A přitom už dávno vydali těch 5000 certifikátů. Jak to teď zpětně dohnat?
CERTUTIL a DSPUBLISH pro vydané certifikáty
Už jsem tu zmiňoval skriptování ohledně vydaných certifikátů - konkrétně jsem zneplatňoval různé staré certifikáty, aby to neotravovalo v databázi. Takže to použijeme podobně. K vylistování všech certifikátů, které nás zajímají jsem použil:
CERTUTIL -view -restrict
Což vybere pouze vydané a platné certifikáty. Dál to ještě přefiltruju podle data jejich platnosti, abych zbytečně nepublikoval něco, co už určitě neplatí. Následuje poměrně komplexní PowerShell skript, kterým se toho dosáhne. Jediné, co si musíte změnit je jméno šablony (certificate template), kterou chcete publikovat. Stáhnout si můžete přímo i .TXT soubor, který to všechno obsahuje:
# Specify the friendly name of the certificate template
# Only certificates with the template will be processed
$certTemplate = 'GOPAS Domain Logon User'
# The script processes only certificates whose NotAfter is still in the future from today
$expirationDate = Get-Date
# Obtain all issued certificates, regadless their effective date or template
# NotBefore cannot be used here as -restrict, because it produces malformed CSV
# CertificateTemplate cannot be used hare as -restrict,
# because it contains template OID which we do not know
$allIssued = CERTUTIL -view -restrict "Disposition=20" `
-out "NotBefore, NotAfter, SerialNumber, CertificateTemplate, CommonName, EMail, RequesterName" csv | `
ConvertFrom-Csv
Write-Host "All issued certificates with future expiration: " $allIssued.Count
# Filter out certificates which started before our effective date
# Filter out other certificate templates as well
$currentTemplates = $allIssued | ? { `
($_."Certificate Expiration Date" -gt $expirationDAte) -and
($_."Certificate Template" -like "*$certTemplate") }
if ($currentTemplates -eq $null) {
Write-Host "No certificates to be published"
} else {
if ($currentTemplates -is [array]) {
Write-Host "Current certificates with the correct template: " $currentTemplates.Count
} else {
Write-Host "Current certificates with the correct template: " 1
}
# The output of CERTUTIL -view -out RawCertificate is not minimalistic
# This function extracts the pure RawCertificate from the command output
function Extract-RawCert($certUtilOutput)
{
$uBound = $certUtilOutput.Count - 1
$header = "-----BEGIN CERTIFICATE-----"
$footer = "-----END CERTIFICATE-----"
$rawCert = @()
$i = 0
while (($i -lt $uBound) -and ($certUtilOutput[$i].Trim() -notlike "$header*")) { $i ++ }
if ($i -lt $uBound) {
while (($i -lt $uBound) -and ($certUtilOutput[$i].Trim() -notlike "$footer*")) {
$rawCert += $certUtilOutput[$i].Trim()
$i ++
}
if ($i -lt $uBound) {
$rawCert += $footer
return $rawCert
}
}
return $null
}
$currentTemplates | % { `
$condition = "SerialNumber=$($_.'Serial Number')" ; `
$utilOutput = CERTUTIL -view -restrict "$condition" -out "RawCertificate" ; `
$rawCert = Extract-RawCert($utilOutput) ;
$tmpFile = [System.IO.Path]::GetTempFileName()
$rawCert | Out-File $tmpFile -Force
Write-Host "Publishing:"
$_
CERTUTIL -f -dsPublish $tmpFile
# To publish to a different user, use addStore with a distinguishedName
# (note the tripple slash ///)
#
# CERTUTIL -f -addStore '
# "LDAP:///cn=judit sik,ou=users,ou=company,dc=ad,dc=gopas,dc=cz?userCertificate" $tmpFile
}
}
Poznámečky na závěr:
- nefiltruju rovnou platnost certifikátů pomocí -restrict "NotAfter", protože to produkuje zkurvené CSV.
- šablonu certifikátů (certificate template) taky filtruju až později pomocí PowerShell Where-Object (alias ?), protože ta hodnota obsahuje ještě její OID a nechtělo se mi to zjišťovat dopředu z Active Directory.
- CERTUTIL -dsPublish bohužel potřebuje dostat vstupní soubor - jak u blbejch - neumí to zřejmě publikovat certifikát rovnou z databáze. Takže musím ty certifikáty co dostanu vyhodit do dočasného souboru a ten potom teprve vypublikovat.