Active Directory
banshee/active-directory-collection/active-directory/ssh/
adcs
The service of an Active Directory certification authority and the days before its certificate expires, by SSH and PowerShell
by banshee1 installation3 versions
v3Latest
Published on October 28, 2026. One naming convention across collections; documentation completed.
// The certification authority of Active Directory Certificate Services, by SSH: the state of its service,
// CertSvc, and the days left before its certificate expires. Once it expires, nothing it issued is trusted.
// Runs one PowerShell command that only reads: Win32_Service for the service CertSvc, and the certificates
// (.crt) the authority publishes in its folder CertEnroll (System32\CertSrv\CertEnroll), read by the class
// X509Certificate2 of .NET; the one that expires last is the current certificate of the authority, the
// former ones staying beside it after a renewal.
// The expiry of the certificate revocation list (CRL) is read by active-directory/https/crl, at its
// distribution point: the .NET Framework of Windows PowerShell has no class that reads a CRL.
need('protocol:ssh');
output('service', 'text', array('label' => 'Certificate Services'));
output('certificate', 'text', array('label' => 'Certificate of the authority'));
output('days-left', 'number', array('label' => 'Before the certificate expires', 'unit' => 'd'));
watch.expect('service-stopped', 'Certificate Services stopped', 'service', array('critical' => array('running')));
watch.below('expiring', 'Authority certificate expiring', 'days-left', array('warning' => 180, 'critical' => 60));
$read = ssh.run("powershell -NoProfile -NonInteractive -Command \""
. "$ErrorActionPreference = 'Stop'; "
. "[Console]::OutputEncoding = New-Object System.Text.UTF8Encoding; "
. "$state = [string](Get-CimInstance Win32_Service -Filter 'Name=''CertSvc''').State; "
. "$folder = Join-Path $env:windir 'System32\\CertSrv\\CertEnroll'; "
. "$subject = ''; $days = ''; "
. "if (Test-Path $folder) {"
. " $latest = Get-ChildItem $folder -Filter '*.crt'"
. " | ForEach-Object { New-Object Security.Cryptography.X509Certificates.X509Certificate2($_.FullName) }"
. " | Sort-Object NotAfter | Select-Object -Last 1;"
. " if ($latest) { $subject = $latest.Subject;"
. " $days = [long]($latest.NotAfter.ToUniversalTime() - [DateTime]::UtcNow).TotalDays } }; "
. "ConvertTo-Json -Compress -InputObject @{service = $state; subject = $subject; days = $days}\"");
$answer = text.trim($read['output']);
if (list.count(text.match($answer, '^\{')) == 0) {
fail('misconfigured', 'PowerShell did not return the certification authority', $answer . $read['errors']);
}
$authority = json.read($answer);
if ($authority['service'] == '') {
fail('misconfigured', 'Active Directory Certificate Services is not installed', $answer);
}
if ($authority['days'] == '') {
fail('misconfigured', 'No certificate of the authority in its CertEnroll folder', $answer);
}
// The state of the service is written by WMI in English: "Running", "Stopped", "Start Pending"...
value('service', text.lower(text.join(text.words($authority['service']), '-')));
value('certificate', $authority['subject']);
value('days-left', $authority['days']);