Behandelte Themen unter "Handling von Zertifikaten"

  1. Einleitung

  2. Zertifikatsverwaltung
    2.1 Zertifikatsverwaltung mit dem .Net Namespace "System.Security.Cryptography.X509Certificates"
          2.1.1 X509Certificate2-Klasse
                   2.1.1.1 Ein X509Certificate2-Object erstellen
                               Beispiel 1a: Auslesen der Zertifikate im lokalen Store mittels dem Zertifikatsprovider
                               Beispiel 1b: Auslesen der Zertifikate im lokalen Store mittels der .Net-Klasse X509Store
                               Beispiel 2a: Ein Zertifikatsobjekt aus einer lokalen pfx-Zertifikatsdatei erstellen (Import-Methode)
                               Beispiel 2b: Ein Zertifikatsobjekt aus einer lokalen pfx-Zertifikatsdatei erstellen (cmdlet: get-pfxcertificate)
                    2.1.1.2 Anwendungen von X509Certificate2
                               Beispiel 1: Anwenden von Eigenschaften und Methoden auf ein Zertifikatsobjekt
                               Beispiel 2: Zertifikat aus *.cer Datei importieren und Eigenschaften auslesen
          2.2.2 X509Store-Klasse     
                   Beispiel 1: Mehrere Klassen des System.Security.Cryptography.X509Certificates-Namespaces im Einsatz
          2.2.3 Sonstige .Net Klassen
                   Beispiel 1a: Exportieren eines Zertifikats in eine pfx-Datei (Klasse X509ContentType)
                   Beispiel 1b: Exportieren aller Zertifikats aus dem Currentuser\my-Store in pfx-Dateien (Klasse X509ContentType)
    2.3 Zertifikatsverwaltung mit dem Zertifikatsprovider
    2.4 Zertifikatsverwaltung mit dem Quest QAD-SnapIn
          Beispiel 1: Auflisten von Zertifikaten mit QAD (Storelocation: LocalMachine, Store: My)
          Beispiel 2: Anzeigen aller Zertifikate im LocalMachineStore
          Beispiel 3a Anlage eines zusätzlichen Zertifikatsstores für den "aktuellen Benutzer" mit QAD
          Beispiel 3b: Löschen eines zusätzlichen Zertifikatsstores für den "aktuellen Benutzer" mit QAD
          Beispiel 4: Exportieren aller Zertifikats aus dem Currentuser\my-Store in pfx-Dateien
          Beispiel 5: Ein Zertifikatsobjekt mit einem Quest-cmdlet erstellen

******************************************************************************************************

 

1 Einleitung

Eine gute Einführung in die Arbeitsweise von Zertifikaten findet man hier:  Technet: How Certificate Services Works


Unter diesem Kapitel möchte ich erarbeiten, wie man Informationen aus Zertifikaten lesen kann, Zertifikate monitort oder diese im- und exportiert. Dazu gehören detaillierte Fragen wie

- haben meine Rechner die richtigen Zertifikate im richtigen Zertifikatsstore
- sind diese Zertifikate gültig
- wann laufen die Zertifikate ab
- sind Zertifikate gesperrt
- ist die Zertifikatskette überall vorhanden
- welche Fileformate soll man für welchen Einsatzzweck wählen

Viele dieser Aufgaben erledigen sich im Zusammenspiel mit einer in ein ActiveDirectory integrierten Zertifizierungsstelle und der Verwendung von GroupPolicies quasi von alleine. Möchte man aber die Verantwortung einer Zertifizierungsstelle nicht im eigenen Hause tragen, oder kommt über Wirtschaftlichkeitsberechnungen zu dem Schluss sich seine Zertifikate lieber von einer externen CA zu besorgen, so können Powershell und .Net wertvolle Werkzeuge für die Administration und das Monitoring der Zertifikate sein.


Eine Alternative zur manchmal etwas aufwändigen .Net-Schreibweise für dieses Aufgabenspektrum ist der Einsatz der
 Quest Software: Free PowerShell Commands for Active Directory

Dabei handelt es sich um ein kostenloses SnapIn, das unter anderem für den Bereich "X.509 Certificate Management" eine Reihe interessanter cmdlets mitbringt. Einige der Beispiele in diesem Kapitel setzen die Installation dieses SnapIns voraus. Module und SnapIns allgemein habe ich in diesem Kapitel unter "My Powershell" näher erläutert .

