Comment signer un script Powershell ?

I. Présentation

Aujourd'hui dans un environnement Microsoft, il y a mille et une raisons d'utiliser PowerShell ! Que ce soit pour l'administration et la configuration des serveurs, mais aussi pour exécuter des scripts via GPO sur les postes clients. Pour avoir cette possibilité qui est clairement indispensable, sans remettre en cause la sécurité des postes clients, il s'avère pertinent de signer les scripts PowerShell pour autoriser uniquement les scripts signés sur vos postes clients. Ceci vous permettra d'exécuter vos scripts sur un poste où la stratégie d'exécution PowerShell est définie sur "AllSigned".

Avant de continuer, vous devez avoir une autorité de certification opérationnelle, vous pouvez lire notre tutoriel à ce sujet : Créer une autorité de certification ADCS. Pour les tests, prévoyais également un poste client dans le domaine.

II. Générer un certificat pour signer du code

Connectez-vous sur votre autorité de certification (où le rôle ADCS est présent) et ouvrez une console PowerShell en tant qu'administrateur. Nous allons devoir créer un certificat dédié à la signature de code, mais avant cela il faut inclure le template grâce à la commande suivante :

Add-CATemplate -Name CodeSigning

Confirmez l'exécution de l'action, et listez les templates de votre autorité de certification : "CodeSigning" doit apparaître.

Toujours sur le serveur ADCS, ouvrez une console MMC vierge et ajoutez le composant "Certificats" pour l'utilisateur actuel.

Sur "Personnel", effectuez un clic droit et sélectionnez la tâche "Demander un nouveau certificat".

Sélectionnez "Stratégie d'inscription à Active Directory.

Nous allons demander un certificat "Signature du code", sélectionnez la case adéquate.

Si l'on regarde les détails, nous pouvons voir que le certificat sera valide 365 jours. Avant de cliquer sur "Inscription", cliquez sur "Propriétés" puis dans l'onglet "Clé privée" activez l'option "Permettre l'exportation de la clé privée".

Si vous obtenez le message "Opération réussie" alors c'est tout bon ! Vous pouvez afficher le certificat si vous le souhaitez.

