Den Autoenrollment Prozess für den angemeldeten Benutzer programmatisch auslösen

Folgendes Szenario angenommen:

  • Man schreibt ein Script oder eine Anwendung, die den Autoenrollment Prozess für den aktuell angemeldeten Benutzer auslösen soll.
  • Man stellt hierbei fest, dass der geplante Task nicht ausgeführt werden kann.
  • Die Fehlermeldung lautet:
The user account does not have permissions to run this task.

Unter dem Begriff Autoenrollment wird die automatische Zertifikatbeantragung im Windows-Ökosystem verstanden. Systeme, die Mitglied einer Active Directory Gesamtstruktur sind, können auf diese Weise automatisch Zertifikate von einer ins Active Directory integrierten Zertifizierungsstelle (engl. Enterprise Certification Authority) beantragen und erneuern. Für weitere Informationen siehe Artikel "Grundlagen manuelle und automatische Zertifikatbeantragung über Lightweight Directory Access Protocol (LDAP) und Remote Procedure Call / Distributed Common Object Model (RPC/DCOM)".

Der Auto Enrollment Prozess wird über vordefinierte geplante Tasks (unter "Microsoft" – "Windows" – "CertificateServicesClient") gestartet.

Neben den automatischen Triggern kann er beispielsweise mit folgendem Kommandozeilenbefehl ausgeführt werden:

certutil -pulse -user

Wirft man einen Blick in den Taskplaner, sieht man, dass dieser Befehl offenbar den geplanten Task "UserTask" ausführt.

Versucht man, den "UserTask" manuell zu starten, erhält man allerdings die Fehlermeldung, dass er aufgrund fehlender Rechte nicht gestaret werden kann.

Das gleiche Bild ergibt sich bei Aufruf über die Windows PowerShell mit dem "Start-ScheduledTask" Befehl:

Get-ScheduledTask -TaskName UserTask | Start-ScheduledTask
Start-ScheduledTask : Access is denied.
At line:1 char:40
+ Get-ScheduledTask -TaskName UserTask | Start-ScheduledTask
+                                        ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : PermissionDenied: (PS_ScheduledTask:Root/Microsoft/…S_ScheduledTask) [Start-ScheduledTask], CimException
+ FullyQualifiedErrorId : HRESULT 0x80070005,Start-ScheduledTask

Das Problem scheint darin zu liegen, dass der "UserTask" konfiguriert ist, mit dem "INTERACTIVE" Prinzipal ausgeführt zu werden.

Analysiert man die certutil.exe (beispielsweise mit dem API Monitor von Rohitab Batra), erkennt man, dass hier offenbar die TaskScheduler Klasse aufgerufen wird.

Bei dieser handelt es sich um ein unter Anderem über C# und PowerShell ansprechbares COM-Objekt ("Schedule.Service"). Dieses besitzt eine RunEx Methode, die mit dem Flag TASK_RUN_AS_SELF aufgerufen werden kann, was dazu führt, dass der Task mit der Identität des aktuell angemeldeten Benutzers ausgeführt wird.

Beispiel-Code

Kennen Sie TameMyCerts? TameMyCerts ist ein Add-On für die Microsoft Zertifizierungsstelle (Active Directory Certificate Services). Es erweitert die Funktion der Zertifizierungsstelle und ermöglicht die Anwendung von Regelwerken, um die sichere Automatisierung von Zertifikat-Ausstellungen zu realisieren. TameMyCerts ist einzigartig im Microsoft-Ökosystem, hat sich bereits in unzähligen Unternehmen auf der ganzen Welt bewährt und steht unter einer freien Lizenz. Es kann über GitHub heruntergeladen und kostenlos verwendet werden. Professionelle Wartung wird ebenfalls angeboten.

Windows PowerShell

Hier ein funktionsfähiger Beispielcode:

New-Variable -Option Constant -Name TaskRunFlags -Value @{
    TASK_RUN_NO_FLAGS = 0
    TASK_RUN_AS_SELF = 1
    TASK_RUN_IGNORE_CONSTRAINTS = 2
    TASK_RUN_USE_SESSION_ID = 3
    TASK_RUN_USER_SID = 4
}
$TaskScheduler = New-Object -ComObject("Schedule.Service")
$TaskScheduler.Connect()
$UserTask = $TaskScheduler.GetFolder("Microsoft\Windows\CertificateServicesClient").GetTask("UserTask")
$UserTask.RunEx(
    $null,
    $TaskRunFlags.TASK_RUN_AS_SELF,
    0,
    $null
)

C#

Ein Beispielcode für C# könnte wie folgt aussehen:

using TaskScheduler;

var Scheduler = new TaskScheduler.TaskScheduler();
Scheduler.Connect();
var UserTask = Scheduler.GetFolder("Microsoft\Windows\CertificateServicesClient").GetTask("UserTask");

UserTask.RunEx(
    null,
    (int)_TASK_RUN_FLAGS.TASK_RUN_AS_SELF,
    0,
    null
    );

Es muss im Visual Studio Projekt eine Referenz auf das TaskScheduler COM Objekt konfiguriert werden.

Weiterführende Links:

de_DEDeutsch