Alle cmdlets des SnapIns hat Quest im Adminguide "ActiveRoles_MgmtShellForAD_14_AdminGuide_English.pdf" dokumentiert, der unter dem obigen Questlink downloadbar ist.
Für die "PKI cmdlets" gibt es nocheinmal ein Extra Paper, für das sich der Download durchaus lohnt.  Quest Software: Guide for Using Quest AD-PKI cmdlets
Der Guide umfasst etwa 50 Seiten und gibt in der ersten Hälfte eine meiner Meinung nach sehr gute Einführung über Zertifikate und behandelt im zweiten Teil die PKI-cmdlets.

 

2 Zertifikatsverwaltung

2.1 Zertifikatsverwaltung mit dem .Net Namespace "System.Security.Cryptography.X509Certificates"

 MSDN: System.Security.Cryptography.X509Certificates-Namespace

Unter diesem Namespace sind alle Klassen enthalten, die für die .Net -Programmierung mit Zertifikaten benötigt werden

 

2.1.1 X509Certificate2-Klasse

MSDN:  X509Certificate2 Class

Möchte man mit bestimmten X509-Zertifikaten arbeiten, so benötigt man aus dem "System.Security.Cryptography.X509Certificates Namespace" entweder die Klasse "X509Certificate" oder "X509Certificate2". Beide Klassen stellen X509-Zertifikat dar und beinhalten Methoden und Eigenschaften für den Umgang mit Zertifikaten.

Die  MSDN nennt als hauptsächlichen Unterschied beider Klassen:

"The primary difference between the X509Certificate and the X509Certificate2 class is that the private key must reside in the certificate store for the X509Certificate class."

In diesem Kapitel 2.1.1 und seinen Unterkapiteln kümmere ich mich nur um die Klasse X509Certificate2!

 

2.1.1.1 Ein X509Certificate2-Object erstellen

Powershell bringt auch in der Version 2 nur wenige cmdlets mit, mit denen ein gewohnt einfacher und komfortabler Umgang mit Zertifikaten möglich wäre. Um Objekte der Klasse "X509Certificate2" zu erzeugen, stehen damit folgende Werkzeuge zur Verfügung:

  a) Zertifikatsprovider

  b) .Net Klassen

  c) Powershell cmdlet "Get-PfxCertificate"

Anbei einige Beispiele, die verdeutlichen sollen, wie mit den eben genannten Werkzeugen Zertifikatsobjekte erzeugt werden können.


Beispiel 1: Auslesen der Zertifikate im lokalen Store
mittels dem Zertifikatsprovider

$Cert=@()
$Cert=(GCI cert:/localmachine/my | Select -First 1)
$Cert.gettype() | Format-Table Name,BaseType -auto

#Ausgabe
Name             BaseType                                                    
----             --------                                                    
X509Certificate2 System.Security.Cryptography.X509Certificates.X509Certificate

Anmerkung 1: Die Syntax des Zertifikatsprovider ist sicherlich die einfachste. Sein Nachteil liegt in der Beschränkung auf die Stores der lokalen Maschine. Möchte man auf die Stores von anderen Maschinen zugreifen, ist der direkte, aber etwas aufwändigere Aufruf der .Net-Klasse der richtige Ansatz (siehe Beispiel 1b).

Anmerkung 2: Die erste Codezeile
"$Cert=@()"
deklariert $Cert als Array.  Sobald $Cert mehr als einen Wert enthält, ist dieser Befehl nicht notwendig. Bei nur einem Wert würde dieser Wert aber nicht ausgegeben werden.


Beispiel 2: Auslesen der Zertifikate im lokalen Store
mittels der .Net-Klasse X509Store

Der Vorteil des folgenden Beispiels gegenüber dem vorigen Beispiel 1a) liegt hier in der Remotefähigkeit.

$Cert=@()
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("\\Dom1Dc01\My","LocalMachine")
$store.Open("ReadOnly")
$Cert=($store.certificates | Select -First 1)
$Cert.gettype() | Format-Table Name,BaseType -auto