Le certificat est bien valide 365 jours comme nous pouvons le voir (bon, j'avoue, ça fait un moment que j'ai pris les captures d'écrans...).

Maintenant que le certificat est créé, il ne reste plus qu'à l'utiliser pour signer un script PowerShell 🙂

III. Déployer le certificat sur les postes clients

Le certificat doit être approuvé par les postes clients, nous allons le déployer par GPO. Pour cela, il faut l'exporter donc toujours à partir de la console MMC précédemment ouverte, effectuez un clic droit sur le certificat puis lancez la tâche "Exporter".

Suivez l'assistant et sélectionnez les deux paramètres suivants : "Non, ne pas exporter la clé privée" et "X.509 binaire encodé DER (*.cer)". Enfin, donnez un nom au certificat et exportez-le.

Connectez-vous sur votre contrôleur de domaine et copiez le certificat dessus. Ensuite, créez une nouvelle GPO qui va déployer le certificat.

Voici à quel endroit vous devez importer le certificat (via un clic droit "Importer" une fois dans "Editeurs approuvés").

La GPO est prête, positionnez-la sur votre domaine pour que le certificat soit déployé ! Passons à la suite.

IV. Signer un script PowerShell

Basculez maintenant sur un poste client, idéalement Windows 10 puisque c'est la version qui tend à être utilisée à la place de Windows 7 petit à petit. Mettez à jour les GPO sur le poste et redémarrez-le :

gpupdate /force

Nous allons définir la politique d'exécution des scripts du poste sur "AllSigned" :

Set-ExecutionPolicy AllSigned

Maintenant qu'il est redémarré, le certificat doit être présent dans le magasin local. Nous pouvons le vérifier avec cette commande :

Get-ChildItem Cert:\CurrentUser\My\ -CodeSigningCert

Maintenant, nous allons exécuter le script "IT-CONNECT.ps1" qui n'est pas signé et vous pourrez constater que ça ne fonctionne pas. Ceci est logique car la stratégie est définie sur "AllSigned". Ce qui donne l'erreur suivante :

Tous les éléments étant maintenant réuni pour que l'on signe notre script PowerShell, on ne va pas s'en priver ! Pour signer le script, on va utiliser le code suivant :

$CertCodeSigning = Get-ChildItem Cert:\CurrentUser\My\ -CodeSigningCert
$ScriptToSign = "C:\Scripting\Scripts\IT-CONNECT.ps1"
$TimestampServer = "http://timestamp.comodoca.com/authenticode"

Set-AuthenticodeSignature $ScriptToSign -Certificate $CertCodeSigning -TimestampServer $TimestampServer

Voici quelques infos sur les variables utilisées :

  • CertCodeSigning : Chemin vers lequel récupérer le certificat de signature du code
  • ScriptToSign : Chemin vers le fichier PS1 de notre script PowerShell
  • TimestampServer : On s'appuie sur un service externe qui va permettre de dater notre signature, ainsi, lorsque le certificat sera expiré la signature restera valable car elle fût réalisée pendant que le certificat était valide

Enfin, on va utiliser ces 3 variables dans le cmdlet Set-AuthenticodeSignature pour signer le script PowerShell.

Si l'on ouvre le script, on voit qu'il contient maintenant une signature :

Retournez sur le poste client et exécutez le script à nouveau : il doit maintenant s'exécuter directement 😉

Voilà, vous pouvez maintenant mettre en place cette configuration et dégainer les signatures sur tout vos scripts PowerShell en production. Bien entendu, à chaque fois que vous modifiez un script déjà signé, il faudra le signer à nouveau.

En bonus, je vous livre un bout de code qui va signer automatiquement tous les fichiers PS1 contenu dans un dossier. Il vous suffit de modifier le chemin du dossier contenu dans la variable $ScriptFolder :

$CertCodeSigning = Get-ChildItem Cert:\CurrentUser\My\ -CodeSigningCert
$TimestampServer = "http://timestamp.comodoca.com/authenticode"

$ScriptFolder = "C:\Dossier\Scripts"
$ScriptList = (Get-ChildItem $ScriptFolder -Filter "*.ps1").FullName

Foreach($ScriptToSign in $ScriptList){

   Write-Output "Traitement du script : $ScriptToSign"
   Set-AuthenticodeSignature $ScriptToSign -Certificate $CertCodeSigning -TimestampServer $TimestampServer

}
Partagez cet article Partager sur Twitter Partager sur Facebook Partager sur Linkedin Partager sur Google+ Envoyer par mail

Florian BURNEL

Ingénieur système et réseau, cofondateur d'IT-Connect et Microsoft MVP "Cloud and Datacenter Management". Je souhaite partager mon expérience et mes découvertes au travers de mes articles. Généraliste avec une attirance particulière pour les solutions Microsoft et le scripting. Bonne lecture.

Nombre de posts de cet auteur : 5502.Voir tous les posts

9 thoughts on “Comment signer un script Powershell ?

  • Bonjour,
    Merci pour cet article. Je me demandai si il est possible de généré un certificat sur l’ADCS d’un domaine et appliquer ce certificat sur un poste qui n’est pas dans le domaine.
    Je cherche a signé un script powershell qui sera installé sur un poste connecté a aucun réseau ni domaine.

    Merci par avance.
    Gael

    Répondre
    • Bonjour,

      Pour moi oui c’est possible, mais il faudra que le poste dispose du certificat racine de votre autorité de certification pour qu’elle soit approuvée en tant que CA de confiance 🙂
      Opération à réaliser manuellement comme le poste est hors domaine.

      Florian

      Répondre
  • Bonjour,
    Merci pour cet article.
    Mais le cmdlet « Add-CATemplate » n’existe pas chez moi, comment faire pour l’avoir ? c’est un module a ajouter ?

    Windows 10 pro 1903 avec RSAT.

    Merci par avance.
    0relien.

    Répondre
    • Le module n’existe pas sur mon poste client, mais existe sur les serveurs avec le rôle CA.

      Répondre
      • Bonjour 0relien,

        Oui c’est normal c’est un cmdlet intégré au module ADCSAdministration donc il s’est ajouté automatiquement sur ton serveur autorité de certification, ce qui n’est pas le cas par défaut sur ton PC.

        Cordialement,
        Florian

        Répondre
  • Bonjour,

    Lorsque je déploie le certificat via GPO, Il ne se retrouve pas dans le magasin local Cert:\CurrentUser\My

    Il y a bien un certificat qui se retrouve dans les éditeurs approuvés mais lorsque j’utilise le paramètre -CodeSigningCert je n’ai aucun retour de la commande…

    J’ai suivi la manipulation pas à pas et je comprends pas pourquoi cela ne s’applique pas comme sur la manipulation.Pourtant ma GPO s’applique bien…

    Auriez vous une solution ou un indice pour mes recherches ?

    Merci d’avance
    Bien à vous,

    Répondre
    • Bonjour,

      J’ai eu le même problème, essaie de taper les commandes depuis le serveur ADCS.

      Répondre
  • @Hendryckx Logan : Même problématique que toi, j’ai pu récupérer la réponse a la commande, en faisant une demande de certificat via le magasin Current User, personnel puis Request New Certificat sur un poste ou srv.

    Uniquement par cette methode, la commande Get-ChildItem Cert:\CurrentUser\My\ -CodeSigningCert me renvoi bien un résultat.

    Répondre
  • Bonjour,

    Merci beaucoup cet article. Cependant, je suis comme Logan, en suivant pas à pas la procédure, mon certificat se déploie parfaitement mais à l’application de la commande Get-ChildItem Cert:\CurrentUser\My\ -CodeSigningCert je n’ai aucun résultat.
    Comment résoudre ce problème ?
    Comment faire une demande de certificat via le current user, personnel car lorsque je le fais depuis la console MMC, je n’ai pas l’autorisation de demander des certificats de signature de code.
    Merci pour vos retours et solutions.
    Cordialement

    Répondre

Répondre à Florian B. Annuler la réponse

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.