#Ausgabe
Name             BaseType                                                    
----             --------                                                    
X509Certificate2 System.Security.Cryptography.X509Certificates.X509Certificate

 MSDN: X509Store-Konstruktor (StoreName, StoreLocation)



Beispiel 3: Ein Zertifikatsobjekt aus einer lokalen pfx-Zertifikatsdatei erstellen (Import-Methode)

$Cert=@()
$cert = new-object System.Security.Cryptography.X509Certificates.X509Certificate2    
$pfxPass = "PW123" 
$certpath="c:\temp\TestCert1.pfx"   
$cert.import($certPath,$pfxPass,"Exportable,PersistKeySet")
$cert.gettype() | Format-Table Name, BaseType -auto  

#Ausgabe
Name             BaseType                                                    
----             --------                                                    
X509Certificate2 System.Security.Cryptography.X509Certificates.X509Certificate

Anmerkungen zu Beispiel 1c:
- Im Beispiel 1 des Kapitel 2.2.3 findet ihr einen Code um Zertifikate in pfx-Dateien zu exportieren



Beispiel 4: Ein Zertifikatsobjekt aus einer lokalen pfx-Zertifikatsdatei erstellen (cmdlet: get-pfxcertificate)

siehe  Technet: get-pfxcertificate

$Cert=@()
$cert=get-pfxcertificate -filepath 'C:\mycerts\test2.pfx'
$cert.gettype() | Format-Table Name, BaseType -auto

#Ausgabe
Name             BaseType                                                    
----             --------                                                    
X509Certificate2 System.Security.Cryptography.X509Certificates.X509Certificate


Zusammenfassung Beispiele 1 bis 4:
Wie man an der identischen Ausgabe des Typs der Beispiele sieht, enthält die Variable $Cert tatsächlich jeweils ein X509-Zertifikat. Jetzt kann das Zertifikatsobjekt mit einer ganzen Reihen von Eigenschaften und Methoden der X509Certificate2-Klasse behandelt werden.
Das nachfolgende  Kapitel 2.1.1.2 zeigt noch ein paar Möglichkeiten die Objekte weiter zu behandeln.

 MSDN: X509Certificate2-Konstruktor (String, SecureString, X509KeyStorageFlags)

 MSDN: X509KeyStorageFlags-Enumeration


Ein weiteres ausgearbeitetes Beispiel:  Technet Scripting Guys: Use PowerShell and .NET to Find Expired Certificates

 

2.1.1.2 Anwendungen von X509Certificate2

Beispiel 1: GetIssuername(), NotAfter, Verify() 

$Cert=@()
$Cert=(GCI cert:/localmachine/my | Select -First 1) #vgl. alternativ die Beispiel 1b) und 1c)

$Cert.getissuername()  #Methode
$Cert.NotAfter #Eigenschaft
$Cert.Verify() #Methode

#Ausgabe
CN=TestCA1
Samstag, 25. Februar 2113 14:01:04
False

In diesem Beispiel werden die Methoden
  - getissuername() - liefert den Namen der Zertifizierungsstelle ab, die das X.509-Zertifikat (v.3) ausgestellt hat
  - Verify() - Führt mithilfe von Basisvalidierungsrichtlinien eine Validierung von X.509-Ketten aus
und die Eigenschaft
   - Notafter - Ruft das Datum in Ortszeit ab, ab dem ein Zertifikat nicht mehr gültig ist
für das erste Zertifikat im My-Store des Systemaccounts aufgerufen.

 

Beispiel 2: Zertifikat aus *.cer Datei importieren und Eigenschaften auslesen

In der MSDN befindet sich ein Visualbasic-Programmcode, den ich hier nach Powershell konvertieren möchte. Dieser Code zeigt meiner Meinung nach schön die Möglichkeiten der X509Certificate2 Klasse auf
Der orginal VB-Code befindet sich am Ende des Artikels unter MSDN:  X509Certificate2.Version Property

function readFile{
# Einlesen eines Zertifikatfiles in ein Bytearray
    param($filename)
    $FileStream = New-Object System.IO.FileStream ($filename,[System.IO.FileMode]::Open,[System.IO.FileAccess]::read)
    [int]$size = [math]::truncate($filestream.Length)
    [byte[]] $data = new-object byte[] $size
    $filestream.Read($data, 0, $size) | out-null
    return $data
}

function showCertInfo{
    param($filename)
    $X509 = new-object System.Security.Cryptography.X509Certificates.X509Certificate2   
    [byte[]] $rawdata=readfile -filename $filename
    'Create X509Certificate2 object from .cer file.
    $X509.import($rawdata)
    #http://msdn.microsoft.com/en-us/library/ms148437.aspx
    #X509Certificate2.Import Method (Byte())

    "Subject: {1}{0}" -f [Environment]::NewLine,$x509.Subject
    "Issuer: {1}{0}" -f [Environment]::NewLine, $x509.Issuer
    "Version: {1}{0}" -f [Environment]::NewLine, $x509.Version
    "Valid Date: {1}{0}" -f [Environment]::NewLine, $x509.NotBefore
    "Expiry Date: {1}{0}" -f [Environment]::NewLine, $x509.NotAfter
    "Thumbprint: {1}{0}" -f [Environment]::NewLine, $x509.Thumbprint
    "Serial Number: {1}{0}" -f [Environment]::NewLine, $x509.SerialNumber
    "Friendly Name: {1}{0}" -f [Environment]::NewLine, $($($x509.PublicKey).Oid).FriendlyName
    "Public Key Format: {1}{0}" -f [Environment]::NewLine, $($($x509.PublicKey).EncodedKeyValue).Format($True)
    "Raw Data Length: {1}{0}" -f [Environment]::NewLine, $RawData.Length
    #"Certificate to string: {1}{0}" -f [Environment]::NewLine, $x509.ToString($True)
    #"Certificate to XML String: {1}{0}" -f [Environment]::NewLine, $($($x509.PublicKey).Key).ToXmlString($False)
   
   'Add the certificate to a X509Store.
    $store = New-Object System.Security.Cryptography.X509Certificates.X509Store
    $store.Open("MaxAllowed")
    $store.Add($X509)
    $store.close()
   
}

#Aufruf des Skripts
showCertInfo -filename "c:\mycerts\test.cer"

#Ausgabe

Subject: CN=Karl Napf, CN=Users, DC=Dom1, DC=intern

Issuer: CN=Dom1-CA01, DC=Dom1, DC=intern

Version: 3

Valid Date: 13.05.2011 14:57:07

Expiry Date: 12.05.2012 14:57:07

Thumbprint: CFAC05F46158ABB0BC29D5EC30E10C06B9655B3F

Serial Number: 74E4644900000000005D

Friendly Name: RSA

Public Key Format: 30 82 01 0a 02 82 01 01 00 a8 dc b2 40 ed 27 4f 7d 19 bb 8e af 81 db bd 89 d4 e7 62 50 62 06 aa ec b9 7b 0a b3 73 71 58 1a 96 a3 e1 5e d8 11 f4 e5 c5 9e
 80 24 93 4f 57 65 5a 3c 26 9a ce 80 06 9c 4d a0 59 6c 7c 80 5a d3 c7 e7 09 06 df 17 6b 1f b6 94 cf 9b 8a 28 5b 65 b8 28 31 62 54 4e 38 be c5 cc 14 f6 ca 1f e0 2e 4b 66 ac
 24 d6 fe 03 75 0c 4c 68 6e c8 d2 7e e5 b8 f8 77 1c 67 18 98 55 a7 49 fa 51 fc e2 a1 ea 5b b6 73 d3 fe 00 91 88 df 81 66 f7 12 e6 9e 70 fa fe a3 79 31 ff ff 87 42 eb 34 9b
 af 1b 0e 5e 17 45 5c 5b 1e 40 28 09 da 53 6d 83 09 95 1a 72 6e 91 c8 97 8a a5 91 f5 81 5b ea 58 8a 37 e3 ce a7 77 2f d9 70 86 22 70 cb c0 16 d9 69 6f a6 5e 16 f0 b9 5e c7
 b9 6c 1b 06 08 42 e5 9b ad 60 b4 f9 99 59 4b 7b 38 14 70 61 4c ea 33 de c0 fc f1 3a cf c5 1f 6c 08 85 c9 15 0a 03 fe f4 93 f6 59 02 03 01 00 01

Raw Data Length: 2094

Steht kein Cer-Zertifikatsfile zur Verfügung, kann man sich einfach in der MMC -> Zertifikate (certmgr.msc) aus dem Container "Vertrauenswürdige Stammzertifizierungsstellen" ein paar Zertifikate mit "Alle Aufgaben -> Exportieren" exportieren. Dabei ist es egal, ob man als Format DER oder BASE-64 wählt.

Das Beispiel liest in der Function "readfile" eine Zertifikatsdatei im cer-Format in ein Bytearray ein. In der Function "showCertInfo" wird ein das Objekt $x509 aus der Klasse "X509Certificate2" erzeugt und mit der import-Methode mit den Daten aus dem Bytearray befüllt.
Anschliessend werden einige Eigenschaften des Objekts $X509 ausgelesen und ausgegeben.

weitere Links:

Zum Thema "ByteArray" siehe "Zertifikate -> Allgemeines -> 3.2 ByteArrays"
Zum Thema "Formatierung" siehe "Formatierung des Outputs -> 1 Schnelleinstieg in die Formatierung"

 

2.2.2 X509Store-Klasse

 MSDN: X509Store-Klasse


Beispiel 1: Mehrere Klassen des System.Security.Cryptography.X509Certificates-Namespaces im Einsatz

Unter den eben genannten MSDN-Link findet man wieder ein ausführliches Beispiel in VisualBasic zu den Klassen

- X509Store
- X509Certificate2
- X509Certificate2Collection

Dieses MSDN- Beispiel möchte ich ebenfalls nach Powershell konvertieren.

#Step 1
#Create new X509 store called teststore from the local certificate store.
$storename = "teststore"
$storelocation = "Currentuser"
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store($storename,$storelocation)
$store.Open("ReadWrite")

#Step 2
#Create certificates from certificate files.
$certificate1 = new-object System.Security.Cryptography.X509Certificates.X509Certificate2("c:\mycerts\zert1.cer")
$certificate2 = new-object System.Security.Cryptography.X509Certificates.X509Certificate2("c:\mycerts\zert2.cer")
$certificate5 = new-object System.Security.Cryptography.X509Certificates.X509Certificate2("c:\mycerts\zert5.cer")

#Step 3
#Create a collection and add two of the certificates.
$collection =  New-object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
$collection.Add($certificate2)
$collection.Add($certificate5)
      
#Step 4
#Add certificates to the store.
$store.Add($certificate1)
$store.AddRange($collection)

$storecollection = new-object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
$storecollection=$store.certificates

"Store name: {0}" -f $store.Name
"Store location: {0}" -f $store.Location
$x509 =new-object System.Security.Cryptography.X509Certificates.X509Certificate2
foreach($x509 in $storecollection){
     $x509.subject
     #$storecollection | %{$_.subject #Alternativ
}

#Step 5
#Remove a certificate
$store.Remove($certificate1)
$storecollection2 = new-object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
$storecollection2=$store.certificates
"{1}Store name: {0}" -f $store.Name, [Environment]::NewLine
$x509a =new-object System.Security.Cryptography.X509Certificates.X509Certificate2
foreach($x509a in $storecollection2){
   $x509a.subject
   #$storecollection | %{$_.subject #alternativ zu foreach
}

#Step 6
#Remove a range of certificates.
$store.RemoveRange($collection)
$storecollection3 = new-object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
$storecollection3=$store.certificates
"{1}Store name: {0}" -f $store.Name, [Environment]::NewLine
If ($storecollection3.Count -eq 0) {
   "Store contains no certificates."
}Else{
   $x509b =new-object System.Security.Cryptography.X509Certificates.X509Certificate2
   foreach($x509b in $storecollection3){
       $x509b.subject
       #$storecollection3 | %{$_.subject #alternativ zu foreach
       } #foreach
} #Endif

#Step 7
#Close the store.
$store.Close()

 

Stehen keine Cer-Zertifikatsfiles zur Verfügung, kann man sich einfach in der MMC -> Zertifikate (certmgr.msc) aus dem Container "Vertrauenswürdige Stammzertifizierungsstellen" ein paar Zertifikate mit "Alle Aufgaben -> Exportieren" exportieren. Dabei ist es egal, ob man als Format DER oder BASE-64 wählt.

Anmerkungen zum Code:

Step 1)
- Im Kapitel Allgemeines ->  2 CertificateLocation/ CertificateStore habe ich einige kurze Beispiele aufgelistet, wie mit der X509Store-Klasse Zertifikatstores behandelt werden können.

- lautet  $storelocation nicht "currentuser", sondern "localmachine", so kann mit $storename = "\\dom1dc01\teststore" auch ein Store auf einer Remotemaschine angelegt werden.

- Die Klasse X509Store ist überladen mit mehreren Konstruktoren. Das Beispiel nutzt den Konstruktor mit dem Parametern Storelocation und des Storenamens.  MSDN: X509Store-Konstruktor (StoreName, StoreLocation)

- Die möglichen Flags der Openmethode findet man  unter MSDN:  OpenFlags-Enumeration

Step 2)
Hier werden aus *.cer Files Objekte der Klasse X509Certificate2 erstellt. *.cer zeichnen sich dadurch aus, daß Sie keinen privaten Schlüssel besitzen.
Für X509Certificate2-Objekte mit privatem Schlüssel und Passwort muß die Import-Methode zusätzlich benützt werden. Der Import eines Zertifikats aus einer *.pfx Datei (= Zertifikate mit privatem Schlüssel) ist in Beispiel 3 unter  2.1.1.1 Ein X509Certificate2-Object erstellen beschrieben

Step 3)  
MSDN:  X509Certificate2Collection-Klasse

Die Klasse X509Certificate2Collection erstellt ein Array, dessen Elemente einzelne Zertifikate der Klasse X509Certificate2 sind. Mit der  Add-Methode werden Zertifikate am Ende des Arrays hinzugefügt

#Codeergänzung
$collection.count
$Collection[1].gettype() | Format-Table Name,BaseType -auto

#Ausgabe
2

Name             BaseType                                                    
----             --------                                                    
X509Certificate2 System.Security.Cryptography.X509Certificates.X509Certificate

 
Step 4)  
- dem in Step 1) erzeugten Objekt $store der Klasse X509Store einige Zertifikatsobjekte hinzugefügt, einmal als einzelnes Zertifikat ($certificate1) und einmal als Range ($Collection bzw. $certificate2 und $certificate5).

- die  X509Name- und  X509Location-Eigenschaft des $StoreObjects werden ausgegeben.


Step 5)
 
- Aus dem Objekt $StoreCollection2 wird ein einzelnes Zertifikat entfernt.


Step 6)
Aus dem Objekt $StoreCollection§ wird ein ein Zertifikatrange ($collection) entfernt.

 

2.2.3 Sonstige .Net Klassen

Beispiel 1a: Exportieren eines Zertifikats in eine pfx-Datei (Klasse X509ContentType)

Im Beispiel 1c des Kapitels 2.1 Überblick der verschiedenen Heransgehensweisen ..,  haben wir gesehen, wie man Zertifikate aus einer pfx-Datei importiert. Auch der umgekehrte Weg ist natürlich möglich, also ein Zertifikat etwa aus dem My-Store in eine pfx-Datei zu exportieren. Voraussetzung für den Export eines Zertifikats in eine pfx-Datei ist, daß im my-Store auch der private Schlüssel des Zertifikats gespeichert ist und dieser Schlüssel als exportierbar markiert ist.

$Cert=@()
$cert = (dir cert:\currentuser\my)[0]
$type = [System.Security.Cryptography.X509Certificates.X509ContentType]::pfx
$pass = ConvertTo-SecureString "Hurra" -AsPlainText -Force
$bytes = $cert.export($type, $pass)
[System.IO.File]::WriteAllBytes("c:\mycerts\file.pfx", $bytes)

#aus
#TechNet Blogs > My Nuggets > exporting certificate from user store to PFX using powershell  

Diesen Code habe ich in der Technet  hier gefunden.

Der Import eines Zertifikats aus einer *.pfx Datei ist in Beispiel 3 unter 2.1.1.1 Ein X509Certificate2-Object erstellen beschrieben

Beispiel 1b: Exportieren aller Zertifikats aus dem Currentuser\my-Store in pfx-Dateien (Klasse X509ContentType)

$Certs=@()
$certs = (dir cert:\currentuser\my)
$type = [System.Security.Cryptography.X509Certificates.X509ContentType]::pfx
$pass = ConvertTo-SecureString "Hurra" -AsPlainText -Force
$certs | % {
   $bytes = $_.export($type, $pass)
   if ($_.hasprivatekey){ #nur Zertifikate mit PrivatKey exportieren
      [System.IO.File]::WriteAllBytes("c:\mycerts\$($_.subject).pfx", $bytes)
      }else{
      "{0} hat keinen Privatekey und kann daher nicht in eine pfx-Datei exportiert werden" -f $_.subject
      }
   }

Der Code exportiert alle Zertifikate mit privatem Schlüssel in das Verzeichnis c:\mycerts. Leider lässt sich nicht steuern, ob alle Zertifikate der Zertifikatskette ebenfalls exportiert werden sollen. Anwendungen, die diese Kette benötigen, kommen mit den so erzeugten PFX-Files leider nicht zurecht.

Mehr Details zum PKCS#12 Standard gibt es unter:  RSA LaboratoriesPKCS #12: Personal Information Exchange Syntax Standard

Dieselbe Lösung erreicht man auch über das Quest Active Roles cmdlets "Export-QADCertificate", wie in Beispiel 4 unter 2.4 Zertifikatsverwaltung mit dem Quest QAD-SnapIn gezeigt. Der Einsatz des Export-QADCertificate ist weniger kryptisch, als die Programmierung mit .Net

 

2.3 Zertifikatsverwaltung mit dem Zertifikatsprovider

 Technet: Certificate Provider

Wie schon weiter oben beschrieben, bietet der Certificate Provider eine einfache Syntax an, um Objekte der Klasse X509Certificate2 zu erstellen. Das erstellte Objekt ist dasselbe, wie mit der ".Net-Klasse X509Certificate2" und "new-object". Siehe Kapitel 2.1.1.1

2.4 Zertifikatsverwaltung mit dem Quest QAD-SnapIn

Installation siehe: Kapitel 3.3.3 Module und SnapIns

Alle QAD-cmdlets mit Beispielen: Powergui - QAD cmdlets reference


Beispiel 1: Auflisten von Zertifikaten mit QAD (Storelocation: LocalMachine, Store: My)

Get-QADLocalCertificateStore My LocalMachine | Get-QADCertificate | Format-Table -autosize

#Ausgabe

IssuedBy  IssuedTo              ValidFrom  ValidTo
--------  --------              ---------  -------
Dom1-CA01 DOM1CLI01.Dom1.intern 02.05.2011 05.05.2011
Dom1-CA01 DOM1CLI01.Dom1.intern 26.04.2011 29.04.2011
Dom1-CA01                       26.04.2011 25.04.2012
Dom1-CA01 DOM1CLI01.Dom1.intern 26.04.2011 25.04.2012
Dom1-CA01 DOM1CLI01.Dom1.intern 02.05.2011 01.05.2012
Dom1-CA01 DOM1CLI01.Dom1.intern 26.04.2011 25.04.2012
Dom1-CA01 DOM1CLI01.Dom1.intern 02.05.2011 30.05.2011
Dom1-CA01 DOM1CLI01.Dom1.intern 26.04.2011 24.05.2011
Dom1-CA01 DOM1CLI01.Dom1.intern 02.05.2011 01.05.2012

 

Beispiel 2: Anzeigen aller Zertifikate im LocalMachineStore

Das Skript kennezeichnet alle Zertifikate, bei denen das heutige Datum nicht im Gültigkeitszeitraum des Zertifikats liegt

function getcerts{
  param($store,$storelocation)
  $certs=Get-QADLocalCertificateStore $store $storelocation | Get-QADCertificate
  $certs | foreach {
     try{
        $ISOlderThanValidfrom=$(get-date)-$($_.validfrom)
        $ISOlderThanValidto=$(get-date)-$($_.validto)
        $a= "{0,-60}  {1:d}  {2:d}  {3:0}  {4:0}" -f $_.issuedto,$_.validfrom,$_.validto,$Store,$storelocation
        if ($ISOlderThanValidfrom -lt 0) {  
           write-host "$a  Dieses Zertifikatsbeginn ist noch nicht gültig" -backgroundcolor yellow 
        }elseif($ISOlderThanValidto -gt 0){
           write-host "$a  Dieses Zertifikat ist abgelaufen" -backgroundcolor yellow
        }else{
           write-host $a
        } #if
      }#try
      catch{
      } 
  } #foreach
} #Function

$storelocation="localmachine"
$stores=Get-QADLocalCertificateStore -StoreLocation $storelocation
$stores | foreach {
  getcerts $_.name $storelocation 
  }

Die Funktion getcerts liest alle Zertifikate des übergebenen Stores aus und prüft seine Gültigkeit bezüglich des Gültigkeitzeitraums. Einen anderen Ansatz mit .Net findet man in diesem sehr lesenswerten Artikel der Scripting Guys

Technet - ScriptingGuy:  Use PowerShell and .NET to Find Expired Certificates

 

Beispiel 3a Anlage eines zusätzlichen Zertifikatsstores für den "aktuellen Benutzer" mit QAD

#erfordert die Installation und Registrierung des Quest-SnapIns

$storename = "TestUserStore04"
$storelocation = "Currentuser"
New-QADLocalCertificateStore -storename $storename -storelocation $storelocation

Im Vergleich zu Beispiel 1a, welches dasselbe Ergebnis liefert, ist dieser Weg sicherlich deutlich einfacher zu Skripten


Beispiel 3b: Löschen eines zusätzlichen Zertifikatsstores für den "aktuellen Benutzer" mit QAD

$storename = "TestUserStore03"
$storelocation = "Currentuser"

Remove-QADLocalCertificateStore -storename $storename -storelocation $storelocation

#identisch zu

Get-QADLocalCertificateStore -storename $storename -storelocation $storelocation | Remove-QADLocalCertificateStore

Einen vergleichbaren Code in native .Net habe ich nicht gefunden.

 

Beispiel 4: Exportieren aller Zertifikats aus dem Currentuser\my-Store in pfx-Dateien

$pw="hello"
Get-QADLocalCertificateStore My|  
 Get-QADCertificate | %{  
 Export-QADCertificate $_ -Mode chain -Format Pfx -Password (ConvertTo-SecureString $pw -asplaintext -force) -File c:\MyCerts\$($_.issuedto).pfx} | out-null

 Dieselbe Aufgabe lässt sich auch über reines .Net erledigen, wie in Beispiel 1b unter 2.2.3 Sonstige .Net Klassen gezeigt.

Die Verwendung des cmdlets "ConvertTo-SecureString" habe ich im Kapitel  Strings - 3. Verschlüsselung von Strings beschrieben

Weitere Beispiele für das cmdlet Export-QADCertificate:  Export-QADCertificate

 

Beispiel 5: Ein Zertifikatsobjekt mit einem Quest-cmdlet erstellen

Das Beispiel zeigt den Unterschied bei der Verwendung der QAD-cmdlets und der .Net-Programmierung. Eine Kombination von Objekten, Methoden oder Eigenschaften zwischen beiden Techniken wird also nicht so ohne weiteres funktionieren. (siehe auch Erklärung am Ende des Skripts)

$Cert=@()
$cert=Get-QADLocalCertificateStore My LocalMachine | Get-QADCertificate  | select -first 1 | Format-Table -autosize
$cert
$cert.gettype() | Format-Table Name, BaseType -auto
$cert | gm

#Ausgabe

IssuedBy  IssuedTo              ValidFrom  ValidTo  
--------  --------              ---------  -------  
Dom1-CA01 DOM1CLI01.Dom1.intern 02.05.2011 05.05.2011


Name     BaseType   
----     --------   
Object[] System.Array


   TypeName: Microsoft.PowerShell.Commands.Internal.Format.FormatStartData

Name                                    MemberType Definition                                                                             
----                                    ---------- ----------                                                                             
Equals                                  Method     bool Equals(System.Object obj)                                                         
GetHashCode                             Method     int GetHashCode() 
...  

Auch bei diesem Beispiel enthält die Variable $Cert ein Zertifikatsobject, allerdings keines der Klasse X509Certificate2, sondern der Klasse FormatStartData. Will man das Ergebnis weiterbearbeiten, muss man sich bei Quest und nicht in der MSDN informieren. (siehe: Quest ActiveRoles Management Shell for Active Directory).